2002-11-14 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / mcs / statement.cs
index 78d5843a4f26bb749c7780f70212048f0311e60a..610e57d28a741f12b2d3740ff5d712c3efe75398 100755 (executable)
@@ -33,7 +33,17 @@ namespace Mono.CSharp {
                /// <summary>
                ///   Return value indicates whether all code paths emitted return.
                /// </summary>
-               public abstract bool Emit (EmitContext ec);
+               protected abstract bool DoEmit (EmitContext ec);
+
+               /// <summary>
+               ///   Return value indicates whether all code paths emitted return.
+               /// </summary>
+               public virtual bool Emit (EmitContext ec)
+               {
+                       ec.Mark (loc);
+                       Report.Debug (8, "MARK", this, loc);
+                       return DoEmit (ec);
+               }
                
                public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
                {
@@ -51,8 +61,7 @@ namespace Mono.CSharp {
                                        31, loc, "Can not convert the expression to a boolean");
                        }
 
-                       if (CodeGen.SymbolWriter != null)
-                               ec.Mark (loc);
+                       ec.Mark (loc);
 
                        return e;
                }
@@ -114,7 +123,7 @@ namespace Mono.CSharp {
                        return true;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        return false;
                }
@@ -145,7 +154,7 @@ namespace Mono.CSharp {
 
                public override bool Resolve (EmitContext ec)
                {
-                       Report.Debug (1, "START IF BLOCK");
+                       Report.Debug (1, "START IF BLOCK", loc);
 
                        expr = ResolveBoolean (ec, expr, loc);
                        if (expr == null){
@@ -168,12 +177,12 @@ namespace Mono.CSharp {
                                        
                        ec.EndFlowBranching ();
 
-                       Report.Debug (1, "END IF BLOCK");
+                       Report.Debug (1, "END IF BLOCK", loc);
 
                        return true;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
                        Label false_target = ig.DefineLabel ();
@@ -229,6 +238,7 @@ namespace Mono.CSharp {
        public class Do : Statement {
                public Expression expr;
                public readonly Statement  EmbeddedStatement;
+               bool infinite, may_return;
                
                public Do (Statement statement, Expression boolExpr, Location l)
                {
@@ -239,24 +249,37 @@ namespace Mono.CSharp {
 
                public override bool Resolve (EmitContext ec)
                {
+                       bool ok = true;
+
+                       ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+
                        if (!EmbeddedStatement.Resolve (ec))
-                               return false;
+                               ok = false;
 
                        expr = ResolveBoolean (ec, expr, loc);
                        if (expr == null)
-                               return false;
-                       
-                       return true;
+                               ok = false;
+                       else if (expr is BoolConstant){
+                               bool res = ((BoolConstant) expr).Value;
+
+                               if (res)
+                                       infinite = true;
+                       }
+
+                       ec.CurrentBranching.Infinite = infinite;
+                       FlowReturns returns = ec.EndFlowBranching ();
+                       may_return = returns != FlowReturns.NEVER;
+
+                       return ok;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
                        Label loop = ig.DefineLabel ();
                        Label old_begin = ec.LoopBegin;
                        Label old_end = ec.LoopEnd;
                        bool  old_inloop = ec.InLoop;
-                       bool old_breaks = ec.Breaks;
                        int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
                        
                        ec.LoopBegin = ig.DefineLabel ();
@@ -265,9 +288,7 @@ namespace Mono.CSharp {
                        ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
                                
                        ig.MarkLabel (loop);
-                       ec.Breaks = false;
                        EmbeddedStatement.Emit (ec);
-                       bool breaks = ec.Breaks;
                        ig.MarkLabel (ec.LoopBegin);
 
                        //
@@ -287,25 +308,18 @@ namespace Mono.CSharp {
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
                        ec.InLoop = old_inloop;
-                       ec.Breaks = old_breaks;
-
-                       //
-                       // Inform whether we are infinite or not
-                       //
-                       if (expr is BoolConstant){
-                               BoolConstant bc = (BoolConstant) expr;
 
-                               if (bc.Value == true)
-                                       return breaks == false;
-                       }
-                       
-                       return false;
+                       if (infinite)
+                               return may_return == false;
+                       else
+                               return false;
                }
        }
 
        public class While : Statement {
                public Expression expr;
                public readonly Statement Statement;
+               bool may_return, empty, infinite;
                
                public While (Expression boolExpr, Statement statement, Location l)
                {
@@ -316,21 +330,55 @@ namespace Mono.CSharp {
 
                public override bool Resolve (EmitContext ec)
                {
+                       bool ok = true;
+
                        expr = ResolveBoolean (ec, expr, loc);
                        if (expr == null)
                                return false;
-                       
-                       return Statement.Resolve (ec);
+
+                       ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+
+                       //
+                       // Inform whether we are infinite or not
+                       //
+                       if (expr is BoolConstant){
+                               BoolConstant bc = (BoolConstant) expr;
+
+                               if (bc.Value == false){
+                                       Warning_DeadCodeFound (Statement.loc);
+                                       empty = true;
+                               } else
+                                       infinite = true;
+                       } else {
+                               //
+                               // We are not infinite, so the loop may or may not be executed.
+                               //
+                               ec.CurrentBranching.CreateSibling ();
+                       }
+
+                       if (!Statement.Resolve (ec))
+                               ok = false;
+
+                       if (empty)
+                               ec.KillFlowBranching ();
+                       else {
+                               ec.CurrentBranching.Infinite = infinite;
+                               FlowReturns returns = ec.EndFlowBranching ();
+                               may_return = returns != FlowReturns.NEVER;
+                       }
+
+                       return ok;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
+                       if (empty)
+                               return false;
+
                        ILGenerator ig = ec.ig;
                        Label old_begin = ec.LoopBegin;
                        Label old_end = ec.LoopEnd;
                        bool old_inloop = ec.InLoop;
-                       bool old_breaks = ec.Breaks;
-                       Label while_loop = ig.DefineLabel ();
                        int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
                        bool ret;
                        
@@ -339,9 +387,6 @@ namespace Mono.CSharp {
                        ec.InLoop = true;
                        ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
 
-                       ig.Emit (OpCodes.Br, ec.LoopBegin);
-                       ig.MarkLabel (while_loop);
-
                        //
                        // Inform whether we are infinite or not
                        //
@@ -349,25 +394,21 @@ namespace Mono.CSharp {
                                BoolConstant bc = (BoolConstant) expr;
 
                                ig.MarkLabel (ec.LoopBegin);
-                               if (bc.Value == false){
-                                       Warning_DeadCodeFound (Statement.loc);
-                                       ret = false;
-                               } else {
-                                       bool breaks;
-                                       
-                                       ec.Breaks = false;
-                                       Statement.Emit (ec);
-                                       breaks = ec.Breaks;
-                                       ig.Emit (OpCodes.Br, ec.LoopBegin);
+                               Statement.Emit (ec);
+                               ig.Emit (OpCodes.Br, ec.LoopBegin);
                                        
-                                       //
-                                       // Inform that we are infinite (ie, `we return'), only
-                                       // if we do not `break' inside the code.
-                                       //
-                                       ret = breaks == false;
-                               }
+                               //
+                               // Inform that we are infinite (ie, `we return'), only
+                               // if we do not `break' inside the code.
+                               //
+                               ret = may_return == false;
                                ig.MarkLabel (ec.LoopEnd);
                        } else {
+                               Label while_loop = ig.DefineLabel ();
+
+                               ig.Emit (OpCodes.Br, ec.LoopBegin);
+                               ig.MarkLabel (while_loop);
+
                                Statement.Emit (ec);
                        
                                ig.MarkLabel (ec.LoopBegin);
@@ -381,7 +422,6 @@ namespace Mono.CSharp {
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
                        ec.InLoop = old_inloop;
-                       ec.Breaks = old_breaks;
                        ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
 
                        return ret;
@@ -393,6 +433,7 @@ namespace Mono.CSharp {
                readonly Statement InitStatement;
                readonly Statement Increment;
                readonly Statement Statement;
+               bool may_return, infinite, empty;
                
                public For (Statement initStatement,
                            Expression test,
@@ -420,23 +461,50 @@ namespace Mono.CSharp {
                                Test = ResolveBoolean (ec, Test, loc);
                                if (Test == null)
                                        ok = false;
-                       }
+                               else if (Test is BoolConstant){
+                                       BoolConstant bc = (BoolConstant) Test;
+
+                                       if (bc.Value == false){
+                                               Warning_DeadCodeFound (Statement.loc);
+                                               empty = true;
+                                       } else
+                                               infinite = true;
+                               }
+                       } else
+                               infinite = true;
 
                        if (Increment != null){
                                if (!Increment.Resolve (ec))
                                        ok = false;
                        }
-                       
-                       return Statement.Resolve (ec) && ok;
+
+                       ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+                       if (!infinite)
+                               ec.CurrentBranching.CreateSibling ();
+
+                       if (!Statement.Resolve (ec))
+                               ok = false;
+
+                       if (empty)
+                               ec.KillFlowBranching ();
+                       else {
+                               ec.CurrentBranching.Infinite = infinite;
+                               FlowReturns returns = ec.EndFlowBranching ();
+                               may_return = returns != FlowReturns.NEVER;
+                       }
+
+                       return ok;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
+                       if (empty)
+                               return false;
+
                        ILGenerator ig = ec.ig;
                        Label old_begin = ec.LoopBegin;
                        Label old_end = ec.LoopEnd;
                        bool old_inloop = ec.InLoop;
-                       bool old_breaks = ec.Breaks;
                        int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
                        Label loop = ig.DefineLabel ();
                        Label test = ig.DefineLabel ();
@@ -452,9 +520,7 @@ namespace Mono.CSharp {
 
                        ig.Emit (OpCodes.Br, test);
                        ig.MarkLabel (loop);
-                       ec.Breaks = false;
                        Statement.Emit (ec);
-                       bool breaks = ec.Breaks;
 
                        ig.MarkLabel (ec.LoopBegin);
                        if (!(Increment is EmptyStatement))
@@ -474,22 +540,21 @@ namespace Mono.CSharp {
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
                        ec.InLoop = old_inloop;
-                       ec.Breaks = old_breaks;
                        ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
                        
                        //
-                       // Inform whether we are infinite or not
+                       // Inform whether we are infinite or not
                        //
                        if (Test != null){
                                if (Test is BoolConstant){
                                        BoolConstant bc = (BoolConstant) Test;
 
                                        if (bc.Value)
-                                               return breaks == false;
+                                               return may_return == false;
                                }
                                return false;
                        } else
-                               return true;
+                               return may_return == false;
                }
        }
        
@@ -508,7 +573,7 @@ namespace Mono.CSharp {
                        return expr != null;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
                        
@@ -552,14 +617,15 @@ namespace Mono.CSharp {
 
                        if (ec.CurrentBranching.InTryBlock ())
                                ec.CurrentBranching.AddFinallyVector (vector);
+                       else
+                               vector.CheckOutParameters (ec.CurrentBranching);
 
                        vector.Returns = FlowReturns.ALWAYS;
                        vector.Breaks = FlowReturns.ALWAYS;
-
                        return true;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        if (ec.InFinally){
                                Report.Error (157,loc,"Control can not leave the body of the finally block");
@@ -642,7 +708,7 @@ namespace Mono.CSharp {
                        }
                }
 
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        Label l = label.LabelTarget (ec);
                        ec.ig.Emit (OpCodes.Br, l);
@@ -700,13 +766,17 @@ namespace Mono.CSharp {
                {
                        if (vectors != null)
                                ec.CurrentBranching.CurrentUsageVector.MergeJumpOrigins (vectors);
+                       else {
+                               ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.NEVER;
+                               ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.NEVER;
+                       }
 
                        referenced = true;
 
                        return true;
                }
 
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        LabelTarget (ec);
                        ec.ig.MarkLabel (label);
@@ -728,12 +798,11 @@ namespace Mono.CSharp {
 
                public override bool Resolve (EmitContext ec)
                {
-                       ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.UNREACHABLE;
-                       ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+                       ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.UNREACHABLE;
                        return true;
                }
 
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        if (ec.Switch == null){
                                Report.Error (153, loc, "goto default is only valid in a switch statement");
@@ -794,12 +863,11 @@ namespace Mono.CSharp {
 
                        label = sl.ILLabelCode;
 
-                       ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.UNREACHABLE;
-                       ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+                       ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.UNREACHABLE;
                        return true;
                }
 
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        ec.ig.Emit (OpCodes.Br, label);
                        return true;
@@ -832,7 +900,9 @@ namespace Mono.CSharp {
 
                                Type t = expr.Type;
                                
-                               if (t != TypeManager.exception_type && !t.IsSubclassOf (TypeManager.exception_type)) {
+                               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");
@@ -845,7 +915,7 @@ namespace Mono.CSharp {
                        return true;
                }
                        
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        if (expr == null){
                                if (ec.InCatch)
@@ -876,11 +946,12 @@ namespace Mono.CSharp {
 
                public override bool Resolve (EmitContext ec)
                {
+                       ec.CurrentBranching.MayLeaveLoop = true;
                        ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
                        return true;
                }
 
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
 
@@ -889,7 +960,6 @@ namespace Mono.CSharp {
                                return false;
                        }
 
-                       ec.Breaks = true;
                        if (ec.InTry || ec.InCatch)
                                ig.Emit (OpCodes.Leave, ec.LoopEnd);
                        else
@@ -912,7 +982,7 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        Label begin = ec.LoopBegin;
                        
@@ -1170,6 +1240,9 @@ namespace Mono.CSharp {
                // Normal (conditional or toplevel) block.
                BLOCK,
 
+               // A loop block.
+               LOOP_BLOCK,
+
                // Try/Catch block.
                EXCEPTION,
 
@@ -1212,11 +1285,22 @@ namespace Mono.CSharp {
                // </summary>
                public ArrayList Siblings;
 
+               // <summary>
+               //   If this is an infinite loop.
+               // </summary>
+               public bool Infinite;
+
+               // <summary>
+               //   If we may leave the current loop.
+               // </summary>
+               public bool MayLeaveLoop;
+
                //
                // Private
                //
                InternalParameters param_info;
                int[] param_map;
+               MyStructInfo[] struct_params;
                int num_params;
                ArrayList finally_vectors;
 
@@ -1294,7 +1378,7 @@ namespace Mono.CSharp {
                        //
                        MyBitVector locals, parameters;
                        FlowReturns real_returns, real_breaks;
-                       bool returns_set, breaks_set, is_finally;
+                       bool is_finally;
 
                        static int next_id = 0;
                        int id;
@@ -1314,6 +1398,8 @@ namespace Mono.CSharp {
                                        locals = new MyBitVector (parent.locals, CountLocals);
                                        if (num_params > 0)
                                                parameters = new MyBitVector (parent.parameters, num_params);
+                                       real_returns = parent.Returns;
+                                       real_breaks = parent.Breaks;
                                } else {
                                        locals = new MyBitVector (null, CountLocals);
                                        if (num_params > 0)
@@ -1369,8 +1455,10 @@ namespace Mono.CSharp {
 
                        //
                        // State of the local variable `vi'.
+                       // If the local variable is a struct, use a non-zero `field_idx'
+                       // to check an individual field in it.
                        //
-                       public bool this [VariableInfo vi]
+                       public bool this [VariableInfo vi, int field_idx]
                        {
                                get {
                                        if (vi.Number == -1)
@@ -1378,7 +1466,7 @@ namespace Mono.CSharp {
                                        else if (vi.Number == 0)
                                                throw new ArgumentException ();
 
-                                       return locals [vi.Number - 1];
+                                       return locals [vi.Number + field_idx - 1];
                                }
 
                                set {
@@ -1387,12 +1475,16 @@ namespace Mono.CSharp {
                                        else if (vi.Number == 0)
                                                throw new ArgumentException ();
 
-                                       locals [vi.Number - 1] = value;
+                                       locals [vi.Number + field_idx - 1] = value;
                                }
                        }
 
                        // <summary>
                        //   Specifies when the current block returns.
+                       //   If this is FlowReturns.UNREACHABLE, then control can never reach the
+                       //   end of the method (so that we don't need to emit a return statement).
+                       //   The same applies for FlowReturns.EXCEPTION, but in this case the return
+                       //   value will never be used.
                        // </summary>
                        public FlowReturns Returns {
                                get {
@@ -1401,7 +1493,6 @@ namespace Mono.CSharp {
 
                                set {
                                        real_returns = value;
-                                       returns_set = true;
                                }
                        }
 
@@ -1409,6 +1500,8 @@ namespace Mono.CSharp {
                        //   Specifies whether control may return to our containing block
                        //   before reaching the end of this block.  This happens if there
                        //   is a break/continue/goto/return in it.
+                       //   This can also be used to find out whether the statement immediately
+                       //   following the current block may be reached or not.
                        // </summary>
                        public FlowReturns Breaks {
                                get {
@@ -1417,7 +1510,34 @@ namespace Mono.CSharp {
 
                                set {
                                        real_breaks = value;
-                                       breaks_set = true;
+                               }
+                       }
+
+                       public bool AlwaysBreaks {
+                               get {
+                                       return (Breaks == FlowReturns.ALWAYS) ||
+                                               (Breaks == FlowReturns.EXCEPTION) ||
+                                               (Breaks == FlowReturns.UNREACHABLE);
+                               }
+                       }
+
+                       public bool MayBreak {
+                               get {
+                                       return Breaks != FlowReturns.NEVER;
+                               }
+                       }
+
+                       public bool AlwaysReturns {
+                               get {
+                                       return (Returns == FlowReturns.ALWAYS) ||
+                                               (Returns == FlowReturns.EXCEPTION);
+                               }
+                       }
+
+                       public bool MayReturn {
+                               get {
+                                       return (Returns == FlowReturns.SOMETIMES) ||
+                                               (Returns == FlowReturns.ALWAYS);
                                }
                        }
 
@@ -1432,39 +1552,39 @@ namespace Mono.CSharp {
                                FlowReturns new_returns = FlowReturns.NEVER;
                                FlowReturns new_breaks = FlowReturns.NEVER;
                                bool new_returns_set = false, new_breaks_set = false;
-                               FlowReturns breaks;
 
-                               Report.Debug (1, "MERGING CHILDREN", branching, this);
+                               Report.Debug (2, "MERGING CHILDREN", branching, branching.Type,
+                                             this, children.Count);
 
                                foreach (UsageVector child in children) {
-                                       Report.Debug (1, "  MERGING CHILD", child);
-
-                                       // If Returns is already set, perform an `And' operation on it,
-                                       // otherwise just set just.
-                                       if (!new_returns_set) {
-                                               new_returns = child.Returns;
-                                               new_returns_set = true;
-                                       } else
-                                               new_returns = AndFlowReturns (new_returns, child.Returns);
+                                       Report.Debug (2, "  MERGING CHILD", child, child.is_finally);
+                                       
+                                       if (!child.is_finally) {
+                                               if (child.Breaks != FlowReturns.UNREACHABLE) {
+                                                       // If Returns is already set, perform an
+                                                       // `And' operation on it, otherwise just set just.
+                                                       if (!new_returns_set) {
+                                                               new_returns = child.Returns;
+                                                               new_returns_set = true;
+                                                       } else
+                                                               new_returns = AndFlowReturns (
+                                                                       new_returns, child.Returns);
+                                               }
 
-                                       // If Breaks is already set, perform an `And' operation on it,
-                                       // otherwise just set just.
-                                       if (!new_breaks_set) {
-                                               new_breaks = child.Breaks;
-                                               new_breaks_set = true;
-                                       } else
-                                               new_breaks = AndFlowReturns (new_breaks, child.Breaks);
+                                               // If Breaks is already set, perform an
+                                               // `And' operation on it, otherwise just set just.
+                                               if (!new_breaks_set) {
+                                                       new_breaks = child.Breaks;
+                                                       new_breaks_set = true;
+                                               } else
+                                                       new_breaks = AndFlowReturns (
+                                                               new_breaks, child.Breaks);
+                                       }
 
                                        // Ignore unreachable children.
                                        if (child.Returns == FlowReturns.UNREACHABLE)
                                                continue;
 
-                                       // If we're a switch section, `break' won't leave the current
-                                       // branching (NOTE: the type check here means that we're "a"
-                                       // switch section, not that we're "in" a switch section!).
-                                       breaks = (branching.Type == FlowBranchingType.SWITCH_SECTION) ?
-                                               child.Returns : child.Breaks;
-
                                        // A local variable is initialized after a flow branching if it
                                        // has been initialized in all its branches which do neither
                                        // always return or always throw an exception.
@@ -1500,43 +1620,60 @@ namespace Mono.CSharp {
                                        // Here, `a' is initialized in line 3 and we must not look at
                                        // line 5 since it always returns.
                                        // 
-                                       if ((breaks != FlowReturns.EXCEPTION) &&
-                                           (breaks != FlowReturns.ALWAYS)) {
-                                               if (new_locals != null)
-                                                       new_locals.And (child.locals);
-                                               else {
+                                       if (child.is_finally) {
+                                               if (new_locals == null)
+                                                       new_locals = locals.Clone ();
+                                               new_locals.Or (child.locals);
+
+                                               if (parameters != null) {
+                                                       if (new_params == null)
+                                                               new_params = parameters.Clone ();
+                                                       new_params.Or (child.parameters);
+                                               }
+
+                                       } else {
+                                               if (!child.AlwaysReturns && !child.AlwaysBreaks) {
+                                                       if (new_locals != null)
+                                                               new_locals.And (child.locals);
+                                                       else {
+                                                               new_locals = locals.Clone ();
+                                                               new_locals.Or (child.locals);
+                                                       }
+                                               } else if (children.Count == 1) {
                                                        new_locals = locals.Clone ();
                                                        new_locals.Or (child.locals);
                                                }
-                                       }
 
-                                       // An `out' parameter must be assigned in all branches which do
-                                       // not always throw an exception.
-                                       if (!child.is_finally && (child.Returns != FlowReturns.EXCEPTION)) {
+                                               // An `out' parameter must be assigned in all branches which do
+                                               // not always throw an exception.
                                                if (parameters != null) {
-                                                       if (new_params != null)
-                                                               new_params.And (child.parameters);
-                                                       else {
+                                                       if (child.Breaks != FlowReturns.EXCEPTION) {
+                                                               if (new_params != null)
+                                                                       new_params.And (child.parameters);
+                                                               else {
+                                                                       new_params = parameters.Clone ();
+                                                                       new_params.Or (child.parameters);
+                                                               }
+                                                       } else if (children.Count == 1) {
                                                                new_params = parameters.Clone ();
                                                                new_params.Or (child.parameters);
                                                        }
                                                }
                                        }
-
-                                       // If we always return, check whether all `out' parameters have
-                                       // been assigned.
-                                       if ((child.Returns == FlowReturns.ALWAYS) && (child.parameters != null)) {
-                                               branching.CheckOutParameters (
-                                                       child.parameters, branching.Location);
-                                       }
                                }
 
-                               // Set new `Returns' status.
-                               if (!returns_set) {
-                                       Returns = new_returns;
-                                       returns_set = true;
-                               } else
-                                       Returns = AndFlowReturns (Returns, new_returns);
+                               Returns = new_returns;
+                               if ((branching.Type == FlowBranchingType.BLOCK) ||
+                                   (branching.Type == FlowBranchingType.EXCEPTION) ||
+                                   (new_breaks == FlowReturns.UNREACHABLE) ||
+                                   (new_breaks == FlowReturns.EXCEPTION))
+                                       Breaks = new_breaks;
+                               else if (branching.Type == FlowBranchingType.SWITCH_SECTION)
+                                       Breaks = new_returns;
+                               else if (branching.Type == FlowBranchingType.SWITCH){
+                                       if (new_breaks == FlowReturns.ALWAYS)
+                                               Breaks = FlowReturns.ALWAYS;
+                               }
 
                                //
                                // We've now either reached the point after the branching or we will
@@ -1547,30 +1684,50 @@ namespace Mono.CSharp {
                                // we need to look at (see above).
                                //
 
-                               breaks = (branching.Type == FlowBranchingType.SWITCH_SECTION) ?
-                                       Returns : Breaks;
+                               if (((new_breaks != FlowReturns.ALWAYS) &&
+                                    (new_breaks != FlowReturns.EXCEPTION) &&
+                                    (new_breaks != FlowReturns.UNREACHABLE)) ||
+                                   (children.Count == 1)) {
+                                       if (new_locals != null)
+                                               locals.Or (new_locals);
 
-                               if ((new_locals != null) &&
-                                   ((breaks == FlowReturns.NEVER) || (breaks == FlowReturns.SOMETIMES))) {
-                                       locals.Or (new_locals);
+                                       if (new_params != null)
+                                               parameters.Or (new_params);
                                }
 
-                               if ((new_params != null) && (Breaks == FlowReturns.NEVER))
-                                       parameters.Or (new_params);
+                               Report.Debug (2, "MERGING CHILDREN DONE", branching.Type,
+                                             new_params, new_locals, new_returns, new_breaks,
+                                             branching.Infinite, branching.MayLeaveLoop, this);
+
+                               if (branching.Type == FlowBranchingType.SWITCH_SECTION) {
+                                       if ((new_breaks != FlowReturns.ALWAYS) &&
+                                           (new_breaks != FlowReturns.EXCEPTION) &&
+                                           (new_breaks != FlowReturns.UNREACHABLE))
+                                               Report.Error (163, branching.Location,
+                                                             "Control cannot fall through from one " +
+                                                             "case label to another");
+                               }
 
-                               //
-                               // If we may have returned (this only happens if there was a reachable
-                               // `return' statement in one of the branches), then we may return to our
-                               // parent block before reaching the end of the block, so set `Breaks'.
-                               //
+                               if (branching.Infinite && !branching.MayLeaveLoop) {
+                                       Report.Debug (1, "INFINITE", new_returns, new_breaks,
+                                                     Returns, Breaks, this);
 
-                               if ((Returns != FlowReturns.NEVER) && (Returns != FlowReturns.SOMETIMES)) {
-                                       real_breaks = Returns;
-                                       breaks_set = true;
-                               }
+                                       // We're actually infinite.
+                                       if (new_returns == FlowReturns.NEVER) {
+                                               Breaks = FlowReturns.UNREACHABLE;
+                                               return FlowReturns.UNREACHABLE;
+                                       }
 
-                               Report.Debug (1, "MERGING CHILDREN DONE", new_params, new_locals,
-                                             new_returns, new_breaks, this);
+                                       // If we're an infinite loop and do not break, the code after
+                                       // the loop can never be reached.  However, if we may return
+                                       // from the loop, then we do always return (or stay in the loop
+                                       // forever).
+                                       if ((new_returns == FlowReturns.SOMETIMES) ||
+                                           (new_returns == FlowReturns.ALWAYS)) {
+                                               Returns = FlowReturns.ALWAYS;
+                                               return FlowReturns.ALWAYS;
+                                       }
+                               }
 
                                return new_returns;
                        }
@@ -1600,7 +1757,7 @@ namespace Mono.CSharp {
                                Report.Debug (1, "MERGING JUMP ORIGIN", this);
 
                                real_breaks = FlowReturns.NEVER;
-                               breaks_set = false;
+                               real_returns = FlowReturns.NEVER;
 
                                foreach (UsageVector vector in origin_vectors) {
                                        Report.Debug (1, "  MERGING JUMP ORIGIN", vector);
@@ -1609,6 +1766,7 @@ namespace Mono.CSharp {
                                        if (parameters != null)
                                                parameters.And (vector.parameters);
                                        Breaks = AndFlowReturns (Breaks, vector.Breaks);
+                                       Returns = AndFlowReturns (Returns, vector.Returns);
                                }
 
                                Report.Debug (1, "MERGING JUMP ORIGIN DONE", this);
@@ -1623,7 +1781,6 @@ namespace Mono.CSharp {
                                Report.Debug (1, "MERGING FINALLY ORIGIN", this);
 
                                real_breaks = FlowReturns.NEVER;
-                               breaks_set = false;
 
                                foreach (UsageVector vector in finally_vectors) {
                                        Report.Debug (1, "  MERGING FINALLY ORIGIN", vector);
@@ -1638,6 +1795,12 @@ namespace Mono.CSharp {
                                Report.Debug (1, "MERGING FINALLY ORIGIN DONE", this);
                        }
 
+                       public void CheckOutParameters (FlowBranching branching)
+                       {
+                               if (parameters != null)
+                                       branching.CheckOutParameters (parameters, branching.Location);
+                       }
+
                        // <summary>
                        //   Performs an `or' operation on the locals and the parameters.
                        // </summary>
@@ -1723,17 +1886,26 @@ namespace Mono.CSharp {
                        Block = block;
                        Parent = null;
 
+                       int count = (ip != null) ? ip.Count : 0;
+
                        param_info = ip;
-                       param_map = new int [(param_info != null) ? param_info.Count : 0];
+                       param_map = new int [count];
+                       struct_params = new MyStructInfo [count];
                        num_params = 0;
 
-                       for (int i = 0; i < param_map.Length; i++) {
+                       for (int i = 0; i < count; i++) {
                                Parameter.Modifier mod = param_info.ParameterModifier (i);
 
                                if ((mod & Parameter.Modifier.OUT) == 0)
                                        continue;
 
                                param_map [i] = ++num_params;
+
+                               Type param_type = param_info.ParameterType (i);
+
+                               struct_params [i] = MyStructInfo.GetStructInfo (param_type);
+                               if (struct_params [i] != null)
+                                       num_params += struct_params [i].Count;
                        }
 
                        Siblings = new ArrayList ();
@@ -1756,6 +1928,7 @@ namespace Mono.CSharp {
                        if (parent != null) {
                                param_info = parent.param_info;
                                param_map = parent.param_map;
+                               struct_params = parent.struct_params;
                                num_params = parent.num_params;
                        }
 
@@ -1820,15 +1993,38 @@ namespace Mono.CSharp {
                                return;
 
                        for (int i = 0; i < param_map.Length; i++) {
-                               if (param_map [i] == 0)
+                               int index = param_map [i];
+
+                               if (index == 0)
+                                       continue;
+
+                               if (parameters [index - 1])
                                        continue;
 
-                               if (!parameters [param_map [i] - 1]) {
+                               // If it's a struct, we must ensure that all its fields have
+                               // been assigned.  If the struct has any non-public fields, this
+                               // can only be done by assigning the whole struct.
+
+                               MyStructInfo struct_info = struct_params [index - 1];
+                               if ((struct_info == null) || struct_info.HasNonPublicFields) {
                                        Report.Error (
                                                177, loc, "The out parameter `" +
-                                               param_info.ParameterName (i) + "` must be " +
+                                               param_info.ParameterName (i) + "' must be " +
                                                "assigned before control leave the current method.");
                                        param_map [i] = 0;
+                                       continue;
+                               }
+
+
+                               for (int j = 0; j < struct_info.Count; j++) {
+                                       if (!parameters [index + j]) {
+                                               Report.Error (
+                                                       177, loc, "The out parameter `" +
+                                                       param_info.ParameterName (i) + "' must be " +
+                                                       "assigned before control leave the current method.");
+                                               param_map [i] = 0;
+                                               break;
+                                       }
                                }
                        }
                }
@@ -1838,9 +2034,16 @@ namespace Mono.CSharp {
                // </summary>
                public FlowReturns MergeChild (FlowBranching child)
                {
-                       return CurrentUsageVector.MergeChildren (child, child.Siblings);
-               }
+                       FlowReturns returns = CurrentUsageVector.MergeChildren (child, child.Siblings);
+
+                       if (child.Type != FlowBranchingType.LOOP_BLOCK)
+                               MayLeaveLoop |= child.MayLeaveLoop;
+                       else
+                               MayLeaveLoop = false;
 
+                       return returns;
+               }
                // <summary>
                //   Does the toplevel merging.
                // </summary>
@@ -1851,17 +2054,21 @@ namespace Mono.CSharp {
 
                        UsageVector vector = new UsageVector (null, num_params, Block.CountVariables);
 
+                       Report.Debug (1, "MERGING TOP BLOCK", Location, vector);
+
                        vector.MergeChildren (this, Siblings);
 
                        Siblings.Clear ();
                        Siblings.Add (vector);
 
-                       Report.Debug (1, "MERGING TOP BLOCK", vector);
-
-                       if (vector.Returns != FlowReturns.EXCEPTION)
-                               CheckOutParameters (CurrentUsageVector.Parameters, Location);
+                       Report.Debug (1, "MERGING TOP BLOCK DONE", Location, vector);
 
-                       return vector.Returns;
+                       if (vector.Breaks != FlowReturns.EXCEPTION) {
+                               if (!vector.AlwaysBreaks)
+                                       CheckOutParameters (CurrentUsageVector.Parameters, Location);
+                               return vector.AlwaysBreaks ? FlowReturns.ALWAYS : vector.Returns;
+                       } else
+                               return FlowReturns.EXCEPTION;
                }
 
                public bool InTryBlock ()
@@ -1889,46 +2096,135 @@ namespace Mono.CSharp {
 
                public bool IsVariableAssigned (VariableInfo vi)
                {
-                       Report.Debug (2, "CHECK VARIABLE ACCESS", this, vi);
+                       if (CurrentUsageVector.AlwaysBreaks)
+                               return true;
+                       else
+                               return CurrentUsageVector [vi, 0];
+               }
 
-                       if (CurrentUsageVector.Breaks == FlowReturns.UNREACHABLE)
+               public bool IsVariableAssigned (VariableInfo vi, int field_idx)
+               {
+                       if (CurrentUsageVector.AlwaysBreaks)
                                return true;
                        else
-                               return CurrentUsageVector [vi];
+                               return CurrentUsageVector [vi, field_idx];
                }
 
                public void SetVariableAssigned (VariableInfo vi)
                {
-                       Report.Debug (2, "SET VARIABLE ACCESS", this, vi, CurrentUsageVector);
+                       if (CurrentUsageVector.AlwaysBreaks)
+                               return;
 
-                       if (CurrentUsageVector.Breaks == FlowReturns.UNREACHABLE)
+                       CurrentUsageVector [vi, 0] = true;
+               }
+
+               public void SetVariableAssigned (VariableInfo vi, int field_idx)
+               {
+                       if (CurrentUsageVector.AlwaysBreaks)
                                return;
 
-                       CurrentUsageVector [vi] = true;
+                       CurrentUsageVector [vi, field_idx] = true;
                }
 
                public bool IsParameterAssigned (int number)
                {
-                       Report.Debug (2, "IS PARAMETER ASSIGNED", this, number);
+                       int index = param_map [number];
 
-                       if (param_map [number] == 0)
+                       if (index == 0)
                                return true;
-                       else
-                               return CurrentUsageVector [param_map [number]];
+
+                       if (CurrentUsageVector [index])
+                               return true;
+
+                       // Parameter is not assigned, so check whether it's a struct.
+                       // If it's either not a struct or a struct which non-public
+                       // fields, return false.
+                       MyStructInfo struct_info = struct_params [number];
+                       if ((struct_info == null) || struct_info.HasNonPublicFields)
+                               return false;
+
+                       // Ok, so each field must be assigned.
+                       for (int i = 0; i < struct_info.Count; i++)
+                               if (!CurrentUsageVector [index + i])
+                                       return false;
+
+                       return true;
                }
 
-               public void SetParameterAssigned (int number)
+               public bool IsParameterAssigned (int number, string field_name)
                {
-                       Report.Debug (2, "SET PARAMETER ACCESS", this, number, param_map [number],
-                                     CurrentUsageVector);
+                       int index = param_map [number];
+
+                       if (index == 0)
+                               return true;
+
+                       MyStructInfo info = (MyStructInfo) struct_params [number];
+                       if (info == null)
+                               return true;
+
+                       int field_idx = info [field_name];
+
+                       return CurrentUsageVector [index + field_idx];
+               }
 
+               public void SetParameterAssigned (int number)
+               {
                        if (param_map [number] == 0)
                                return;
 
-                       if (CurrentUsageVector.Breaks == FlowReturns.NEVER)
+                       if (!CurrentUsageVector.AlwaysBreaks)
                                CurrentUsageVector [param_map [number]] = true;
                }
 
+               public void SetParameterAssigned (int number, string field_name)
+               {
+                       int index = param_map [number];
+
+                       if (index == 0)
+                               return;
+
+                       MyStructInfo info = (MyStructInfo) struct_params [number];
+                       if (info == null)
+                               return;
+
+                       int field_idx = info [field_name];
+
+                       if (!CurrentUsageVector.AlwaysBreaks)
+                               CurrentUsageVector [index + field_idx] = true;
+               }
+
+               public bool IsReachable ()
+               {
+                       bool reachable;
+
+                       switch (Type) {
+                       case FlowBranchingType.SWITCH_SECTION:
+                               // The code following a switch block is reachable unless the switch
+                               // block always returns.
+                               reachable = !CurrentUsageVector.AlwaysReturns;
+                               break;
+
+                       case FlowBranchingType.LOOP_BLOCK:
+                               // The code following a loop is reachable unless the loop always
+                               // returns or it's an infinite loop without any `break's in it.
+                               reachable = !CurrentUsageVector.AlwaysReturns &&
+                                       (CurrentUsageVector.Breaks != FlowReturns.UNREACHABLE);
+                               break;
+
+                       default:
+                               // The code following a block or exception is reachable unless the
+                               // block either always returns or always breaks.
+                               reachable = !CurrentUsageVector.AlwaysBreaks &&
+                                       !CurrentUsageVector.AlwaysReturns;
+                               break;
+                       }
+
+                       Report.Debug (1, "REACHABLE", Type, CurrentUsageVector.Returns,
+                                     CurrentUsageVector.Breaks, CurrentUsageVector, reachable);
+
+                       return reachable;
+               }
+
                public override string ToString ()
                {
                        StringBuilder sb = new StringBuilder ("FlowBranching (");
@@ -1950,11 +2246,129 @@ namespace Mono.CSharp {
                        return sb.ToString ();
                }
        }
+
+       public class MyStructInfo {
+               public readonly Type Type;
+               public readonly FieldInfo[] Fields;
+               public readonly FieldInfo[] NonPublicFields;
+               public readonly int Count;
+               public readonly int CountNonPublic;
+               public readonly bool HasNonPublicFields;
+
+               private static Hashtable field_type_hash = new Hashtable ();
+               private Hashtable field_hash;
+
+               // Private constructor.  To save memory usage, we only need to create one instance
+               // of this class per struct type.
+               private MyStructInfo (Type type)
+               {
+                       this.Type = type;
+
+                       if (type is TypeBuilder) {
+                               TypeContainer tc = TypeManager.LookupTypeContainer (type);
+
+                               ArrayList fields = tc.Fields;
+                               if (fields != null) {
+                                       foreach (Field field in fields) {
+                                               if ((field.ModFlags & Modifiers.STATIC) != 0)
+                                                       continue;
+                                               if ((field.ModFlags & Modifiers.PUBLIC) != 0)
+                                                       ++Count;
+                                               else
+                                                       ++CountNonPublic;
+                                       }
+                               }
+
+                               Fields = new FieldInfo [Count];
+                               NonPublicFields = new FieldInfo [CountNonPublic];
+
+                               Count = CountNonPublic = 0;
+                               if (fields != null) {
+                                       foreach (Field field in fields) {
+                                               if ((field.ModFlags & Modifiers.STATIC) != 0)
+                                                       continue;
+                                               if ((field.ModFlags & Modifiers.PUBLIC) != 0)
+                                                       Fields [Count++] = field.FieldBuilder;
+                                               else
+                                                       NonPublicFields [CountNonPublic++] =
+                                                               field.FieldBuilder;
+                                       }
+                               }
+                               
+                       } else {
+                               Fields = type.GetFields (BindingFlags.Instance|BindingFlags.Public);
+                               Count = Fields.Length;
+
+                               NonPublicFields = type.GetFields (BindingFlags.Instance|BindingFlags.NonPublic);
+                               CountNonPublic = NonPublicFields.Length;
+                       }
+
+                       Count += NonPublicFields.Length;
+
+                       int number = 0;
+                       field_hash = new Hashtable ();
+                       foreach (FieldInfo field in Fields)
+                               field_hash.Add (field.Name, ++number);
+
+                       if (NonPublicFields.Length != 0)
+                               HasNonPublicFields = true;
+
+                       foreach (FieldInfo field in NonPublicFields)
+                               field_hash.Add (field.Name, ++number);
+               }
+
+               public int this [string name] {
+                       get {
+                               if (field_hash.Contains (name))
+                                       return (int) field_hash [name];
+                               else
+                                       return 0;
+                       }
+               }
+
+               public FieldInfo this [int index] {
+                       get {
+                               if (index >= Fields.Length)
+                                       return NonPublicFields [index - Fields.Length];
+                               else
+                                       return Fields [index];
+                       }
+               }                      
+
+               public static MyStructInfo GetStructInfo (Type type)
+               {
+                       if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type))
+                               return null;
+
+                       if (!(type is TypeBuilder) && TypeManager.IsBuiltinType (type))
+                               return null;
+
+                       MyStructInfo info = (MyStructInfo) field_type_hash [type];
+                       if (info != null)
+                               return info;
+
+                       info = new MyStructInfo (type);
+                       field_type_hash.Add (type, info);
+                       return info;
+               }
+
+               public static MyStructInfo GetStructInfo (TypeContainer tc)
+               {
+                       MyStructInfo info = (MyStructInfo) field_type_hash [tc.TypeBuilder];
+                       if (info != null)
+                               return info;
+
+                       info = new MyStructInfo (tc.TypeBuilder);
+                       field_type_hash.Add (tc.TypeBuilder, info);
+                       return info;
+               }
+       }
        
-       public class VariableInfo {
+       public class VariableInfo : IVariable {
                public Expression Type;
                public LocalBuilder LocalBuilder;
                public Type VariableType;
+               public readonly string Name;
                public readonly Location Location;
                public readonly int Block;
 
@@ -1964,14 +2378,115 @@ namespace Mono.CSharp {
                public bool Assigned;
                public bool ReadOnly;
                
-               public VariableInfo (Expression type, int block, Location l)
+               public VariableInfo (Expression type, string name, int block, Location l)
                {
                        Type = type;
+                       Name = name;
                        Block = block;
                        LocalBuilder = null;
                        Location = l;
                }
 
+               public VariableInfo (TypeContainer tc, int block, Location l)
+               {
+                       VariableType = tc.TypeBuilder;
+                       struct_info = MyStructInfo.GetStructInfo (tc);
+                       Block = block;
+                       LocalBuilder = null;
+                       Location = l;
+               }
+
+               MyStructInfo struct_info;
+               public MyStructInfo StructInfo {
+                       get {
+                               return struct_info;
+                       }
+               }
+
+               public bool IsAssigned (EmitContext ec, Location loc)
+               {
+                       if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsVariableAssigned (this))
+                               return true;
+
+                       MyStructInfo struct_info = StructInfo;
+                       if ((struct_info == null) || (struct_info.HasNonPublicFields && (Name != null))) {
+                               Report.Error (165, loc, "Use of unassigned local variable `" + Name + "'");
+                               ec.CurrentBranching.SetVariableAssigned (this);
+                               return false;
+                       }
+
+                       int count = struct_info.Count;
+
+                       for (int i = 0; i < count; i++) {
+                               if (!ec.CurrentBranching.IsVariableAssigned (this, i+1)) {
+                                       if (Name != null) {
+                                               Report.Error (165, loc,
+                                                             "Use of unassigned local variable `" +
+                                                             Name + "'");
+                                               ec.CurrentBranching.SetVariableAssigned (this);
+                                               return false;
+                                       }
+
+                                       FieldInfo field = struct_info [i];
+                                       Report.Error (171, loc,
+                                                     "Field `" + TypeManager.CSharpName (VariableType) +
+                                                     "." + field.Name + "' must be fully initialized " +
+                                                     "before control leaves the constructor");
+                                       return false;
+                               }
+                       }
+
+                       return true;
+               }
+
+               public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
+               {
+                       if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsVariableAssigned (this) ||
+                           (struct_info == null))
+                               return true;
+
+                       int field_idx = StructInfo [name];
+                       if (field_idx == 0)
+                               return true;
+
+                       if (!ec.CurrentBranching.IsVariableAssigned (this, field_idx)) {
+                               Report.Error (170, loc,
+                                             "Use of possibly unassigned field `" + name + "'");
+                               ec.CurrentBranching.SetVariableAssigned (this, field_idx);
+                               return false;
+                       }
+
+                       return true;
+               }
+
+               public void SetAssigned (EmitContext ec)
+               {
+                       if (ec.DoFlowAnalysis)
+                               ec.CurrentBranching.SetVariableAssigned (this);
+               }
+
+               public void SetFieldAssigned (EmitContext ec, string name)
+               {
+                       if (ec.DoFlowAnalysis && (struct_info != null))
+                               ec.CurrentBranching.SetVariableAssigned (this, StructInfo [name]);
+               }
+
+               public bool Resolve (DeclSpace decl)
+               {
+                       if (struct_info != null)
+                               return true;
+
+                       if (VariableType == null)
+                               VariableType = decl.ResolveType (Type, false, Location);
+
+                       if (VariableType == null)
+                               return false;
+
+                       struct_info = MyStructInfo.GetStructInfo (VariableType);
+
+                       return true;
+               }
+
                public void MakePinned ()
                {
                        TypeManager.MakePinned (LocalBuilder);
@@ -2082,13 +2597,10 @@ namespace Mono.CSharp {
 
                public int ID {
                        get {
-                               if (Implicit)
-                                       return Parent.ID;
-                               else
-                                       return this_id;
+                               return this_id;
                        }
                }
-               
+
                void AddChild (Block b)
                {
                        if (children == null)
@@ -2135,6 +2647,90 @@ namespace Mono.CSharp {
                        return null;
                }
 
+               VariableInfo this_variable = null;
+
+               // <summary>
+               //   Returns the "this" instance variable of this block.
+               //   See AddThisVariable() for more information.
+               // </summary>
+               public VariableInfo ThisVariable {
+                       get {
+                               if (this_variable != null)
+                                       return this_variable;
+                               else if (Parent != null)
+                                       return Parent.ThisVariable;
+                               else
+                                       return null;
+                       }
+               }
+
+               Hashtable child_variable_names;
+
+               // <summary>
+               //   Marks a variable with name @name as being used in a child block.
+               //   If a variable name has been used in a child block, it's illegal to
+               //   declare a variable with the same name in the current block.
+               // </summary>
+               public void AddChildVariableName (string name)
+               {
+                       if (child_variable_names == null)
+                               child_variable_names = new Hashtable ();
+
+                       if (!child_variable_names.Contains (name))
+                               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);
+                       }
+
+                       foreach (Block child in block.children) {
+                               if (child.Variables != null) {
+                                       foreach (string name in child.Variables.Keys)
+                                               AddChildVariableName (name);
+                               }
+                       }
+               }
+
+               // <summary>
+               //   Checks whether a variable name has already been used in a child block.
+               // </summary>
+               public bool IsVariableNameUsedInChildBlock (string name)
+               {
+                       if (child_variable_names == null)
+                               return false;
+
+                       return child_variable_names.Contains (name);
+               }
+
+               // <summary>
+               //   This is used by non-static `struct' constructors which do not have an
+               //   initializer - in this case, the constructor must initialize all of the
+               //   struct's fields.  To do this, we add a "this" variable and use the flow
+               //   analysis code to ensure that it's been fully initialized before control
+               //   leaves the constructor.
+               // </summary>
+               public VariableInfo AddThisVariable (TypeContainer tc, Location l)
+               {
+                       if (this_variable != null)
+                               return this_variable;
+
+                       this_variable = new VariableInfo (tc, ID, l);
+
+                       if (variables == null)
+                               variables = new Hashtable ();
+                       variables.Add ("this", this_variable);
+
+                       return this_variable;
+               }
+
                public VariableInfo AddVariable (Expression type, string name, Parameters pars, Location l)
                {
                        if (variables == null)
@@ -2154,6 +2750,15 @@ namespace Mono.CSharp {
                                return null;
                        }
 
+                       if (IsVariableNameUsedInChildBlock (name)) {
+                               Report.Error (136, l, "A local variable named `" + name + "' " +
+                                             "cannot be declared in this scope since it would " +
+                                             "give a different meaning to `" + name + "', which " +
+                                             "is already used in a `child' scope to denote something " +
+                                             "else");
+                               return null;
+                       }
+
                        if (pars != null) {
                                int idx = 0;
                                Parameter p = pars.GetParameterByName (name, out idx);
@@ -2167,7 +2772,7 @@ namespace Mono.CSharp {
                                }
                        }
                        
-                       vi = new VariableInfo (type, ID, l);
+                       vi = new VariableInfo (type, name, ID, l);
 
                        variables.Add (name, vi);
 
@@ -2239,24 +2844,6 @@ namespace Mono.CSharp {
                        return null;
                }
                
-               /// <summary>
-               ///   True if the variable named @name has been defined
-               ///   in this block
-               /// </summary>
-               public bool IsVariableDefined (string name)
-               {
-                       // Console.WriteLine ("Looking up {0} in {1}", name, ID);
-                       if (variables != null) {
-                               if (variables.Contains (name))
-                                       return true;
-                       }
-                       
-                       if (Parent != null)
-                               return Parent.IsVariableDefined (name);
-
-                       return false;
-               }
-
                /// <summary>
                ///   True if the variable named @name is a constant
                ///  </summary>
@@ -2329,25 +2916,15 @@ namespace Mono.CSharp {
                        count_variables = first_variable;
                        if (variables != null) {
                                foreach (VariableInfo vi in variables.Values) {
-                                       Report.Debug (2, "VARIABLE", vi);
-
-                                       Type type = ds.ResolveType (vi.Type, false, vi.Location);
-                                       if (type == null) {
+                                       if (!vi.Resolve (ds)) {
                                                vi.Number = -1;
                                                continue;
                                        }
 
-                                       vi.VariableType = type;
-
-                                       Report.Debug (2, "VARIABLE", vi, type, type.IsValueType,
-                                                     TypeManager.IsValueType (type),
-                                                     TypeManager.IsBuiltinType (type));
+                                       vi.Number = ++count_variables;
 
-                                       // FIXME: we don't have support for structs yet.
-                                       if (TypeManager.IsValueType (type) && !TypeManager.IsBuiltinType (type))
-                                               vi.Number = -1;
-                                       else
-                                               vi.Number = ++count_variables;
+                                       if (vi.StructInfo != null)
+                                               count_variables += vi.StructInfo.Count;
                                }
                        }
 
@@ -2466,6 +3043,8 @@ namespace Mono.CSharp {
                                        b.UsageWarning ();
                }
 
+               bool has_ret = false;
+
                public override bool Resolve (EmitContext ec)
                {
                        Block prev_block = ec.CurrentBlock;
@@ -2474,21 +3053,50 @@ namespace Mono.CSharp {
                        ec.CurrentBlock = this;
                        ec.StartFlowBranching (this);
 
-                       Report.Debug (1, "RESOLVE BLOCK", StartLocation);
+                       Report.Debug (1, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
 
                        if (!variables_initialized)
                                UpdateVariableInfo (ec);
 
-                       foreach (Statement s in statements){
-                               if (s.Resolve (ec) == false)
-                                       ok = false;
+                       ArrayList new_statements = new ArrayList ();
+                       bool unreachable = false, warning_shown = false;
+
+                       foreach (Statement s in statements){
+                               if (unreachable && !(s is LabeledStatement)) {
+                                       if (!warning_shown && !(s is EmptyStatement)) {
+                                               warning_shown = true;
+                                               Warning_DeadCodeFound (s.loc);
+                                       }
+
+                                       continue;
+                               }
+
+                               if (s.Resolve (ec) == false) {
+                                       ok = false;
+                                       continue;
+                               }
+
+                               if (s is LabeledStatement)
+                                       unreachable = false;
+                               else
+                                       unreachable = ! ec.CurrentBranching.IsReachable ();
+
+                               new_statements.Add (s);
                        }
 
-                       Report.Debug (1, "RESOLVE BLOCK DONE", StartLocation);
+                       statements = new_statements;
 
-                       ec.EndFlowBranching ();
+                       Report.Debug (1, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching);
+
+                       FlowReturns returns = ec.EndFlowBranching ();
                        ec.CurrentBlock = prev_block;
 
+                       // If we're a non-static `struct' constructor which doesn't have an
+                       // initializer, then we must initialize all of the struct's fields.
+                       if ((this_variable != null) && (returns != FlowReturns.EXCEPTION) &&
+                           !this_variable.IsAssigned (ec, loc))
+                               ok = false;
+
                        if ((labels != null) && (RootContext.WarningLevel >= 2)) {
                                foreach (LabeledStatement label in labels.Values)
                                        if (!label.HasBeenReferenced)
@@ -2496,47 +3104,27 @@ namespace Mono.CSharp {
                                                                "This label has not been referenced");
                        }
 
+                       if ((returns == FlowReturns.ALWAYS) ||
+                           (returns == FlowReturns.EXCEPTION) ||
+                           (returns == FlowReturns.UNREACHABLE))
+                               has_ret = true;
+
                        return ok;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
-                       bool is_ret = false, this_ret = false;
                        Block prev_block = ec.CurrentBlock;
-                       bool warning_shown = false;
 
                        ec.CurrentBlock = this;
 
-                       if (CodeGen.SymbolWriter != null) {
-                               ec.Mark (StartLocation);
-                               
-                               foreach (Statement s in statements) {
-                                       ec.Mark (s.loc);
-                                       
-                                       if (is_ret && !warning_shown && !(s is EmptyStatement)){
-                                               warning_shown = true;
-                                               Warning_DeadCodeFound (s.loc);
-                                       }
-                                       this_ret = s.Emit (ec);
-                                       if (this_ret)
-                                               is_ret = true;
-                               }
-
-                               ec.Mark (EndLocation); 
-                       } else {
-                               foreach (Statement s in statements){
-                                       if (is_ret && !warning_shown && !(s is EmptyStatement)){
-                                               warning_shown = true;
-                                               Warning_DeadCodeFound (s.loc);
-                                       }
-                                       this_ret = s.Emit (ec);
-                                       if (this_ret)
-                                               is_ret = true;
-                               }
-                       }
+                       ec.Mark (StartLocation);
+                       foreach (Statement s in statements)
+                               s.Emit (ec);
+                       ec.Mark (EndLocation); 
                        
                        ec.CurrentBlock = prev_block;
-                       return is_ret;
+                       return has_ret;
                }
        }
 
@@ -2593,7 +3181,7 @@ namespace Mono.CSharp {
 
                        if (e is StringConstant || e is NullLiteral){
                                if (required_type == TypeManager.string_type){
-                                       converted = label;
+                                       converted = e;
                                        ILLabel = ec.ig.DefineLabel ();
                                        return true;
                                }
@@ -3142,7 +3730,8 @@ namespace Mono.CSharp {
                                                fFoundDefault = true;
                                        }
                                }
-                               fAllReturn &= ss.Block.Emit (ec);
+                               bool returns = ss.Block.Emit (ec);
+                               fAllReturn &= returns;
                                //ig.Emit (OpCodes.Br, lblEnd);
                        }
                        
@@ -3190,9 +3779,6 @@ namespace Mono.CSharp {
                                ig.Emit (OpCodes.Call, TypeManager.string_isinterneted_string);
                                ig.Emit (OpCodes.Stloc, val);
                        }
-
-                       SwitchSection last_section;
-                       last_section = (SwitchSection) Sections [Sections.Count-1];
                        
                        foreach (SwitchSection ss in Sections){
                                Label sec_begin = ig.DefineLabel ();
@@ -3245,15 +3831,17 @@ namespace Mono.CSharp {
                                                }
                                        }
                                }
-                               if (label_count != 1 && ss != last_section)
+                               if (label_count != 1)
                                        ig.Emit (OpCodes.Br, next_test);
                                
                                if (null_found)
                                        ig.MarkLabel (null_target);
                                ig.MarkLabel (sec_begin);
-                               foreach (SwitchLabel sl in ss.Labels)\r
+                               foreach (SwitchLabel sl in ss.Labels)
                                        ig.MarkLabel (sl.ILLabelCode);
-                               if (ss.Block.Emit (ec))
+
+                               bool returns = ss.Block.Emit (ec);
+                               if (returns)
                                        pending_goto_end = false;
                                else {
                                        all_return = false;
@@ -3306,13 +3894,17 @@ namespace Mono.CSharp {
                                        return false;
                        }
 
+
+                       if (!got_default)
+                               ec.CurrentBranching.CreateSibling ();
+
                        ec.EndFlowBranching ();
                        ec.Switch = old_switch;
 
                        return true;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        // Store variable for comparission purposes
                        LocalBuilder value = ec.ig.DeclareLocal (SwitchType);
@@ -3369,7 +3961,7 @@ namespace Mono.CSharp {
                        return Statement.Resolve (ec) && expr != null;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        Type type = expr.Type;
                        bool val;
@@ -3423,7 +4015,7 @@ namespace Mono.CSharp {
                        return Block.Resolve (ec);
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        bool previous_state = ec.CheckState;
                        bool previous_state_const = ec.ConstantCheckState;
@@ -3461,7 +4053,7 @@ namespace Mono.CSharp {
                        return ret;
                }
 
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        bool previous_state = ec.CheckState;
                        bool previous_state_const = ec.ConstantCheckState;
@@ -3497,7 +4089,7 @@ namespace Mono.CSharp {
                        return val;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        bool previous_state = ec.InUnsafe;
                        bool val;
@@ -3647,7 +4239,7 @@ namespace Mono.CSharp {
                        return statement.Resolve (ec);
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
 
@@ -3734,11 +4326,12 @@ namespace Mono.CSharp {
                public readonly Block  Block;
                public readonly Location Location;
 
-               Expression type;
+               Expression type_expr;
+               Type type;
                
                public Catch (Expression type, string name, Block block, Location l)
                {
-                       this.type = type;
+                       type_expr = type;
                        Name = name;
                        Block = block;
                        Location = l;
@@ -3746,34 +4339,31 @@ namespace Mono.CSharp {
 
                public Type CatchType {
                        get {
-                               if (type == null)
-                                       throw new InvalidOperationException ();
-
-                               return type.Type;
+                               return type;
                        }
                }
 
                public bool IsGeneral {
                        get {
-                               return type == null;
+                               return type_expr == null;
                        }
                }
 
                public bool Resolve (EmitContext ec)
                {
-                       if (type != null) {
-                               type = type.DoResolve (ec);
+                       if (type_expr != null) {
+                               type = ec.DeclSpace.ResolveType (type_expr, false, Location);
                                if (type == null)
                                        return false;
 
-                               Type t = type.Type;
-                               if (t != TypeManager.exception_type && !t.IsSubclassOf (TypeManager.exception_type)){
+                               if (type != TypeManager.exception_type && !type.IsSubclassOf (TypeManager.exception_type)){
                                        Report.Error (155, Location,
                                                      "The type caught or thrown must be derived " +
                                                      "from System.Exception");
                                        return false;
                                }
-                       }
+                       } else
+                               type = null;
 
                        if (!Block.Resolve (ec))
                                return false;
@@ -3845,12 +4435,12 @@ namespace Mono.CSharp {
 
                                FlowBranching.UsageVector current = ec.CurrentBranching.CurrentUsageVector;
 
-                               if ((current.Returns == FlowReturns.NEVER) ||
-                                   (current.Returns == FlowReturns.SOMETIMES)) {
+                               if (!current.AlwaysReturns && !current.AlwaysBreaks)
                                        vector.AndLocals (current);
-                               }
                        }
 
+                       Report.Debug (1, "END OF CATCH BLOCKS", ec.CurrentBranching);
+
                        if (General != null){
                                ec.CurrentBranching.CreateSibling ();
                                Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching);
@@ -3865,16 +4455,16 @@ namespace Mono.CSharp {
 
                                FlowBranching.UsageVector current = ec.CurrentBranching.CurrentUsageVector;
 
-                               if ((current.Returns == FlowReturns.NEVER) ||
-                                   (current.Returns == FlowReturns.SOMETIMES)) {
+                               if (!current.AlwaysReturns && !current.AlwaysBreaks)
                                        vector.AndLocals (current);
-                               }
                        }
 
-                       ec.CurrentBranching.CreateSiblingForFinally ();
-                       Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
+                       Report.Debug (1, "END OF GENERAL CATCH BLOCKS", ec.CurrentBranching);
 
                        if (Fini != null) {
+                               ec.CurrentBranching.CreateSiblingForFinally ();
+                               Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
+
                                bool old_in_finally = ec.InFinally;
                                ec.InFinally = true;
 
@@ -3884,10 +4474,10 @@ namespace Mono.CSharp {
                                ec.InFinally = old_in_finally;
                        }
 
-                       FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
-
                        FlowReturns returns = ec.EndFlowBranching ();
 
+                       FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
+
                        Report.Debug (1, "END OF FINALLY", ec.CurrentBranching, returns, vector, f_vector);
 
                        if ((returns == FlowReturns.SOMETIMES) || (returns == FlowReturns.ALWAYS)) {
@@ -3901,7 +4491,7 @@ namespace Mono.CSharp {
                        return ok;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
                        Label end;
@@ -3977,10 +4567,6 @@ namespace Mono.CSharp {
                }
        }
 
-       //
-       // FIXME: We still do not support the expression variant of the using
-       // statement.
-       //
        public class Using : Statement {
                object expression_or_block;
                Statement Statement;
@@ -4024,7 +4610,7 @@ namespace Mono.CSharp {
                                        if (var == null)
                                                return false;
                                        
-                                       converted_vars [i] = Expression.ConvertImplicit (
+                                       converted_vars [i] = Expression.ConvertImplicitRequired (
                                                ec, var, TypeManager.idisposable_type, loc);
 
                                        if (converted_vars [i] == null)
@@ -4057,7 +4643,7 @@ namespace Mono.CSharp {
                bool ResolveExpression (EmitContext ec)
                {
                        if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
-                               conv = Expression.ConvertImplicit (
+                               conv = Expression.ConvertImplicitRequired (
                                        ec, expr, TypeManager.idisposable_type, loc);
 
                                if (conv == null)
@@ -4165,7 +4751,7 @@ namespace Mono.CSharp {
                        return Statement.Resolve (ec);
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        if (expression_or_block is DictionaryEntry)
                                return EmitLocalVariableDecls (ec);
@@ -4217,7 +4803,7 @@ namespace Mono.CSharp {
                        // out to return values in ExprClass?  I think they should.
                        //
                        if (!(expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.Value ||
-                             expr.eclass == ExprClass.PropertyAccess)){
+                             expr.eclass == ExprClass.PropertyAccess || expr.eclass == ExprClass.IndexerAccess)){
                                error1579 (expr.Type);
                                return false;
                        }
@@ -4240,6 +4826,10 @@ namespace Mono.CSharp {
                                empty = new EmptyExpression (hm.element_type);
                        }
 
+                       ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+                       ec.CurrentBranching.CreateSibling ();
+
+                       //
                        //
                        // FIXME: maybe we can apply the same trick we do in the
                        // array handling to avoid creating empty and conv in some cases.
@@ -4257,6 +4847,8 @@ namespace Mono.CSharp {
                        if (!statement.Resolve (ec))
                                return false;
 
+                       FlowReturns returns = ec.EndFlowBranching ();
+
                        return true;
                }
                
@@ -4265,13 +4857,13 @@ namespace Mono.CSharp {
                //
                static MethodInfo FetchMethodMoveNext (Type t)
                {
-                       MemberInfo [] move_next_list;
+                       MemberList move_next_list;
                        
                        move_next_list = TypeContainer.FindMembers (
                                t, MemberTypes.Method,
                                BindingFlags.Public | BindingFlags.Instance,
                                Type.FilterName, "MoveNext");
-                       if (move_next_list == null || move_next_list.Length == 0)
+                       if (move_next_list.Count == 0)
                                return null;
 
                        foreach (MemberInfo m in move_next_list){
@@ -4292,13 +4884,13 @@ namespace Mono.CSharp {
                //
                static MethodInfo FetchMethodGetCurrent (Type t)
                {
-                       MemberInfo [] move_next_list;
+                       MemberList move_next_list;
                        
                        move_next_list = TypeContainer.FindMembers (
                                t, MemberTypes.Method,
                                BindingFlags.Public | BindingFlags.Instance,
                                Type.FilterName, "get_Current");
-                       if (move_next_list == null || move_next_list.Length == 0)
+                       if (move_next_list.Count == 0)
                                return null;
 
                        foreach (MemberInfo m in move_next_list){
@@ -4439,14 +5031,14 @@ namespace Mono.CSharp {
 
                static bool TryType (Type t, ForeachHelperMethods hm)
                {
-                       MemberInfo [] mi;
+                       MemberList mi;
                        
                        mi = TypeContainer.FindMembers (t, MemberTypes.Method,
                                                        BindingFlags.Public | BindingFlags.NonPublic |
                                                        BindingFlags.Instance,
                                                        FilterEnumerator, hm);
 
-                       if (mi == null || mi.Length == 0)
+                       if (mi.Count == 0)
                                return false;
 
                        hm.get_enumerator = (MethodInfo) mi [0];
@@ -4698,7 +5290,7 @@ namespace Mono.CSharp {
                        return false;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        bool ret_val;
                        
@@ -4726,4 +5318,3 @@ namespace Mono.CSharp {
                }
        }
 }
-