Merge pull request #820 from brendanzagaeski/master
[mono.git] / mcs / mcs / async.cs
index 7742126beda0353d680e283e1c258d2b7f58a024..262519893c48d19764dfc2f8710b07f94b50ecb4 100644 (file)
@@ -65,8 +65,19 @@ namespace Mono.CSharp
                        return true;
                }
 
+               public override void FlowAnalysis (FlowAnalysisContext fc)
+               {
+                       stmt.Expr.FlowAnalysis (fc);
+
+                       stmt.RegisterResumePoint ();
+               }
+
                protected override Expression DoResolve (ResolveContext rc)
                {
+                       if (rc.HasSet (ResolveContext.Options.FinallyScope)) {
+                               rc.Report.Error (1984, loc,  "The `await' operator cannot be used in the body of a finally clause");
+                       }
+
                        if (rc.HasSet (ResolveContext.Options.LockScope)) {
                                rc.Report.Error (1996, loc,
                                        "The `await' operator cannot be used in the body of a lock statement");
@@ -115,6 +126,12 @@ namespace Mono.CSharp
                        stmt.EmitStatement (ec);
                }
 
+               public override void MarkReachable (Reachability rc)
+               {
+                       base.MarkReachable (rc);
+                       stmt.MarkReachable (rc);
+               }
+
                public override object Accept (StructuralVisitor visitor)
                {
                        return visitor.Visit (this);
@@ -175,6 +192,7 @@ namespace Mono.CSharp
                public AwaitStatement (Expression expr, Location loc)
                        : base (expr, loc)
                {
+                       unwind_protect = true;
                }
 
                #region Properties
@@ -195,7 +213,9 @@ namespace Mono.CSharp
 
                protected override void DoEmit (EmitContext ec)
                {
-                       GetResultExpression (ec).Emit (ec);
+                       using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
+                               GetResultExpression (ec).Emit (ec);
+                       }
                }
 
                public Expression GetResultExpression (EmitContext ec)
@@ -219,39 +239,39 @@ namespace Mono.CSharp
 
                public void EmitPrologue (EmitContext ec)
                {
-                       awaiter = ((AsyncTaskStorey) machine_initializer.Storey).AddAwaiter (expr.Type, loc);
+                       awaiter = ((AsyncTaskStorey) machine_initializer.Storey).AddAwaiter (expr.Type);
 
                        var fe_awaiter = new FieldExpr (awaiter, loc);
                        fe_awaiter.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
 
-                       //
-                       // awaiter = expr.GetAwaiter ();
-                       //
+                               Label skip_continuation = ec.DefineLabel ();
+
                        using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
+                               //
+                               // awaiter = expr.GetAwaiter ();
+                               //
                                fe_awaiter.EmitAssign (ec, expr, false, false);
-                       }
 
-                       Label skip_continuation = ec.DefineLabel ();
+                               Expression completed_expr;
+                               if (IsDynamic) {
+                                       var rc = new ResolveContext (ec.MemberContext);
 
-                       Expression completed_expr;
-                       if (IsDynamic) {
-                               var rc = new ResolveContext (ec.MemberContext);
+                                       Arguments dargs = new Arguments (1);
+                                       dargs.Add (new Argument (fe_awaiter));
+                                       completed_expr = new DynamicMemberBinder ("IsCompleted", dargs, loc).Resolve (rc);
 
-                               Arguments dargs = new Arguments (1);
-                               dargs.Add (new Argument (fe_awaiter));
-                               completed_expr = new DynamicMemberBinder ("IsCompleted", dargs, loc).Resolve (rc);
+                                       dargs = new Arguments (1);
+                                       dargs.Add (new Argument (completed_expr));
+                                       completed_expr = new DynamicConversion (ec.Module.Compiler.BuiltinTypes.Bool, 0, dargs, loc).Resolve (rc);
+                               } else {
+                                       var pe = PropertyExpr.CreatePredefined (awaiter_definition.IsCompleted, loc);
+                                       pe.InstanceExpression = fe_awaiter;
+                                       completed_expr = pe;
+                               }
 
-                               dargs = new Arguments (1);
-                               dargs.Add (new Argument (completed_expr));
-                               completed_expr = new DynamicConversion (ec.Module.Compiler.BuiltinTypes.Bool, 0, dargs, loc).Resolve (rc);
-                       } else {
-                               var pe = PropertyExpr.CreatePredefined (awaiter_definition.IsCompleted, loc);
-                               pe.InstanceExpression = fe_awaiter;
-                               completed_expr = pe;
+                               completed_expr.EmitBranchable (ec, skip_continuation, true);
                        }
 
-                       completed_expr.EmitBranchable (ec, skip_continuation, true);
-
                        base.DoEmit (ec);
 
                        //
@@ -304,6 +324,10 @@ namespace Mono.CSharp
                                return false;
                        }
 
+                       if (bc.HasSet (ResolveContext.Options.CatchScope)) {
+                               bc.Report.Error (1985, loc, "The `await' operator cannot be used in the body of a catch clause");
+                       }
+
                        if (!base.Resolve (bc))
                                return false;
 
@@ -361,6 +385,47 @@ namespace Mono.CSharp
                }
        }
 
