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;
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);
}
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 ());
}
}
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)) {
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;
#region Properties
+ public bool HasAwaitInsideFinally { get; set; }
+
public Expression HoistedReturnValue { get; set; }
public TypeSpec ReturnType {
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"),
set_state_machine.Block.AddStatement (new StatementExpression (new Invocation (mg, args)));
if (has_task_return_type) {
- HoistedReturnValue = TemporaryVariableReference.Create (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;
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);
}
}
args.Add (new Argument (exceptionVariable));
using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
- mg.EmitCall (ec, args);
+ mg.EmitCall (ec, args, true);
}
}
}
using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
- mg.EmitCall (ec, args);
+ mg.EmitCall (ec, args, true);
}
}