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)) {
get; set;
}
+ public StackFieldExpr HoistedReturnState {
+ get; set;
+ }
+
public override bool IsIterator {
get {
return false;
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;
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;
#region Properties
- public LocalVariable HoistedReturn {
- get {
- return hoisted_return;
- }
- }
+ public bool HasAwaitInsideFinally { get; set; }
+
+ public Expression HoistedReturnValue { get; set; }
public TypeSpec ReturnType {
get {
return field;
}
- public Field AddCapturedLocalVariable (TypeSpec type)
+ public Field AddCapturedLocalVariable (TypeSpec type, bool requiresUninitialized = false)
{
if (mutator != null)
type = mutator.Mutate (type);
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;
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) {
- 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;
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);
}
}
};
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);
}
}