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");
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);
public AwaitStatement (Expression expr, Location loc)
: base (expr, loc)
{
+ unwind_protect = true;
}
#region Properties
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;
}
}
+ 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;
#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;
}
storey.EmitInitializer (ec);
ec.Emit (OpCodes.Ret);
}
+
+ public override void MarkReachable (Reachability rc)
+ {
+ //
+ // Reachability has been done in AsyncInitializerStatement
+ //
+ }
}
class AsyncTaskStorey : StateMachine
}
}
- 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