Merge pull request #438 from mattleibow/master
[mono.git] / mcs / mcs / statement.cs
index ae11782edbdf2ad2a30fceb863a0784048c224ea..1742956bda77768ed2ec64df7130610f19398150 100644 (file)
@@ -49,13 +49,21 @@ namespace Mono.CSharp {
                        // in unreachable code, for instance.
                        //
 
-                       if (warn)
+                       bool unreachable = false;
+                       if (warn && !ec.UnreachableReported) {
+                               ec.UnreachableReported = true;
+                               unreachable = true;
                                ec.Report.Warning (162, 2, loc, "Unreachable code detected");
+                       }
 
                        ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
                        bool ok = Resolve (ec);
                        ec.KillFlowBranching ();
 
+                       if (unreachable) {
+                               ec.UnreachableReported = false;
+                       }
+
                        return ok;
                }
                                
@@ -281,11 +289,16 @@ namespace Mono.CSharp {
                public Expression expr;
                public Statement  EmbeddedStatement;
 
-               public Do (Statement statement, BooleanExpression bool_expr, Location l)
+               public Do (Statement statement, BooleanExpression bool_expr, Location doLocation, Location whileLocation)
                {
                        expr = bool_expr;
                        EmbeddedStatement = statement;
-                       loc = l;
+                       loc = doLocation;
+                       WhileLocation = whileLocation;
+               }
+
+               public Location WhileLocation {
+                       get; private set;
                }
 
                public override bool Resolve (BlockContext ec)
@@ -332,7 +345,7 @@ namespace Mono.CSharp {
                        ec.MarkLabel (ec.LoopBegin);
 
                        // Mark start of while condition
-                       ec.Mark (expr.Location);
+                       ec.Mark (WhileLocation);
 
                        //
                        // Dead code elimination
@@ -461,7 +474,7 @@ namespace Mono.CSharp {
                        
                                ec.MarkLabel (ec.LoopBegin);
 
-                               ec.Mark (expr.Location);
+                               ec.Mark (loc);
                                expr.EmitBranchable (ec, while_loop, true);
                                
                                ec.MarkLabel (ec.LoopEnd);
@@ -878,7 +891,6 @@ namespace Mono.CSharp {
                                                        return true;
                                                }
 
-                                               // TODO: Better error message
                                                if (async_type.Kind == MemberKind.Void) {
                                                        ec.Report.Error (127, loc,
                                                                "`{0}': A return keyword must not be followed by any expression when method returns void",
@@ -909,6 +921,15 @@ namespace Mono.CSharp {
                                                }
                                        }
                                } else {
+                                       // Same error code as .NET but better error message
+                                       if (block_return_type.Kind == MemberKind.Void) {
+                                               ec.Report.Error (127, loc,
+                                                       "`{0}': A return keyword must not be followed by any expression when delegate returns void",
+                                                       am.GetSignatureForError ());
+
+                                               return false;
+                                       }
+
                                        var l = am as AnonymousMethodBody;
                                        if (l != null && l.ReturnTypeInference != null && expr != null) {
                                                l.ReturnTypeInference.AddCommonTypeBound (expr.Type);
@@ -1212,7 +1233,7 @@ namespace Mono.CSharp {
                                res = c;
                        } else {
                                TypeSpec type = ec.Switch.SwitchType;
-                               res = c.TryReduce (ec, type);
+                               res = c.Reduce (ec, type);
                                if (res == null) {
                                        c.Error_ValueCannotBeConverted (ec, type, true);
                                        return false;
@@ -1620,8 +1641,10 @@ namespace Mono.CSharp {
                        if (declarators != null) {
                                foreach (var d in declarators) {
                                        d.Variable.CreateBuilder (ec);
-                                       if (d.Initializer != null)
+                                       if (d.Initializer != null) {
+                                               ec.Mark (d.Variable.Location);
                                                ((ExpressionStatement) d.Initializer).EmitStatement (ec);
+                                       }
                                }
                        }
                }
@@ -2058,9 +2081,7 @@ namespace Mono.CSharp {
 #endif
 
 //             int assignable_slots;
-               bool unreachable_shown;
-               bool unreachable;
-               
+
                public Block (Block parent, Location start, Location end)
                        : this (parent, 0, start, end)
                {
@@ -2232,6 +2253,8 @@ namespace Mono.CSharp {
 
                        Block prev_block = ec.CurrentBlock;
                        bool ok = true;
+                       bool unreachable = ec.IsUnreachable;
+                       bool prev_unreachable = unreachable;
 
                        ec.CurrentBlock = this;
                        ec.StartFlowBranching (this);
@@ -2264,14 +2287,10 @@ namespace Mono.CSharp {
                                        if (s is EmptyStatement)
                                                continue;
 
-                                       if (!unreachable_shown && !(s is LabeledStatement)) {
+                                       if (!ec.UnreachableReported && !(s is LabeledStatement)) {
                                                ec.Report.Warning (162, 2, s.loc, "Unreachable code detected");
-                                               unreachable_shown = true;
+                                               ec.UnreachableReported = true;
                                        }
-
-                                       Block c_block = s as Block;
-                                       if (c_block != null)
-                                               c_block.unreachable = c_block.unreachable_shown = true;
                                }
 
                                //
@@ -2295,8 +2314,15 @@ namespace Mono.CSharp {
                                        statements [ix] = new EmptyStatement (s.loc);
 
                                unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
-                               if (unreachable && s is LabeledStatement)
-                                       throw new InternalErrorException ("should not happen");
+                               if (unreachable) {
+                                       ec.IsUnreachable = true;
+                               } else if (ec.IsUnreachable)
+                                       ec.IsUnreachable = false;
+                       }
+
+                       if (unreachable != prev_unreachable) {
+                               ec.IsUnreachable = prev_unreachable;
+                               ec.UnreachableReported = false;
                        }
 
                        while (ec.CurrentBranching is FlowBranchingLabeled)
@@ -2320,17 +2346,21 @@ namespace Mono.CSharp {
 
                public override bool ResolveUnreachable (BlockContext ec, bool warn)
                {
-                       unreachable_shown = true;
-                       unreachable = true;
-
-                       if (warn)
+                       bool unreachable = false;
+                       if (warn && !ec.UnreachableReported) {
+                               ec.UnreachableReported = true;
+                               unreachable = true;
                                ec.Report.Warning (162, 2, loc, "Unreachable code detected");
+                       }
 
                        var fb = ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
                        fb.CurrentUsageVector.IsUnreachable = true;
                        bool ok = Resolve (ec);
                        ec.KillFlowBranching ();
 
+                       if (unreachable)
+                               ec.UnreachableReported = false;
+
                        return ok;
                }
                
@@ -2519,10 +2549,17 @@ namespace Mono.CSharp {
                                // Only first storey in path will hold this reference. All children blocks will
                                // reference it indirectly using $ref field
                                //
-                               for (Block b = Original.Explicit.Parent; b != null; b = b.Parent) {
-                                       var s = b.Explicit.AnonymousMethodStorey;
-                                       if (s != null) {
-                                               storey.HoistedThis = s.HoistedThis;
+                               for (Block b = Original.Explicit; b != null; b = b.Parent) {
+                                       if (b.Parent != null) {
+                                               var s = b.Parent.Explicit.AnonymousMethodStorey;
+                                               if (s != null) {
+                                                       storey.HoistedThis = s.HoistedThis;
+                                                       break;
+                                               }
+                                       }
+
+                                       if (b.Explicit == b.Explicit.ParametersBlock && b.Explicit.ParametersBlock.StateMachine != null) {
+                                               storey.HoistedThis = b.Explicit.ParametersBlock.StateMachine.HoistedThis;
                                                break;
                                        }
                                }
@@ -2820,7 +2857,7 @@ namespace Mono.CSharp {
                        // Overwrite original for comparison purposes when linking cross references
                        // between anonymous methods
                        //
-                       Original = source;
+                       Original = source.Original;
                }
 
                #region Properties
@@ -4236,10 +4273,10 @@ namespace Mono.CSharp {
 
                                Expression cond = null;
                                for (int ci = 0; ci < s.Labels.Count; ++ci) {
-                                       var e = new Binary (Binary.Operator.Equality, value, s.Labels[ci].Converted, loc);
+                                       var e = new Binary (Binary.Operator.Equality, value, s.Labels[ci].Converted);
 
                                        if (ci > 0) {
-                                               cond = new Binary (Binary.Operator.LogicalOr, cond, e, loc);
+                                               cond = new Binary (Binary.Operator.LogicalOr, cond, e);
                                        } else {
                                                cond = e;
                                        }
@@ -4529,6 +4566,12 @@ namespace Mono.CSharp {
                        ec.MarkLabel (start_finally);
 
                        if (finally_host != null) {
+                               finally_host.Define ();
+                               finally_host.Emit ();
+
+                               // Now it's safe to add, to close it properly and emit sequence points
+                               finally_host.Parent.AddMember (finally_host);
+
                                var ce = new CallEmitter ();
                                ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
                                ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0));
@@ -4743,21 +4786,9 @@ namespace Mono.CSharp {
                                locked = false;
                        }
 
-                       using (ec.Set (ResolveContext.Options.LockScope)) {
-                               ec.StartFlowBranching (this);
-                               Statement.Resolve (ec);
-                               ec.EndFlowBranching ();
-                       }
-
-                       if (lv != null) {
-                               lv.IsLockedByStatement = locked;
-                       }
-
-                       base.Resolve (ec);
-
                        //
                        // Have to keep original lock value around to unlock same location
-                       // in the case the original has changed or is null
+                       // in the case of original value has changed or is null
                        //
                        expr_copy = TemporaryVariableReference.Create (ec.BuiltinTypes.Object, ec.CurrentBlock, loc);
                        expr_copy.Resolve (ec);
@@ -4770,6 +4801,18 @@ namespace Mono.CSharp {
                                lock_taken.Resolve (ec);
                        }
 
+                       using (ec.Set (ResolveContext.Options.LockScope)) {
+                               ec.StartFlowBranching (this);
+                               Statement.Resolve (ec);
+                               ec.EndFlowBranching ();
+                       }
+
+                       if (lv != null) {
+                               lv.IsLockedByStatement = locked;
+                       }
+
+                       base.Resolve (ec);
+
                        return true;
                }
                
@@ -5123,8 +5166,8 @@ namespace Mono.CSharp {
                                        // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
                                        //
                                        converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr,
-                                               new Binary (Binary.Operator.Equality, initializer, new NullLiteral (loc), loc),
-                                               new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc), loc), loc)),
+                                               new Binary (Binary.Operator.Equality, initializer, new NullLiteral (loc)),
+                                               new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc)))),
                                                        new NullLiteral (loc),
                                                        converted, loc);
 
@@ -5682,7 +5725,7 @@ namespace Mono.CSharp {
 
                                // Add conditional call when disposing possible null variable
                                if (!type.IsStruct || type.IsNullableType)
-                                       dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc), loc), dispose, dispose.loc);
+                                       dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc)), dispose, dispose.loc);
 
                                return dispose;
                        }
@@ -5696,7 +5739,7 @@ namespace Mono.CSharp {
                        {
                                for (int i = declarators.Count - 1; i >= 0; --i) {
                                        var d = declarators [i];
-                                       var vd = new VariableDeclaration (d.Variable, type_expr.Location);
+                                       var vd = new VariableDeclaration (d.Variable, d.Variable.Location);
                                        vd.Initializer = d.Initializer;
                                        vd.IsNested = true;
                                        vd.dispose_call = CreateDisposeCall (bc, d.Variable);
@@ -5932,7 +5975,7 @@ namespace Mono.CSharp {
                                if (variable_ref == null)
                                        return false;
 
-                               for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, access, Location.Null), for_each.variable.Location));
+                               for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, access, Location.Null), for_each.type.Location));
 
                                bool ok = true;
 
@@ -6028,7 +6071,7 @@ namespace Mono.CSharp {
                                        var idisaposable_test = new Binary (Binary.Operator.Inequality, new CompilerAssign (
                                                dispose_variable.CreateReferenceExpression (bc, loc),
                                                new As (lv.CreateReferenceExpression (bc, loc), new TypeExpression (dispose_variable.Type, loc), loc),
-                                               loc), new NullLiteral (loc), loc);
+                                               loc), new NullLiteral (loc));
 
                                        var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
 
@@ -6243,7 +6286,7 @@ namespace Mono.CSharp {
                                if (variable_ref == null)
                                        return false;
 
-                               for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, current_pe, Location.Null), variable.Location));
+                               for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, current_pe, Location.Null), for_each.type.Location));
 
                                var init = new Invocation (get_enumerator_mg, null);