Improved DateTime parsing of years.
[mono.git] / mcs / mcs / async.cs
index daa0073136204c4679d02a28290e89e11654c31b..6ffa92aa06a3f9cda8df1e97a0cbf67eaa719206 100644 (file)
@@ -65,6 +65,13 @@ 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.LockScope)) {
@@ -115,6 +122,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 +188,7 @@ namespace Mono.CSharp
                public AwaitStatement (Expression expr, Location loc)
                        : base (expr, loc)
                {
+                       unwind_protect = true;
                }
 
                #region Properties
@@ -226,7 +240,7 @@ namespace Mono.CSharp
                        var fe_awaiter = new FieldExpr (awaiter, loc);
                        fe_awaiter.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
 
-                               Label skip_continuation = ec.DefineLabel ();
+                       Label skip_continuation = ec.DefineLabel ();
 
                        using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
                                //
@@ -363,6 +377,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;
@@ -384,6 +439,10 @@ namespace Mono.CSharp
                        get; set;
                }
 
+               public StackFieldExpr HoistedReturnState {
+                       get; set;
+               }
+
                public override bool IsIterator {
                        get {
                                return false;
@@ -398,14 +457,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;
-                       if (lambda != null)
-                               return_inference = lambda.ReturnTypeInference;
+                       var ctx = base.CreateBlockContext (bc);
+                       var am = bc.CurrentAnonymousMethod as AnonymousMethodBody;
+                       if (am != null)
+                               return_inference = am.ReturnTypeInference;
+
+                       ctx.Set (ResolveContext.Options.TryScope);
 
-                       ctx.StartFlowBranching (this, rc.CurrentBranching);
                        return ctx;
                }
 
@@ -414,6 +474,24 @@ namespace Mono.CSharp
                        throw new NotImplementedException ();
                }
 
+               public void EmitCatchBlock (EmitContext ec)
+               {
+                       var catch_value = LocalVariable.CreateCompilerGenerated (ec.Module.Compiler.BuiltinTypes.Exception, block, Location);
+
+                       ec.BeginCatchBlock (catch_value.Type);
+                       catch_value.EmitAssign (ec);
+
+                       ec.EmitThis ();
+                       ec.EmitInt ((int) IteratorStorey.State.After);
+                       ec.Emit (OpCodes.Stfld, storey.PC.Spec);
+
+                       ((AsyncTaskStorey) Storey).EmitSetException (ec, new LocalVariableReference (catch_value, Location));
+
+                       ec.Emit (OpCodes.Leave, move_next_ok);
+                       ec.EndExceptionBlock ();
+
+               }
+
                protected override void EmitMoveNextEpilogue (EmitContext ec)
                {
                        var storey = (AsyncTaskStorey) Storey;
@@ -426,6 +504,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
@@ -438,7 +523,6 @@ namespace Mono.CSharp
                MethodSpec builder_factory;
                MethodSpec builder_start;
                PropertySpec task;
-               LocalVariable hoisted_return;
                int locals_captured;
                Dictionary<TypeSpec, List<Field>> stack_fields;
                Dictionary<TypeSpec, List<Field>> awaiter_fields;
@@ -452,11 +536,7 @@ namespace Mono.CSharp
 
                #region Properties
 
-               public LocalVariable HoistedReturn {
-                       get {
-                               return hoisted_return;
-                       }
-               }
+               public Expression HoistedReturnValue { get; set; }
 
                public TypeSpec ReturnType {
                        get {
@@ -505,7 +585,7 @@ namespace Mono.CSharp
                        return field;
                }
 
-               public Field AddCapturedLocalVariable (TypeSpec type)
+               public Field AddCapturedLocalVariable (TypeSpec type, bool requiresUninitialized = false)
                {
                        if (mutator != null)
                                type = mutator.Mutate (type);
@@ -513,7 +593,7 @@ namespace Mono.CSharp
                        List<Field> existing_fields = null;
                        if (stack_fields == null) {
                                stack_fields = new Dictionary<TypeSpec, List<Field>> ();
-                       } else if (stack_fields.TryGetValue (type, out existing_fields)) {
+                       } else if (stack_fields.TryGetValue (type, out existing_fields) && !requiresUninitialized) {
                                foreach (var f in existing_fields) {
                                        if (f.IsAvailableForReuse) {
                                                f.IsAvailableForReuse = false;
@@ -646,7 +726,7 @@ namespace Mono.CSharp
                        set_state_machine.Block.AddStatement (new StatementExpression (new Invocation (mg, args)));
 
                        if (has_task_return_type) {
-                               hoisted_return = LocalVariable.CreateCompilerGenerated (bt.TypeArguments[0], StateMachineMethod.Block, Location);
+                               HoistedReturnValue = TemporaryVariableReference.Create (bt.TypeArguments [0], StateMachineMethod.Block, Location);
                        }
 
                        return true;
@@ -739,7 +819,7 @@ namespace Mono.CSharp
                        args.Add (new Argument (awaiter, Argument.AType.Ref));
                        args.Add (new Argument (new CompilerGeneratedThis (CurrentType, Location), Argument.AType.Ref));
                        using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
-                               mg.EmitCall (ec, args);
+                               mg.EmitCall (ec, args, true);
                        }
                }
 
@@ -817,7 +897,7 @@ namespace Mono.CSharp
                        args.Add (new Argument (exceptionVariable));
 
                        using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
-                               mg.EmitCall (ec, args);
+                               mg.EmitCall (ec, args, true);
                        }
                }
 
@@ -833,15 +913,15 @@ namespace Mono.CSharp
                        };
 
                        Arguments args;
-                       if (hoisted_return == null) {
+                       if (HoistedReturnValue == null) {
                                args = new Arguments (0);
                        } else {
                                args = new Arguments (1);
-                               args.Add (new Argument (new LocalVariableReference (hoisted_return, Location)));
+                               args.Add (new Argument (HoistedReturnValue));
                        }
 
                        using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
-                               mg.EmitCall (ec, args);
+                               mg.EmitCall (ec, args, true);
                        }
                }
 
@@ -859,20 +939,30 @@ 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;
                        }
                }
 
@@ -880,8 +970,17 @@ namespace Mono.CSharp
                {
                        base.Emit (ec);
 
-                       var field = (Field) spec.MemberDefinition;
-                       field.IsAvailableForReuse = true;
+                       PrepareCleanup (ec);
+               }
+
+               public void EmitLoad (EmitContext ec)
+               {
+                       base.Emit (ec);
+               }
+
+               public void PrepareCleanup (EmitContext ec)
+               {
+                       IsAvailableForReuse = true;
 
                        //
                        // Release any captured reference type stack variables