2004-05-24 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / mcs / statement.cs
index bec33d3b5c5f2b81ca2efe3f33c0437d7d15c1e2..203e61d58bf9c0fc51f3aeecf25aaeace77b483e 100755 (executable)
@@ -62,6 +62,22 @@ namespace Mono.CSharp {
                /// </summary>
                protected abstract void DoEmit (EmitContext ec);
 
+               /// <summary>
+               ///   Utility wrapper routine for Error, just to beautify the code
+               /// </summary>
+               public void Error (int error, string format, params object[] args)
+               {
+                       Error (error, String.Format (format, args));
+               }
+
+               public void Error (int error, string s)
+               {
+                       if (!Location.IsNull (loc))
+                               Report.Error (error, loc, s);
+                       else
+                               Report.Error (error, s);
+               }
+
                /// <summary>
                ///   Return value indicates whether all code paths emitted return.
                /// </summary>
@@ -155,7 +171,7 @@ namespace Mono.CSharp {
 
                        is_true_ret = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
 
-                       ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
+                       ec.CurrentBranching.CreateSibling ();
 
                        if ((FalseStatement != null) && !FalseStatement.Resolve (ec))
                                ok = false;
@@ -228,7 +244,7 @@ namespace Mono.CSharp {
                {
                        bool ok = true;
 
-                       ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
 
                        if (!EmbeddedStatement.Resolve (ec))
                                ok = false;
@@ -255,13 +271,9 @@ namespace Mono.CSharp {
                        Label loop = ig.DefineLabel ();
                        Label old_begin = ec.LoopBegin;
                        Label old_end = ec.LoopEnd;
-                       bool  old_inloop = ec.InLoop;
-                       int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
                        
                        ec.LoopBegin = ig.DefineLabel ();
                        ec.LoopEnd = ig.DefineLabel ();
-                       ec.InLoop = true;
-                       ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
                                
                        ig.MarkLabel (loop);
                        EmbeddedStatement.Emit (ec);
@@ -280,10 +292,8 @@ namespace Mono.CSharp {
                        
                        ig.MarkLabel (ec.LoopEnd);
 
-                       ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
-                       ec.InLoop = old_inloop;
                }
        }
 
@@ -322,7 +332,7 @@ namespace Mono.CSharp {
                                        infinite = true;
                        }
 
-                       ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
 
                        if (!Statement.Resolve (ec))
                                ok = false;
@@ -341,13 +351,9 @@ namespace Mono.CSharp {
                        ILGenerator ig = ec.ig;
                        Label old_begin = ec.LoopBegin;
                        Label old_end = ec.LoopEnd;
-                       bool old_inloop = ec.InLoop;
-                       int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
                        
                        ec.LoopBegin = ig.DefineLabel ();
                        ec.LoopEnd = ig.DefineLabel ();
-                       ec.InLoop = true;
-                       ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
 
                        //
                        // Inform whether we are infinite or not
@@ -379,8 +385,6 @@ namespace Mono.CSharp {
 
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
-                       ec.InLoop = old_inloop;
-                       ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
                }
        }
 
@@ -434,9 +438,9 @@ namespace Mono.CSharp {
                        } else
                                infinite = true;
 
-                       ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
                        if (!infinite)
-                               ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
+                               ec.CurrentBranching.CreateSibling ();
 
                        if (!Statement.Resolve (ec))
                                ok = false;
@@ -460,8 +464,6 @@ namespace Mono.CSharp {
                        ILGenerator ig = ec.ig;
                        Label old_begin = ec.LoopBegin;
                        Label old_end = ec.LoopEnd;
-                       bool old_inloop = ec.InLoop;
-                       int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
                        Label loop = ig.DefineLabel ();
                        Label test = ig.DefineLabel ();
                        
@@ -470,8 +472,6 @@ namespace Mono.CSharp {
 
                        ec.LoopBegin = ig.DefineLabel ();
                        ec.LoopEnd = ig.DefineLabel ();
-                       ec.InLoop = true;
-                       ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
 
                        ig.Emit (OpCodes.Br, test);
                        ig.MarkLabel (loop);
@@ -503,8 +503,6 @@ namespace Mono.CSharp {
 
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
-                       ec.InLoop = old_inloop;
-                       ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
                }
        }
        
@@ -546,24 +544,49 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
+               bool in_exc;
+
                public override bool Resolve (EmitContext ec)
                {
-                       if (Expr != null){
+                       if (ec.ReturnType == null){
+                               if (Expr != null){
+                                       Error (127, "Return with a value not allowed here");
+                                       return false;
+                               }
+                       } else {
+                               if (Expr == null){
+                                       Error (126, "An object of type `{0}' is expected " +
+                                              "for the return statement",
+                                              TypeManager.CSharpName (ec.ReturnType));
+                                       return false;
+                               }
+
                                Expr = Expr.Resolve (ec);
                                if (Expr == null)
                                        return false;
+
+                               if (Expr.Type != ec.ReturnType) {
+                                       Expr = Convert.ImplicitConversionRequired (
+                                               ec, Expr, ec.ReturnType, loc);
+                                       if (Expr == null)
+                                               return false;
+                               }
                        }
 
                        if (ec.InIterator){
-                               Report.Error (-206, loc, "Return statement not allowed inside iterators");
+                               Error (-206, "Return statement not allowed inside iterators");
                                return false;
                        }
                                
                        FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
 
-                       if (ec.CurrentBranching.InTryBlock ())
+                       if (ec.CurrentBranching.InTryOrCatch (true)) {
                                ec.CurrentBranching.AddFinallyVector (vector);
-                       else
+                               in_exc = true;
+                       } else if (ec.CurrentBranching.InFinally (true)) {
+                               Error (157, "Control can not leave the body of the finally block");
+                               return false;
+                       } else
                                vector.CheckOutParameters (ec.CurrentBranching);
 
                        ec.CurrentBranching.CurrentUsageVector.Return ();
@@ -572,46 +595,18 @@ namespace Mono.CSharp {
                
                protected override void DoEmit (EmitContext ec)
                {
-                       if (ec.InFinally){
-                               Report.Error (157, loc, "Control can not leave the body of the finally block");
-                               return;
-                       }
-
-                       if (ec.ReturnType == null){
-                               if (Expr != null){
-                                       Report.Error (127, loc, "Return with a value not allowed here");
-                                       return;
-                               }
-                       } else {
-                               if (Expr == null){
-                                       Report.Error (126, loc, "An object of type `" +
-                                                     TypeManager.CSharpName (ec.ReturnType) + "' is " +
-                                                     "expected for the return statement");
-                                       return;
-                               }
-
-                               if (Expr.Type != ec.ReturnType)
-                                       Expr = Convert.ImplicitConversionRequired (
-                                               ec, Expr, ec.ReturnType, loc);
-
-                               if (Expr == null)
-                                       return;
-
+                       if (Expr != null) {
                                Expr.Emit (ec);
 
-                               if (ec.InTry || ec.InCatch)
+                               if (in_exc)
                                        ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
                        }
 
-                       if (ec.InTry || ec.InCatch) {
-                               if (!ec.HasReturnLabel) {
-                                       ec.ReturnLabel = ec.ig.DefineLabel ();
-                                       ec.HasReturnLabel = true;
-                               }
+                       if (in_exc) {
+                               ec.NeedReturnLabel ();
                                ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
                        } else {
                                ec.ig.Emit (OpCodes.Ret);
-                               ec.NeedExplicitReturn = false;
                        }
                }
        }
@@ -623,13 +618,9 @@ namespace Mono.CSharp {
                
                public override bool Resolve (EmitContext ec)
                {
-                       label = block.LookupLabel (target);
-                       if (label == null){
-                               Report.Error (
-                                       159, loc,
-                                       "No such label `" + target + "' in this scope");
+                       label = ec.CurrentBranching.LookupLabel (target, loc);
+                       if (label == null)
                                return false;
-                       }
 
                        // If this is a forward goto.
                        if (!label.IsDefined)
@@ -666,7 +657,7 @@ namespace Mono.CSharp {
                bool referenced;
                Label label;
 
-               ArrayList vectors;
+               FlowBranching.UsageVector vectors;
                
                public LabeledStatement (string label_name, Location l)
                {
@@ -697,10 +688,9 @@ namespace Mono.CSharp {
 
                public void AddUsageVector (FlowBranching.UsageVector vector)
                {
-                       if (vectors == null)
-                               vectors = new ArrayList ();
-
-                       vectors.Add (vector.Clone ());
+                       vector = vector.Clone ();
+                       vector.Next = vectors;
+                       vectors = vector;
                }
 
                public override bool Resolve (EmitContext ec)
@@ -818,6 +808,9 @@ namespace Mono.CSharp {
 
                public override bool Resolve (EmitContext ec)
                {
+                       bool in_catch = ec.CurrentBranching.InCatch ();
+                       ec.CurrentBranching.CurrentUsageVector.Throw ();
+
                        if (expr != null){
                                expr = expr.Resolve (ec);
                                if (expr == null)
@@ -836,34 +829,30 @@ namespace Mono.CSharp {
                                if ((t != TypeManager.exception_type) &&
                                    !t.IsSubclassOf (TypeManager.exception_type) &&
                                    !(expr is NullLiteral)) {
-                                       Report.Error (155, loc,
-                                                     "The type caught or thrown must be derived " +
-                                                     "from System.Exception");
+                                       Error (155,
+                                              "The type caught or thrown must be derived " +
+                                              "from System.Exception");
                                        return false;
                                }
+                       } else if (!in_catch) {
+                               Error (156,
+                                      "A throw statement with no argument is only " +
+                                      "allowed in a catch clause");
+                               return false;
                        }
 
-                       ec.CurrentBranching.CurrentUsageVector.Throw ();
                        return true;
                }
                        
                protected override void DoEmit (EmitContext ec)
                {
-                       if (expr == null){
-                               if (ec.InCatch)
-                                       ec.ig.Emit (OpCodes.Rethrow);
-                               else {
-                                       Report.Error (
-                                               156, loc,
-                                               "A throw statement with no argument is only " +
-                                               "allowed in a catch clause");
-                               }
-                               return;
-                       }
-
-                       expr.Emit (ec);
+                       if (expr == null)
+                               ec.ig.Emit (OpCodes.Rethrow);
+                       else {
+                               expr.Emit (ec);
 
-                       ec.ig.Emit (OpCodes.Throw);
+                               ec.ig.Emit (OpCodes.Throw);
+                       }
                }
        }
 
@@ -874,8 +863,25 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
+               bool crossing_exc;
+
                public override bool Resolve (EmitContext ec)
                {
+                       if (!ec.CurrentBranching.InLoop () && !ec.CurrentBranching.InSwitch ()){
+                               Error (139, "No enclosing loop or switch to continue to");
+                               return false;
+                       } else if (ec.CurrentBranching.InFinally (false)) {
+                               Error (157, "Control can not leave the body of the finally block");
+                               return false;
+                       } else if (ec.CurrentBranching.InTryOrCatch (false))
+                               ec.CurrentBranching.AddFinallyVector (
+                                       ec.CurrentBranching.CurrentUsageVector);
+                       else if (ec.CurrentBranching.InLoop ())
+                               ec.CurrentBranching.AddBreakVector (
+                                       ec.CurrentBranching.CurrentUsageVector);
+
+                       crossing_exc = ec.CurrentBranching.BreakCrossesTryCatchBoundary ();
+
                        ec.CurrentBranching.CurrentUsageVector.Break ();
                        return true;
                }
@@ -884,15 +890,10 @@ namespace Mono.CSharp {
                {
                        ILGenerator ig = ec.ig;
 
-                       if (ec.InLoop == false && ec.Switch == null){
-                               Report.Error (139, loc, "No enclosing loop or switch to continue to");
-                               return;
-                       }
-
-                       if (ec.InTry || ec.InCatch)
+                       if (crossing_exc)
                                ig.Emit (OpCodes.Leave, ec.LoopEnd);
                        else {
-                               ec.NeedExplicitReturn = true;
+                               ec.NeedReturnLabel ();
                                ig.Emit (OpCodes.Br, ec.LoopEnd);
                        }
                }
@@ -905,8 +906,21 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
+               bool crossing_exc;
+
                public override bool Resolve (EmitContext ec)
                {
+                       if (!ec.CurrentBranching.InLoop () && !ec.CurrentBranching.InSwitch ()){
+                               Error (139, "No enclosing loop to continue to");
+                               return false;
+                       } else if (ec.CurrentBranching.InFinally (false)) {
+                               Error (157, "Control can not leave the body of the finally block");
+                               return false;
+                       } else if (ec.CurrentBranching.InTryOrCatch (false))
+                               ec.CurrentBranching.AddFinallyVector (ec.CurrentBranching.CurrentUsageVector);
+
+                       crossing_exc = ec.CurrentBranching.BreakCrossesTryCatchBoundary ();
+
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
                        return true;
                }
@@ -915,26 +929,8 @@ namespace Mono.CSharp {
                {
                        Label begin = ec.LoopBegin;
                        
-                       if (!ec.InLoop){
-                               Report.Error (139, loc, "No enclosing loop to continue to");
-                               return;
-                       } 
-
-                       //
-                       // UGH: Non trivial.  This Br might cross a try/catch boundary
-                       // How can we tell?
-                       //
-                       // while () {
-                       //   try { ... } catch { continue; }
-                       // }
-                       //
-                       // From:
-                       // try {} catch { while () { continue; }}
-                       //
-                       if (ec.TryCatchLevel > ec.LoopBeginTryCatchLevel)
+                       if (crossing_exc)
                                ec.ig.Emit (OpCodes.Leave, begin);
-                       else if (ec.TryCatchLevel < ec.LoopBeginTryCatchLevel)
-                               throw new Exception ("Should never happen");
                        else
                                ec.ig.Emit (OpCodes.Br, begin);
                }
@@ -1007,6 +1003,12 @@ namespace Mono.CSharp {
                        if (VariableType == null)
                                VariableType = decl.ResolveType (Type, false, Location);
 
+                       if (VariableType == TypeManager.void_type) {
+                               Report.Error (1547, Location,
+                                             "Keyword 'void' cannot be used in this context");
+                               return false;
+                       }
+
                        if (VariableType == null)
                                return false;
 
@@ -1081,7 +1083,8 @@ namespace Mono.CSharp {
                        Unchecked = 2,
                        BlockUsed = 4,
                        VariablesInitialized = 8,
-                       HasRet = 16
+                       HasRet = 16,
+                       IsDestructor = 32       
                }
                Flags flags;
 
@@ -1104,6 +1107,7 @@ namespace Mono.CSharp {
                // The statements in this block
                //
                ArrayList statements;
+               int num_statements;
 
                //
                // An array of Blocks.  We keep track of children just
@@ -1175,6 +1179,14 @@ namespace Mono.CSharp {
                        this.loc = start;
                        this_id = id++;
                        statements = new ArrayList ();
+
+                       if (parent != null && Implicit) {
+                               if (parent.child_variable_names == null)
+                                       parent.child_variable_names = new Hashtable();
+                               // share with parent
+                               child_variable_names = parent.child_variable_names;
+                       }
+                               
                }
 
                public Block CreateSwitchBlock (Location start)
@@ -1212,56 +1224,93 @@ namespace Mono.CSharp {
                ///   otherwise.
                /// </returns>
                ///
-               public bool AddLabel (string name, LabeledStatement target)
+               public bool AddLabel (string name, LabeledStatement target, Location loc)
                {
                        if (switch_block != null)
-                               return switch_block.AddLabel (name, target);
+                               return switch_block.AddLabel (name, target, loc);
+
+                       Block cur = this;
+                       while (cur != null) {
+                               if (cur.DoLookupLabel (name) != null) {
+                                       Report.Error (
+                                               140, loc, "The label '{0}' is a duplicate",
+                                               name);
+                                       return false;
+                               }
+
+                               if (!Implicit)
+                                       break;
+
+                               cur = cur.Parent;
+                       }
+
+                       while (cur != null) {
+                               if (cur.DoLookupLabel (name) != null) {
+                                       Report.Error (
+                                               158, loc,
+                                               "The label '{0}' shadows another label " +
+                                               "by the same name in a containing scope.",
+                                               name);
+                                       return false;
+                               }
+
+                               if (children != null) {
+                                       foreach (Block b in children) {
+                                               LabeledStatement s = b.DoLookupLabel (name);
+                                               if (s == null)
+                                                       continue;
+
+                                               Report.Error (
+                                                       158, s.Location,
+                                                       "The label '{0}' shadows another " +
+                                                       "label by the same name in a " +
+                                                       "containing scope.",
+                                                       name);
+                                               return false;
+                                       }
+                               }
+
+
+                               cur = cur.Parent;
+                       }
 
                        if (labels == null)
                                labels = new Hashtable ();
-                       if (labels.Contains (name))
-                               return false;
-                       
+
                        labels.Add (name, target);
                        return true;
                }
 
                public LabeledStatement LookupLabel (string name)
                {
-                       Hashtable l = new Hashtable ();
-                       
-                       return LookupLabel (name, l);
+                       LabeledStatement s = DoLookupLabel (name);
+                       if (s != null)
+                               return s;
+
+                       if (children == null)
+                               return null;
+
+                       foreach (Block child in children) {
+                               if (!child.Implicit)
+                                       continue;
+
+                               s = child.LookupLabel (name);
+                               if (s != null)
+                                       return s;
+                       }
+
+                       return null;
                }
 
-               //
-               // Lookups a label in the current block, parents and children.
-               // It skips during child recurssion on `source'
-               //
-               LabeledStatement LookupLabel (string name, Hashtable seen)
+               LabeledStatement DoLookupLabel (string name)
                {
                        if (switch_block != null)
-                               return switch_block.LookupLabel (name, seen);
-
-                       if (seen [this] != null)
-                               return null;
+                               return switch_block.LookupLabel (name);
 
-                       seen [this] = this;
-                       
                        if (labels != null)
                                if (labels.Contains (name))
                                        return ((LabeledStatement) labels [name]);
 
-                       if (children != null){
-                               foreach (Block b in children){
-                                       LabeledStatement s = b.LookupLabel (name, seen);
-                                       if (s != null)
-                                               return s;
-                               }
-                       }
-
-                       if (Parent != null)
-                               return Parent.LookupLabel (name, seen);
-
                        return null;
                }
 
@@ -1298,28 +1347,6 @@ namespace Mono.CSharp {
                                child_variable_names.Add (name, true);
                }
 
-               // <summary>
-               //   Marks all variables from block @block and all its children as being
-               //   used in a child block.
-               // </summary>
-               public void AddChildVariableNames (Block block)
-               {
-                       if (block.Variables != null) {
-                               foreach (string name in block.Variables.Keys)
-                                       AddChildVariableName (name);
-                       }
-
-                       if (block.children != null) {
-                               foreach (Block child in block.children)
-                                       AddChildVariableNames (child);
-                       }
-
-                       if (block.child_variable_names != null) {
-                               foreach (string name in block.child_variable_names.Keys)
-                                       AddChildVariableName (name);
-                       }
-               }
-
                // <summary>
                //   Checks whether a variable name has already been used in a child block.
                // </summary>
@@ -1394,11 +1421,19 @@ namespace Mono.CSharp {
                                        return null;
                                }
                        }
-                       
+
                        vi = new LocalInfo (type, name, this, l);
 
                        variables.Add (name, vi);
 
+                       // Mark 'name' as "used by a child block" in every surrounding block
+                       Block cur = this;
+                       while (cur != null && cur.Implicit) 
+                               cur = cur.Parent;
+                       if (cur != null)
+                               for (Block par = cur.Parent; par != null; par = par.Parent)
+                                       par.AddChildVariableName (name);
+
                        if ((flags & Flags.VariablesInitialized) != 0)
                                throw new Exception ();
 
@@ -1470,15 +1505,6 @@ namespace Mono.CSharp {
                        return e != null;
                }
                
-               /// <summary>
-               ///   Use to fetch the statement associated with this label
-               /// </summary>
-               public Statement this [string name] {
-                       get {
-                               return (Statement) labels [name];
-                       }
-               }
-
                Parameters parameters = null;
                public Parameters Parameters {
                        get {
@@ -1521,6 +1547,17 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool IsDestructor {
+                       get {
+                               return (flags & Flags.IsDestructor) != 0;
+                       }
+               }
+
+               public void SetDestructor ()
+               {
+                       flags |= Flags.IsDestructor;
+               }
+
                VariableMap param_map, local_map;
 
                public VariableMap ParameterMap {
@@ -1694,7 +1731,7 @@ namespace Mono.CSharp {
                        ec.StartFlowBranching (this);
 
                        Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
-                       
+
                        bool unreachable = false, warning_shown = false;
 
                        int statement_count = statements.Count;
@@ -1702,11 +1739,16 @@ namespace Mono.CSharp {
                                Statement s = (Statement) statements [ix];
 
                                if (unreachable && !(s is LabeledStatement)) {
+                                       if (s == EmptyStatement.Value)
+                                               s.loc = EndLocation;
+
                                        if (!s.ResolveUnreachable (ec, !warning_shown))
                                                ok = false;
 
                                        if (s != EmptyStatement.Value)
                                                warning_shown = true;
+                                       else
+                                               s.loc = Location.Null;
 
                                        statements [ix] = EmptyStatement.Value;
                                        continue;
@@ -1718,13 +1760,16 @@ namespace Mono.CSharp {
                                        continue;
                                }
 
+                               num_statements = ix + 1;
+
                                if (s is LabeledStatement)
                                        unreachable = false;
                                else
                                        unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
                        }
 
-                       Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching);
+                       Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation,
+                                     ec.CurrentBranching, statement_count, num_statements);
 
 
                        FlowBranching.UsageVector vector = ec.DoEndFlowBranching ();
@@ -1762,9 +1807,17 @@ namespace Mono.CSharp {
                
                protected override void DoEmit (EmitContext ec)
                {
-                       int statement_count = statements.Count;
-                       for (int ix = 0; ix < statement_count; ix++){
+                       for (int ix = 0; ix < num_statements; ix++){
                                Statement s = (Statement) statements [ix];
+
+                               // Check whether we are the last statement in a
+                               // top-level block.
+
+                               if ((Parent == null) && (ix+1 == num_statements))
+                                       ec.IsLastStatement = true;
+                               else
+                                       ec.IsLastStatement = false;
+
                                s.Emit (ec);
                        }
                }
@@ -2158,7 +2211,7 @@ namespace Mono.CSharp {
                        }
                        if (error)
                                return false;
-                       
+
                        return true;
                }
 
@@ -2219,6 +2272,8 @@ namespace Mono.CSharp {
                        public long nFirst;
                        public long nLast;
                        public ArrayList rgKeys = null;
+                       // how many items are in the bucket
+                       public int Size = 1;
                        public int Length
                        {
                                get { return (int) (nLast - nFirst + 1); }
@@ -2270,10 +2325,11 @@ namespace Mono.CSharp {
                                for (int ikb = 1; ikb < rgKeyBlocks.Count; ikb++)
                                {
                                        KeyBlock kb = (KeyBlock) rgKeyBlocks [ikb];
-                                       if ((kbCurr.Length + kb.Length) * 2 >=  KeyBlock.TotalLength (kbCurr, kb))
+                                       if ((kbCurr.Size + kb.Size) * 2 >=  KeyBlock.TotalLength (kbCurr, kb))
                                        {
                                                // merge blocks
                                                kbCurr.nLast = kb.nLast;
+                                               kbCurr.Size += kb.Size;
                                        }
                                        else
                                        {
@@ -2453,6 +2509,7 @@ namespace Mono.CSharp {
                        bool first_test = true;
                        bool pending_goto_end = false;
                        bool null_found;
+                       bool default_at_end = false;
                        
                        ig.Emit (OpCodes.Ldloc, val);
                        
@@ -2474,6 +2531,7 @@ namespace Mono.CSharp {
                                        ig.Emit (OpCodes.Br, end_of_switch);
 
                                int label_count = ss.Labels.Count;
+                               bool mark_default = false;
                                null_found = false;
                                for (int label = 0; label < label_count; label++){
                                        SwitchLabel sl = (SwitchLabel) ss.Labels [label];
@@ -2487,7 +2545,9 @@ namespace Mono.CSharp {
                                        // If we are the default target
                                        //
                                        if (sl.Label == null){
-                                               ig.MarkLabel (default_target);
+                                               if (label+1 == label_count)
+                                                       default_at_end = true;
+                                               mark_default = true;
                                                default_found = true;
                                        } else {
                                                object lit = sl.Converted;
@@ -2519,14 +2579,18 @@ namespace Mono.CSharp {
                                foreach (SwitchLabel sl in ss.Labels)
                                        ig.MarkLabel (sl.ILLabelCode);
 
+                               if (mark_default)
+                                       ig.MarkLabel (default_target);
                                ss.Block.Emit (ec);
                                pending_goto_end = !ss.Block.HasRet;
                                first_test = false;
                        }
-                       if (!default_found){
-                               ig.MarkLabel (default_target);
-                       }
                        ig.MarkLabel (next_test);
+                       if (default_found){
+                               if (!default_at_end)
+                                       ig.Emit (OpCodes.Br, default_target);
+                       } else 
+                               ig.MarkLabel (default_target);
                        ig.MarkLabel (end_of_switch);
                }
 
@@ -2552,12 +2616,14 @@ namespace Mono.CSharp {
                        ec.Switch = this;
                        ec.Switch.SwitchType = SwitchType;
 
+                       Report.Debug (1, "START OF SWITCH BLOCK", loc, ec.CurrentBranching);
                        ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
 
                        bool first = true;
                        foreach (SwitchSection ss in Sections){
                                if (!first)
-                                       ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.SwitchSection);
+                                       ec.CurrentBranching.CreateSibling (
+                                               null, FlowBranching.SiblingType.SwitchSection);
                                else
                                        first = false;
 
@@ -2567,11 +2633,15 @@ namespace Mono.CSharp {
 
 
                        if (!got_default)
-                               ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.SwitchSection);
+                               ec.CurrentBranching.CreateSibling (
+                                       null, FlowBranching.SiblingType.SwitchSection);
 
-                       ec.EndFlowBranching ();
+                       FlowBranching.Reachability reachability = ec.EndFlowBranching ();
                        ec.Switch = old_switch;
 
+                       Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching,
+                                     reachability);
+
                        return true;
                }
                
@@ -2626,20 +2696,27 @@ namespace Mono.CSharp {
                public override bool Resolve (EmitContext ec)
                {
                        expr = expr.Resolve (ec);
-                       return Statement.Resolve (ec) && expr != null;
+                       if (expr == null)
+                               return false;
+
+                       if (expr.Type.IsValueType){
+                               Error (185, "lock statement requires the expression to be " +
+                                      " a reference type (type is: `{0}'",
+                                      TypeManager.CSharpName (expr.Type));
+                               return false;
+                       }
+
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Exception, loc);
+                       bool ok = Statement.Resolve (ec);
+                       ec.EndFlowBranching ();
+
+                       return ok;
                }
                
                protected override void DoEmit (EmitContext ec)
                {
                        Type type = expr.Type;
                        
-                       if (type.IsValueType){
-                               Report.Error (185, loc, "lock statement requires the expression to be " +
-                                             " a reference type (type is: `" +
-                                             TypeManager.CSharpName (type) + "'");
-                               return;
-                       }
-
                        ILGenerator ig = ec.ig;
                        LocalBuilder temp = ig.DeclareLocal (type);
                                
@@ -2650,11 +2727,8 @@ namespace Mono.CSharp {
 
                        // try
                        ig.BeginExceptionBlock ();
-                       bool old_in_try = ec.InTry;
-                       ec.InTry = true;
                        Label finish = ig.DefineLabel ();
                        Statement.Emit (ec);
-                       ec.InTry = old_in_try;
                        // ig.Emit (OpCodes.Leave, finish);
 
                        ig.MarkLabel (finish);
@@ -3116,20 +3190,17 @@ namespace Mono.CSharp {
 
                        Report.Debug (1, "START OF TRY BLOCK", Block.StartLocation);
 
-                       bool old_in_try = ec.InTry;
-                       ec.InTry = true;
-
                        if (!Block.Resolve (ec))
                                ok = false;
 
-                       ec.InTry = old_in_try;
-
                        FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
 
                        Report.Debug (1, "START OF CATCH BLOCKS", vector);
 
                        foreach (Catch c in Specific){
-                               ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Catch);
+                               ec.CurrentBranching.CreateSibling (
+                                       c.Block, FlowBranching.SiblingType.Catch);
+
                                Report.Debug (1, "STARTED SIBLING FOR CATCH", ec.CurrentBranching);
 
                                if (c.Name != null) {
@@ -3140,44 +3211,33 @@ namespace Mono.CSharp {
                                        vi.VariableInfo = null;
                                }
 
-                               bool old_in_catch = ec.InCatch;
-                               ec.InCatch = true;
-
                                if (!c.Resolve (ec))
                                        ok = false;
-
-                               ec.InCatch = old_in_catch;
                        }
 
                        Report.Debug (1, "END OF CATCH BLOCKS", ec.CurrentBranching);
 
                        if (General != null){
-                               ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Catch);
-                               Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching);
+                               ec.CurrentBranching.CreateSibling (
+                                       General.Block, FlowBranching.SiblingType.Catch);
 
-                               bool old_in_catch = ec.InCatch;
-                               ec.InCatch = true;
+                               Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching);
 
                                if (!General.Resolve (ec))
                                        ok = false;
-
-                               ec.InCatch = old_in_catch;
                        }
 
                        Report.Debug (1, "END OF GENERAL CATCH BLOCKS", ec.CurrentBranching);
 
                        if (Fini != null) {
                                if (ok)
-                                       ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Finally);
-                               Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
+                                       ec.CurrentBranching.CreateSibling (
+                                               Fini, FlowBranching.SiblingType.Finally);
 
-                               bool old_in_finally = ec.InFinally;
-                               ec.InFinally = true;
+                               Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
 
                                if (!Fini.Resolve (ec))
                                        ok = false;
-
-                               ec.InFinally = old_in_finally;
                        }
 
                        FlowBranching.Reachability reachability = ec.EndFlowBranching ();
@@ -3191,7 +3251,7 @@ namespace Mono.CSharp {
                                // to the end of the finally block.  This is a problem if `returns'
                                // is true since we may jump to a point after the end of the method.
                                // As a workaround, emit an explicit ret here.
-                               ec.NeedExplicitReturn = true;
+                               ec.NeedReturnLabel ();
                        }
 
                        return ok;
@@ -3202,20 +3262,13 @@ namespace Mono.CSharp {
                        ILGenerator ig = ec.ig;
                        Label finish = ig.DefineLabel ();;
 
-                       ec.TryCatchLevel++;
                        ig.BeginExceptionBlock ();
-                       bool old_in_try = ec.InTry;
-                       ec.InTry = true;
                        Block.Emit (ec);
-                       ec.InTry = old_in_try;
 
                        //
                        // System.Reflection.Emit provides this automatically:
                        // ig.Emit (OpCodes.Leave, finish);
 
-                       bool old_in_catch = ec.InCatch;
-                       ec.InCatch = true;
-
                        foreach (Catch c in Specific){
                                LocalInfo vi;
                                
@@ -3238,19 +3291,14 @@ namespace Mono.CSharp {
                                ig.Emit (OpCodes.Pop);
                                General.Block.Emit (ec);
                        }
-                       ec.InCatch = old_in_catch;
 
                        ig.MarkLabel (finish);
                        if (Fini != null){
                                ig.BeginFinallyBlock ();
-                               bool old_in_finally = ec.InFinally;
-                               ec.InFinally = true;
                                Fini.Emit (ec);
-                               ec.InFinally = old_in_finally;
                        }
                        
                        ig.EndExceptionBlock ();
-                       ec.TryCatchLevel--;
                }
        }
 
@@ -3348,18 +3396,13 @@ namespace Mono.CSharp {
                        ILGenerator ig = ec.ig;
                        int i = 0;
 
-                       bool old_in_try = ec.InTry;
-                       ec.InTry = true;
                        for (i = 0; i < assign.Length; i++) {
                                assign [i].EmitStatement (ec);
                                
                                ig.BeginExceptionBlock ();
                        }
                        Statement.Emit (ec);
-                       ec.InTry = old_in_try;
 
-                       bool old_in_finally = ec.InFinally;
-                       ec.InFinally = true;
                        var_list.Reverse ();
                        foreach (DictionaryEntry e in var_list){
                                LocalVariableReference var = (LocalVariableReference) e.Key;
@@ -3374,7 +3417,7 @@ namespace Mono.CSharp {
                                        converted_vars [i].Emit (ec);
                                        ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
                                } else {
-                                       Expression ml = Expression.MemberLookup(ec, typeof(IDisposable), var.Type, "Dispose", Mono.CSharp.Location.Null);
+                                       Expression ml = Expression.MemberLookup(ec, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null);
 
                                        if (!(ml is MethodGroupExpr)) {
                                                var.Emit (ec);
@@ -3403,7 +3446,6 @@ namespace Mono.CSharp {
                                ig.MarkLabel (skip);
                                ig.EndExceptionBlock ();
                        }
-                       ec.InFinally = old_in_finally;
 
                        return false;
                }
@@ -3421,21 +3463,16 @@ namespace Mono.CSharp {
                                expr.Emit (ec);
                        ig.Emit (OpCodes.Stloc, local_copy);
 
-                       bool old_in_try = ec.InTry;
-                       ec.InTry = true;
                        ig.BeginExceptionBlock ();
                        Statement.Emit (ec);
-                       ec.InTry = old_in_try;
                        
                        Label skip = ig.DefineLabel ();
-                       bool old_in_finally = ec.InFinally;
                        ig.BeginFinallyBlock ();
                        ig.Emit (OpCodes.Ldloc, local_copy);
                        ig.Emit (OpCodes.Brfalse, skip);
                        ig.Emit (OpCodes.Ldloc, local_copy);
                        ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
                        ig.MarkLabel (skip);
-                       ec.InFinally = old_in_finally;
                        ig.EndExceptionBlock ();
 
                        return false;
@@ -3463,7 +3500,7 @@ namespace Mono.CSharp {
                                        return false;
                        }
 
-                       ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Exception, loc);
 
                        bool ok = Statement.Resolve (ec);
 
@@ -3479,7 +3516,7 @@ namespace Mono.CSharp {
                                // to the end of the finally block.  This is a problem if `returns'
                                // is true since we may jump to a point after the end of the method.
                                // As a workaround, emit an explicit ret here.
-                               ec.NeedExplicitReturn = true;
+                               ec.NeedReturnLabel ();
                        }
 
                        return true;
@@ -3550,7 +3587,7 @@ namespace Mono.CSharp {
                                if (hm == null){
                                        error1579 (expr.Type);
                                        return false;
-                               }
+                               }                       
 
                                array_type = expr.Type;
                                element_type = hm.element_type;
@@ -3558,8 +3595,10 @@ namespace Mono.CSharp {
                                empty = new EmptyExpression (hm.element_type);
                        }
 
-                       ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
-                       ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
+                       bool ok = true;
+
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
+                       ec.CurrentBranching.CreateSibling ();
 
                        //
                        //
@@ -3571,18 +3610,25 @@ namespace Mono.CSharp {
                        //
                        conv = Convert.ExplicitConversion (ec, empty, var_type, loc);
                        if (conv == null)
-                               return false;
+                               ok = false;
 
                        variable = variable.ResolveLValue (ec, empty);
                        if (variable == null)
-                               return false;
+                               ok = false;
+
+                       bool disposable = (hm != null) && hm.is_disposable;
+                       if (disposable)
+                               ec.StartFlowBranching (FlowBranching.BranchingType.Exception, loc);
 
                        if (!statement.Resolve (ec))
-                               return false;
+                               ok = false;
+
+                       if (disposable)
+                               ec.EndFlowBranching ();
 
                        ec.EndFlowBranching ();
 
-                       return true;
+                       return ok;
                }
                
                //
@@ -3722,30 +3768,51 @@ namespace Mono.CSharp {
                        // Ok, we can access it, now make sure that we can do something
                        // with this `GetEnumerator'
                        //
-
+                       
+                       Type return_type = mi.ReturnType;
                        if (mi.ReturnType == TypeManager.ienumerator_type ||
-                           TypeManager.ienumerator_type.IsAssignableFrom (mi.ReturnType) ||
-                           (!RootContext.StdLib && TypeManager.ImplementsInterface (mi.ReturnType, TypeManager.ienumerator_type))) {
-                               if (declaring != TypeManager.string_type) {
+                           TypeManager.ienumerator_type.IsAssignableFrom (return_type) ||
+                           (!RootContext.StdLib && TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type))) {
+                               
+                               //
+                               // If it is not an interface, lets try to find the methods ourselves.
+                               // For example, if we have:
+                               // public class Foo : IEnumerator { public bool MoveNext () {} public int Current { get {}}}
+                               // We can avoid the iface call. This is a runtime perf boost.
+                               // even bigger if we have a ValueType, because we avoid the cost
+                               // of boxing.
+                               //
+                               // We have to make sure that both methods exist for us to take
+                               // this path. If one of the methods does not exist, we will just
+                               // use the interface. Sadly, this complex if statement is the only
+                               // way I could do this without a goto
+                               //
+                               
+                               if (return_type.IsInterface ||
+                                   (hm.move_next = FetchMethodMoveNext (return_type)) == null ||
+                                   (hm.get_current = FetchMethodGetCurrent (return_type)) == null) {
+                                       
                                        hm.move_next = TypeManager.bool_movenext_void;
                                        hm.get_current = TypeManager.object_getcurrent_void;
-                                       return true;
+                                       return true;    
                                }
-                       }
 
-                       //
-                       // Ok, so they dont return an IEnumerable, we will have to
-                       // find if they support the GetEnumerator pattern.
-                       //
-                       Type return_type = mi.ReturnType;
-
-                       hm.move_next = FetchMethodMoveNext (return_type);
-                       if (hm.move_next == null)
-                               return false;
-                       hm.get_current = FetchMethodGetCurrent (return_type);
-                       if (hm.get_current == null)
-                               return false;
+                       } else {
 
+                               //
+                               // Ok, so they dont return an IEnumerable, we will have to
+                               // find if they support the GetEnumerator pattern.
+                               //
+                               
+                               hm.move_next = FetchMethodMoveNext (return_type);
+                               if (hm.move_next == null)
+                                       return false;
+                               
+                               hm.get_current = FetchMethodGetCurrent (return_type);
+                               if (hm.get_current == null)
+                                       return false;
+                       }
+                       
                        hm.element_type = hm.get_current.ReturnType;
                        hm.enumerator_type = return_type;
                        hm.is_disposable = !hm.enumerator_type.IsSealed ||
@@ -3837,14 +3904,9 @@ namespace Mono.CSharp {
                bool EmitCollectionForeach (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
-                       VariableStorage enumerator, disposable;
+                       VariableStorage enumerator;
 
                        enumerator = new VariableStorage (ec, hm.enumerator_type);
-                       if (hm.is_disposable)
-                               disposable = new VariableStorage (ec, TypeManager.idisposable_type);
-                       else
-                               disposable = null;
-
                        enumerator.EmitThis ();
                        //
                        // Instantiate the enumerator
@@ -3853,11 +3915,18 @@ namespace Mono.CSharp {
                                if (expr is IMemoryLocation){
                                        IMemoryLocation ml = (IMemoryLocation) expr;
 
-                                       ml.AddressOf (ec, AddressOp.Load);
+                                       Expression ml1 = Expression.MemberLookup(ec, TypeManager.ienumerator_type, expr.Type, "GetEnumerator", Mono.CSharp.Location.Null);
+
+                                       if (!(ml1 is MethodGroupExpr)) {
+                                               expr.Emit(ec);
+                                               ec.ig.Emit(OpCodes.Box, expr.Type);
+                                       } else {
+                                               ml.AddressOf (ec, AddressOp.Load);
+                                       }
                                } else
                                        throw new Exception ("Expr " + expr + " of type " + expr.Type +
                                                             " does not implement IMemoryLocation");
-                               ig.Emit (OpCodes.Call, hm.get_enumerator);
+                               ig.Emit (OpCodes.Callvirt, hm.get_enumerator);
                        } else {
                                expr.Emit (ec);
                                ig.Emit (OpCodes.Callvirt, hm.get_enumerator);
@@ -3868,24 +3937,20 @@ namespace Mono.CSharp {
                        // Protect the code in a try/finalize block, so that
                        // if the beast implement IDisposable, we get rid of it
                        //
-                       bool old_in_try = ec.InTry;
-
-                       if (hm.is_disposable) {
+                       if (hm.is_disposable)
                                ig.BeginExceptionBlock ();
-                               ec.InTry = true;
-                       }
                        
                        Label end_try = ig.DefineLabel ();
                        
                        ig.MarkLabel (ec.LoopBegin);
-                       enumerator.EmitLoad ();
-                       ig.Emit (OpCodes.Callvirt, hm.move_next);
+                       
+                       enumerator.EmitCall (hm.move_next);
+                       
                        ig.Emit (OpCodes.Brfalse, end_try);
                        if (ec.InIterator)
                                ec.EmitThis ();
                        
-                       enumerator.EmitLoad ();
-                       ig.Emit (OpCodes.Callvirt, hm.get_current);
+                       enumerator.EmitCall (hm.get_current);
 
                        if (ec.InIterator){
                                conv.Emit (ec);
@@ -3896,7 +3961,6 @@ namespace Mono.CSharp {
                        statement.Emit (ec);
                        ig.Emit (OpCodes.Br, ec.LoopBegin);
                        ig.MarkLabel (end_try);
-                       ec.InTry = old_in_try;
                        
                        // The runtime provides this for us.
                        // ig.Emit (OpCodes.Leave, end);
@@ -3905,23 +3969,20 @@ namespace Mono.CSharp {
                        // Now the finally block
                        //
                        if (hm.is_disposable) {
-                               Label end_finally = ig.DefineLabel ();
-                               bool old_in_finally = ec.InFinally;
-                               ec.InFinally = true;
+                               Label call_dispose = ig.DefineLabel ();
                                ig.BeginFinallyBlock ();
-
-                               disposable.EmitThis ();
+                               
                                enumerator.EmitThis ();
                                enumerator.EmitLoad ();
                                ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
-                               disposable.EmitStore ();
-                               disposable.EmitLoad ();
-                               ig.Emit (OpCodes.Brfalse, end_finally);
-                               disposable.EmitThis ();
-                               disposable.EmitLoad ();
+                               ig.Emit (OpCodes.Dup);
+                               ig.Emit (OpCodes.Brtrue_S, call_dispose);
+                               ig.Emit (OpCodes.Pop);
+                               ig.Emit (OpCodes.Endfinally);
+                               
+                               ig.MarkLabel (call_dispose);
                                ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
-                               ig.MarkLabel (end_finally);
-                               ec.InFinally = old_in_finally;
+                               
 
                                // The runtime generates this anyways.
                                // ig.Emit (OpCodes.Endfinally);
@@ -4052,7 +4113,7 @@ namespace Mono.CSharp {
                                for (int i = 0; i < rank; i++)
                                        args [i] = TypeManager.int32_type;
 
-                               ModuleBuilder mb = CodeGen.ModuleBuilder;
+                               ModuleBuilder mb = CodeGen.Module.Builder;
                                get = mb.GetArrayMethod (
                                        array_type, "Get",
                                        CallingConventions.HasThis| CallingConventions.Standard,
@@ -4091,12 +4152,8 @@ namespace Mono.CSharp {
                        ILGenerator ig = ec.ig;
                        
                        Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
-                       bool old_inloop = ec.InLoop;
-                       int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
                        ec.LoopBegin = ig.DefineLabel ();
                        ec.LoopEnd = ig.DefineLabel ();
-                       ec.InLoop = true;
-                       ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
                        
                        if (hm != null)
                                EmitCollectionForeach (ec);
@@ -4105,8 +4162,6 @@ namespace Mono.CSharp {
                        
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
-                       ec.InLoop = old_inloop;
-                       ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
                }
        }
 }