+       class AsyncInitializerStatement : StatementExpression
+       {
+               public AsyncInitializerStatement (AsyncInitializer expr)
+                       : base (expr)
+               {
+               }
+
+               protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
+               {
+                       base.DoFlowAnalysis (fc);
+
+                       var init = (AsyncInitializer) Expr;
+                       var res = !init.Block.HasReachableClosingBrace;
+                       var storey = (AsyncTaskStorey) init.Storey;
+
+                       if (storey.ReturnType.IsGenericTask)
+                               return res;
+
+                       return true;
+               }
+
+               public override Reachability MarkReachable (Reachability rc)
+               {
+                       if (!rc.IsUnreachable)
+                               reachable = true;
+
+                       var init = (AsyncInitializer) Expr;
+                       rc = init.Block.MarkReachable (rc);
+
+                       var storey = (AsyncTaskStorey) init.Storey;
+
+                       //
+                       // Explicit return is required for Task<T> state machine
+                       //
+                       if (storey.ReturnType != null && storey.ReturnType.IsGenericTask)
+                               return rc;
+
+                   return Reachability.CreateUnreachable ();
+               }
+       }
+
        public class AsyncInitializer : StateMachineInitializer
        {
                TypeInferenceContext return_inference;
@@ -378,6 +443,10 @@ namespace Mono.CSharp
                        }
                }
 
+               public TypeSpec DelegateType {
+                       get; set;
+               }
+
                public override bool IsIterator {
                        get {
                                return false;
@@ -392,20 +461,16 @@ namespace Mono.CSharp
 
                #endregion
 
-               protected override BlockContext CreateBlockContext (ResolveContext rc)
+               protected override BlockContext CreateBlockContext (BlockContext bc)
                {
-                       var ctx = base.CreateBlockContext (rc);
-                       var lambda = rc.CurrentAnonymousMethod as LambdaMethod;
+                       var ctx = base.CreateBlockContext (bc);
+                       var lambda = bc.CurrentAnonymousMethod as LambdaMethod;
                        if (lambda != null)
                                return_inference = lambda.ReturnTypeInference;
 
-                       ctx.StartFlowBranching (this, rc.CurrentBranching);
-                       return ctx;
-               }
+                       ctx.Set (ResolveContext.Options.TryScope);
 
-               public override Expression CreateExpressionTree (ResolveContext ec)
-               {
-                       return base.CreateExpressionTree (ec);
+                       return ctx;
                }
 
                public override void Emit (EmitContext ec)
@@ -425,6 +490,13 @@ namespace Mono.CSharp
                        storey.EmitInitializer (ec);
                        ec.Emit (OpCodes.Ret);
                }
+
+               public override void MarkReachable (Reachability rc)
+               {
+                       //
+                       // Reachability has been done in AsyncInitializerStatement
+                       //
+               }
        }
 
        class AsyncTaskStorey : StateMachine
@@ -477,12 +549,12 @@ namespace Mono.CSharp
 
                #endregion
 
-               public Field AddAwaiter (TypeSpec type, Location loc)
+               public Field AddAwaiter (TypeSpec type)
                {
                        if (mutator != null)
                                type = mutator.Mutate (type);
 
-                       List<Field> existing_fields = null;
+                       List<Field> existing_fields;
                        if (awaiter_fields.TryGetValue (type, out existing_fields)) {
                                foreach (var f in existing_fields) {
                                        if (f.IsAvailableForReuse) {
@@ -737,7 +809,9 @@ namespace Mono.CSharp
                        var args = new Arguments (2);
                        args.Add (new Argument (awaiter, Argument.AType.Ref));
                        args.Add (new Argument (new CompilerGeneratedThis (CurrentType, Location), Argument.AType.Ref));
-                       mg.EmitCall (ec, args);
+                       using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
+                               mg.EmitCall (ec, args);
+                       }
                }
 
                public void EmitInitializer (EmitContext ec)
@@ -813,7 +887,9 @@ namespace Mono.CSharp
                        Arguments args = new Arguments (1);
                        args.Add (new Argument (exceptionVariable));
 
-                       mg.EmitCall (ec, args);
+                       using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
+                               mg.EmitCall (ec, args);
+                       }
                }
 
                public void EmitSetResult (EmitContext ec)
@@ -835,7 +911,9 @@ namespace Mono.CSharp
                                args.Add (new Argument (new LocalVariableReference (hoisted_return, Location)));
                        }
 
-                       mg.EmitCall (ec, args);
+                       using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
+                               mg.EmitCall (ec, args);
+                       }
                }
 
                protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class)
@@ -852,29 +930,44 @@ namespace Mono.CSharp
                }
        }
 
-       class StackFieldExpr : FieldExpr, IExpressionCleanup
+       public class StackFieldExpr : FieldExpr, IExpressionCleanup
        {
                public StackFieldExpr (Field field)
                        : base (field, Location.Null)
                {
                }
 
+               public bool IsAvailableForReuse {
+                       get {
+                               var field = (Field) spec.MemberDefinition;
+                               return field.IsAvailableForReuse;
+                       }
+                       set {
+                               var field = (Field) spec.MemberDefinition;
+                               field.IsAvailableForReuse = value;
+                       }
+               }
+
                public override void AddressOf (EmitContext ec, AddressOp mode)
                {
                        base.AddressOf (ec, mode);
 
                        if (mode == AddressOp.Load) {
-                               var field = (Field) spec.MemberDefinition;
-                               field.IsAvailableForReuse = true;
+                               IsAvailableForReuse = true;
                        }
                }
 
                public override void Emit (EmitContext ec)
+               {
+                       EmitWithCleanup (ec, true);
+               }
+
+               public void EmitWithCleanup (EmitContext ec, bool release)
                {
                        base.Emit (ec);
 
-                       var field = (Field) spec.MemberDefinition;
-                       field.IsAvailableForReuse = true;
+                       if (release)
+                               IsAvailableForReuse = true;
 
                        //
                        // Release any captured reference type stack variables