Merge pull request #820 from brendanzagaeski/master
[mono.git] / mcs / mcs / async.cs
index daa0073136204c4679d02a28290e89e11654c31b..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
@@ -306,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;
 
@@ -363,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;
@@ -398,14 +461,15 @@ 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);
+                       ctx.Set (ResolveContext.Options.TryScope);
+
                        return ctx;
                }
 
@@ -426,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
@@ -859,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