X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fasync.cs;h=b3efae3241024e39237558fbf7b0634d32f8a761;hb=29556e2cd8ca7bbf45a5e8e642dd1ba0c1836bb4;hp=5d8f65053bf7f2010a2d56ee3e555f3900e39474;hpb=8f53ba7970cd38449d5bb86801559d4e62b14510;p=mono.git diff --git a/mcs/mcs/async.cs b/mcs/mcs/async.cs index 5d8f65053bf..b3efae32410 100644 --- a/mcs/mcs/async.cs +++ b/mcs/mcs/async.cs @@ -90,6 +90,11 @@ namespace Mono.CSharp if (!stmt.Resolve (bc)) return null; + if (rc.HasSet (ResolveContext.Options.FinallyScope) && rc.CurrentAnonymousMethod != null) { + var ats = (AsyncTaskStorey)rc.CurrentAnonymousMethod.Storey; + ats.HasAwaitInsideFinally = true; + } + type = stmt.ResultType; eclass = ExprClass.Variable; return this; @@ -145,7 +150,7 @@ namespace Mono.CSharp public bool ProbingMode { get; set; } - protected override void Error_TypeDoesNotContainDefinition (ResolveContext rc, TypeSpec type, string name) + public override void Error_TypeDoesNotContainDefinition (ResolveContext rc, TypeSpec type, string name) { Error_OperatorCannotBeApplied (rc, type); } @@ -159,7 +164,7 @@ namespace Mono.CSharp if (invocation != null && invocation.MethodGroup != null && (invocation.MethodGroup.BestCandidate.Modifiers & Modifiers.ASYNC) != 0) { rc.Report.Error (4008, loc, "Cannot await void method `{0}'. Consider changing method return type to `Task'", invocation.GetSignatureForError ()); - } else { + } else if (type != InternalType.ErrorType) { rc.Report.Error (4001, loc, "Cannot await `{0}' expression", type.GetSignatureForError ()); } } @@ -344,7 +349,11 @@ namespace Mono.CSharp var errors_printer = new SessionReportPrinter (); var old = bc.Report.SetPrinter (errors_printer); - ama = new Invocation (ama, args).Resolve (bc); + + // + // The expression await t is classified the same way as the expression (t).GetAwaiter().GetResult(). + // + ama = new Invocation (new ParenthesizedExpression (ama, Location.Null), args).Resolve (bc); bc.Report.SetPrinter (old); if (errors_printer.ErrorsCount > 0 || !MemberAccess.IsValidDotExpression (ama.Type)) { @@ -439,6 +448,10 @@ namespace Mono.CSharp get; set; } + public StackFieldExpr HoistedReturnState { + get; set; + } + public override bool IsIterator { get { return false; @@ -470,6 +483,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; @@ -501,7 +532,6 @@ namespace Mono.CSharp MethodSpec builder_factory; MethodSpec builder_start; PropertySpec task; - LocalVariable hoisted_return; int locals_captured; Dictionary> stack_fields; Dictionary> awaiter_fields; @@ -515,11 +545,9 @@ namespace Mono.CSharp #region Properties - public LocalVariable HoistedReturn { - get { - return hoisted_return; - } - } + public bool HasAwaitInsideFinally { get; set; } + + public Expression HoistedReturnValue { get; set; } public TypeSpec ReturnType { get { @@ -568,7 +596,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); @@ -576,7 +604,7 @@ namespace Mono.CSharp List existing_fields = null; if (stack_fields == null) { stack_fields = new Dictionary> (); - } 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; @@ -672,6 +700,18 @@ namespace Mono.CSharp builder = AddCompilerGeneratedField ("$builder", new TypeExpression (bt, Location)); + Field rfield; + if (has_task_return_type && HasAwaitInsideFinally) { + // + // Special case async block with return value from finally clause. In such case + // we rewrite all return expresison stores to stfld to $return. Instead of treating + // returns outside of finally and inside of finally differently. + // + rfield = AddCompilerGeneratedField ("$return", new TypeExpression (bt.TypeArguments [0], Location)); + } else { + rfield = null; + } + var set_state_machine = new Method (this, new TypeExpression (Compiler.BuiltinTypes.Void, Location), Modifiers.COMPILER_GENERATED | Modifiers.DEBUGGER_HIDDEN | Modifiers.PUBLIC, new MemberName ("SetStateMachine"), @@ -709,7 +749,13 @@ 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); + if (rfield != null) { + HoistedReturnValue = new FieldExpr (rfield, Location) { + InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null) + }; + } else { + HoistedReturnValue = TemporaryVariableReference.Create (bt.TypeArguments [0], StateMachineMethod.Block, Location); + } } return true; @@ -802,7 +848,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); } } @@ -880,7 +926,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); } } @@ -896,15 +942,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); } }