Make some mcs methods static
[mono.git] / mcs / mcs / async.cs
1 //
2 // async.cs: Asynchronous functions
3 //
4 // Author:
5 //   Marek Safar (marek.safar@gmail.com)
6 //
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
8 //
9 // Copyright 2011 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
11 //
12
13 using System;
14 using System.Collections.Generic;
15 using System.Linq;
16 using System.Collections;
17
18 #if STATIC
19 using IKVM.Reflection.Emit;
20 #else
21 using System.Reflection.Emit;
22 #endif
23
24 namespace Mono.CSharp
25 {
26         public class Await : ExpressionStatement
27         {
28                 Expression expr;
29                 AwaitStatement stmt;
30
31                 public Await (Expression expr, Location loc)
32                 {
33                         this.expr = expr;
34                         this.loc = loc;
35                 }
36
37                 public Expression Expr {
38                         get {
39                                 return expr;
40                         }
41                 }
42
43                 protected override void CloneTo (CloneContext clonectx, Expression target)
44                 {
45                         var t = (Await) target;
46
47                         t.expr = expr.Clone (clonectx);
48                 }
49
50                 public override Expression CreateExpressionTree (ResolveContext ec)
51                 {
52                         throw new NotImplementedException ("ET");
53                 }
54
55                 public override bool ContainsEmitWithAwait ()
56                 {
57                         return true;
58                 }
59
60                 protected override Expression DoResolve (ResolveContext rc)
61                 {
62                         if (rc.HasSet (ResolveContext.Options.LockScope)) {
63                                 rc.Report.Error (1996, loc,
64                                         "The `await' operator cannot be used in the body of a lock statement");
65                         }
66
67                         if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
68                                 rc.Report.Error (1989, loc, "An expression tree cannot contain an await operator");
69                                 return null;
70                         }
71
72                         if (rc.IsUnsafe) {
73                                 rc.Report.Error (4004, loc,
74                                         "The `await' operator cannot be used in an unsafe context");
75                         }
76
77                         var bc = (BlockContext) rc;
78
79                         stmt = new AwaitStatement (expr, loc);
80                         if (!stmt.Resolve (bc))
81                                 return null;
82
83                         type = stmt.ResultType;
84                         eclass = ExprClass.Variable;
85                         return this;
86                 }
87
88                 public override void Emit (EmitContext ec)
89                 {
90                         stmt.EmitPrologue (ec);
91
92                         using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
93                                 stmt.Emit (ec);
94                         }
95                 }
96                 
97                 public override Expression EmitToField (EmitContext ec)
98                 {
99                         stmt.EmitPrologue (ec);
100                         return stmt.GetResultExpression (ec);
101                 }
102                 
103                 public void EmitAssign (EmitContext ec, FieldExpr field)
104                 {
105                         stmt.EmitPrologue (ec);
106                         field.InstanceExpression.Emit (ec);
107                         stmt.Emit (ec);
108                 }
109
110                 public override void EmitStatement (EmitContext ec)
111                 {
112                         stmt.EmitStatement (ec);
113                 }
114
115                 public override object Accept (StructuralVisitor visitor)
116                 {
117                         return visitor.Visit (this);
118                 }
119         }
120
121         class AwaitStatement : YieldStatement<AsyncInitializer>
122         {
123                 sealed class AwaitableMemberAccess : MemberAccess
124                 {
125                         public AwaitableMemberAccess (Expression expr)
126                                 : base (expr, "GetAwaiter")
127                         {
128                         }
129
130                         protected override void Error_TypeDoesNotContainDefinition (ResolveContext rc, TypeSpec type, string name)
131                         {
132                                 Error_OperatorCannotBeApplied (rc, type);
133                         }
134
135                         protected override void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
136                         {
137                                 rc.Report.Error (4001, loc, "Cannot await `{0}' expression", type.GetSignatureForError ());
138                         }
139                 }
140
141                 sealed class GetResultInvocation : Invocation
142                 {
143                         public GetResultInvocation (MethodGroupExpr mge, Arguments arguments)
144                                 : base (null, arguments)
145                         {
146                                 mg = mge;
147                                 type = mg.BestCandidateReturnType;
148                         }
149
150                         public override Expression EmitToField (EmitContext ec)
151                         {
152                                 return this;
153                         }
154                 }
155
156                 Field awaiter;
157                 PropertySpec is_completed;
158                 MethodSpec on_completed;
159                 MethodSpec get_result;
160                 TypeSpec type;
161                 TypeSpec result_type;
162
163                 public AwaitStatement (Expression expr, Location loc)
164                         : base (expr, loc)
165                 {
166                 }
167
168                 #region Properties
169
170                 bool IsDynamic {
171                         get {
172                                 return is_completed == null;
173                         }
174                 }
175
176                 public TypeSpec ResultType {
177                         get {
178                                 return result_type;
179                         }
180                 }
181
182                 #endregion
183
184                 protected override void DoEmit (EmitContext ec)
185                 {
186                         GetResultExpression (ec).Emit (ec);
187                 }
188
189                 public Expression GetResultExpression (EmitContext ec)
190                 {
191                         var fe_awaiter = new FieldExpr (awaiter, loc);
192                         fe_awaiter.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
193
194                         //
195                         // result = awaiter.GetResult ();
196                         //
197                         if (IsDynamic) {
198                                 var rc = new ResolveContext (ec.MemberContext);
199                                 return new Invocation (new MemberAccess (fe_awaiter, "GetResult"), new Arguments (0)).Resolve (rc);
200                         } else {
201                                 var mg_result = MethodGroupExpr.CreatePredefined (get_result, fe_awaiter.Type, loc);
202                                 mg_result.InstanceExpression = fe_awaiter;
203
204                                 return new GetResultInvocation (mg_result, new Arguments (0));
205                         }
206                 }
207
208                 public void EmitPrologue (EmitContext ec)
209                 {
210                         var fe_awaiter = new FieldExpr (awaiter, loc);
211                         fe_awaiter.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
212
213                         //
214                         // awaiter = expr.GetAwaiter ();
215                         //
216                         fe_awaiter.EmitAssign (ec, expr, false, false);
217
218                         Label skip_continuation = ec.DefineLabel ();
219
220                         Expression completed_expr;
221                         if (IsDynamic) {
222                                 var rc = new ResolveContext (ec.MemberContext);
223
224                                 Arguments dargs = new Arguments (1);
225                                 dargs.Add (new Argument (fe_awaiter));
226                                 completed_expr = new DynamicMemberBinder ("IsCompleted", dargs, loc).Resolve (rc);
227                         } else {
228                                 var pe = PropertyExpr.CreatePredefined (is_completed, loc);
229                                 pe.InstanceExpression = fe_awaiter;
230                                 completed_expr = pe;
231                         }
232
233                         completed_expr.EmitBranchable (ec, skip_continuation, true);
234
235                         base.DoEmit (ec);
236
237                         //
238                         // The stack has to be empty before calling await continuation. We handle this
239                         // by lifting values which would be left on stack into class fields. The process
240                         // is quite complicated and quite hard to test because any expression can possibly
241                         // leave a value on the stack.
242                         //
243                         // Following assert fails when some of expression called before is missing EmitToField
244                         // or parent expression fails to find await in children expressions
245                         //
246                         ec.AssertEmptyStack ();
247
248                         var storey = (AsyncTaskStorey) machine_initializer.Storey;
249                         var cont_field = storey.EmitContinuationInitialization (ec);
250
251                         var args = new Arguments (1);
252                         args.Add (new Argument (cont_field));
253
254                         if (IsDynamic) {
255                                 var rc = new ResolveContext (ec.MemberContext);
256                                 var mg_expr = new Invocation (new MemberAccess (fe_awaiter, "OnCompleted"), args).Resolve (rc);
257
258                                 ExpressionStatement es = (ExpressionStatement) mg_expr;
259                                 es.EmitStatement (ec);
260                         } else {
261                                 var mg_completed = MethodGroupExpr.CreatePredefined (on_completed, fe_awaiter.Type, loc);
262                                 mg_completed.InstanceExpression = fe_awaiter;
263
264                                 //
265                                 // awaiter.OnCompleted (continuation);
266                                 //
267                                 mg_completed.EmitCall (ec, args);
268                         }
269
270                         // Return ok
271                         machine_initializer.EmitLeave (ec, unwind_protect);
272
273                         ec.MarkLabel (resume_point);
274                         ec.MarkLabel (skip_continuation);
275                 }
276
277                 public void EmitStatement (EmitContext ec)
278                 {
279                         EmitPrologue (ec);
280                         DoEmit (ec);
281
282                         if (ResultType.Kind != MemberKind.Void) {
283                                 var storey = (AsyncTaskStorey) machine_initializer.Storey;
284
285                             if (storey.HoistedReturn != null)
286                                 storey.HoistedReturn.EmitAssign (ec);
287                                 else
288                                         ec.Emit (OpCodes.Pop);
289                         }
290                 }
291
292                 void Error_WrongAwaiterPattern (ResolveContext rc, TypeSpec awaiter)
293                 {
294                         rc.Report.Error (4011, loc, "The awaiter type `{0}' must have suitable IsCompleted, OnCompleted, and GetResult members",
295                                 awaiter.GetSignatureForError ());
296                 }
297
298                 public override bool Resolve (BlockContext bc)
299                 {
300                         if (!base.Resolve (bc))
301                                 return false;
302
303                         Arguments args = new Arguments (0);
304
305                         type = expr.Type;
306
307                         //
308                         // The await expression is of dynamic type
309                         //
310                         if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
311                                 result_type = type;
312
313                                 awaiter = ((AsyncTaskStorey) machine_initializer.Storey).AddAwaiter (type, loc);
314
315                                 expr = new Invocation (new MemberAccess (expr, "GetAwaiter"), args).Resolve (bc);
316                                 return true;
317                         }
318
319                         //
320                         // Check whether the expression is awaitable
321                         //
322                         Expression ama = new AwaitableMemberAccess (expr).Resolve (bc);
323                         if (ama == null)
324                                 return false;
325
326                         var errors_printer = new SessionReportPrinter ();
327                         var old = bc.Report.SetPrinter (errors_printer);
328                         ama = new Invocation (ama, args).Resolve (bc);
329                         bc.Report.SetPrinter (old);
330
331                         if (errors_printer.ErrorsCount > 0 || !MemberAccess.IsValidDotExpression (ama.Type)) {
332                                 bc.Report.Error (1986, expr.Location,
333                                         "The `await' operand type `{0}' must have suitable GetAwaiter method",
334                                         expr.Type.GetSignatureForError ());
335
336                                 return false;
337                         }
338
339                         var awaiter_type = ama.Type;
340                         awaiter = ((AsyncTaskStorey) machine_initializer.Storey).AddAwaiter (awaiter_type, loc);
341
342                         expr = ama;
343
344                         //
345                         // Predefined: bool IsCompleted { get; } 
346                         //
347                         is_completed = MemberCache.FindMember (awaiter_type, MemberFilter.Property ("IsCompleted", bc.Module.Compiler.BuiltinTypes.Bool),
348                                 BindingRestriction.InstanceOnly) as PropertySpec;
349
350                         if (is_completed == null || !is_completed.HasGet) {
351                                 Error_WrongAwaiterPattern (bc, awaiter_type);
352                                 return false;
353                         }
354
355                         //
356                         // Predefined: OnCompleted (Action)
357                         //
358                         if (bc.Module.PredefinedTypes.Action.Define ()) {
359                                 on_completed = MemberCache.FindMember (awaiter_type, MemberFilter.Method ("OnCompleted", 0,
360                                         ParametersCompiled.CreateFullyResolved (bc.Module.PredefinedTypes.Action.TypeSpec), bc.Module.Compiler.BuiltinTypes.Void),
361                                         BindingRestriction.InstanceOnly) as MethodSpec;
362
363                                 if (on_completed == null) {
364                                         Error_WrongAwaiterPattern (bc, awaiter_type);
365                                         return false;
366                                 }
367                         }
368
369                         //
370                         // Predefined: GetResult ()
371                         //
372                         // The method return type is also result type of await expression
373                         //
374                         get_result = MemberCache.FindMember (awaiter_type, MemberFilter.Method ("GetResult", 0,
375                                 ParametersCompiled.EmptyReadOnlyParameters, null),
376                                 BindingRestriction.InstanceOnly) as MethodSpec;
377
378                         if (get_result == null) {
379                                 Error_WrongAwaiterPattern (bc, awaiter_type);
380                                 return false;
381                         }
382
383                         result_type = get_result.ReturnType;
384
385                         return true;
386                 }
387         }
388
389         public class AsyncInitializer : StateMachineInitializer
390         {
391                 TypeInferenceContext return_inference;
392
393                 public AsyncInitializer (ParametersBlock block, TypeDefinition host, TypeSpec returnType)
394                         : base (block, host, returnType)
395                 {
396                 }
397
398                 #region Properties
399
400                 public override string ContainerType {
401                         get {
402                                 return "async state machine block";
403                         }
404                 }
405
406                 public override bool IsIterator {
407                         get {
408                                 return false;
409                         }
410                 }
411
412                 public Block OriginalBlock {
413                         get {
414                                 return block.Parent;
415                         }
416                 }
417
418                 public TypeInferenceContext ReturnTypeInference {
419                         get {
420                                 return return_inference;
421                         }
422                 }
423
424                 #endregion
425
426                 public static void Create (IMemberContext context, ParametersBlock block, ParametersCompiled parameters, TypeDefinition host, TypeSpec returnType, Location loc)
427                 {
428                         for (int i = 0; i < parameters.Count; i++) {
429                                 Parameter p = parameters[i];
430                                 Parameter.Modifier mod = p.ModFlags;
431                                 if ((mod & Parameter.Modifier.ISBYREF) != 0) {
432                                         host.Compiler.Report.Error (1988, p.Location,
433                                                 "Async methods cannot have ref or out parameters");
434                                         return;
435                                 }
436
437                                 if (p is ArglistParameter) {
438                                         host.Compiler.Report.Error (4006, p.Location,
439                                                 "__arglist is not allowed in parameter list of async methods");
440                                         return;
441                                 }
442
443                                 if (parameters.Types[i].IsPointer) {
444                                         host.Compiler.Report.Error (4005, p.Location,
445                                                 "Async methods cannot have unsafe parameters");
446                                         return;
447                                 }
448                         }
449
450                         if (!block.HasAwait) {
451                                 host.Compiler.Report.Warning (1998, 1, loc,
452                                         "Async block lacks `await' operator and will run synchronously");
453                         }
454
455                         block.WrapIntoAsyncTask (context, host, returnType);
456                 }
457
458                 protected override BlockContext CreateBlockContext (ResolveContext rc)
459                 {
460                         var ctx = base.CreateBlockContext (rc);
461                         var lambda = rc.CurrentAnonymousMethod as LambdaMethod;
462                         if (lambda != null)
463                                 return_inference = lambda.ReturnTypeInference;
464
465                         ctx.StartFlowBranching (this, rc.CurrentBranching);
466                         return ctx;
467                 }
468
469                 public override Expression CreateExpressionTree (ResolveContext ec)
470                 {
471                         return base.CreateExpressionTree (ec);
472                 }
473
474                 public override void Emit (EmitContext ec)
475                 {
476                         throw new NotImplementedException ();
477                 }
478
479                 protected override void EmitMoveNextEpilogue (EmitContext ec)
480                 {
481                         var storey = (AsyncTaskStorey) Storey;
482                         storey.EmitSetResult (ec);
483                 }
484
485                 public override void EmitStatement (EmitContext ec)
486                 {
487                         var storey = (AsyncTaskStorey) Storey;
488                         storey.Instance.Emit (ec);
489
490                         var move_next_entry = storey.StateMachineMethod.Spec;
491                         if (storey.MemberName.Arity > 0) {
492                                 move_next_entry = MemberCache.GetMember (storey.Instance.Type, move_next_entry);
493                         }
494
495                         ec.Emit (OpCodes.Call, move_next_entry);
496
497                         //
498                         // Emits return <async-storey-instance>.$builder.Task;
499                         //
500                         if (storey.Task != null) {
501                                 var builder_field = storey.Builder.Spec;
502                                 var task_get = storey.Task.Get;
503
504                                 if (storey.MemberName.Arity > 0) {
505                                         builder_field = MemberCache.GetMember (storey.Instance.Type, builder_field);
506                                         task_get = MemberCache.GetMember (builder_field.MemberType, task_get);
507                                 }
508
509                                 var pe_task = new PropertyExpr (storey.Task, loc) {
510                                         InstanceExpression = new FieldExpr (builder_field, loc) {
511                                                 InstanceExpression = storey.Instance
512                                         },
513                                         Getter = task_get
514                                 };
515
516                                 pe_task.Emit (ec);
517                         }
518
519                         ec.Emit (OpCodes.Ret);
520                 }
521         }
522
523         class AsyncTaskStorey : StateMachine
524         {
525                 int awaiters;
526                 Field builder, continuation;
527                 readonly TypeSpec return_type;
528                 MethodSpec set_result;
529                 MethodSpec set_exception;
530                 PropertySpec task;
531                 LocalVariable hoisted_return;
532                 int locals_captured;
533                 Dictionary<TypeSpec, List<StackField>> stack_fields;
534                 TypeSpec action;
535
536                 public AsyncTaskStorey (IMemberContext context, AsyncInitializer initializer, TypeSpec type)
537                         : base (initializer.OriginalBlock, initializer.Host, context.CurrentMemberDefinition as MemberBase, context.CurrentTypeParameters, "async")
538                 {
539                         return_type = type;
540                 }
541
542                 #region Properties
543
544                 public Field Builder {
545                         get {
546                                 return builder;
547                         }
548                 }
549
550                 public LocalVariable HoistedReturn {
551                         get {
552                                 return hoisted_return;
553                         }
554                 }
555
556                 public TypeSpec ReturnType {
557                         get {
558                                 return return_type;
559                         }
560                 }
561
562                 public PropertySpec Task {
563                         get {
564                                 return task;
565                         }
566                 }
567
568                 #endregion
569
570                 public Field AddAwaiter (TypeSpec type, Location loc)
571                 {
572                         return AddCapturedVariable ("$awaiter" + awaiters++.ToString ("X"), type);
573                 }
574
575                 public StackField AddCapturedLocalVariable (TypeSpec type)
576                 {
577                         if (mutator != null)
578                                 type = mutator.Mutate (type);
579
580                         List<StackField> existing_fields = null;
581                         if (stack_fields == null) {
582                                 stack_fields = new Dictionary<TypeSpec, List<StackField>> ();
583                         } else if (stack_fields.TryGetValue (type, out existing_fields)) {
584                                 foreach (var f in existing_fields) {
585                                         if (f.CanBeReused) {
586                                                 f.CanBeReused = false;
587                                                 return f;
588                                         }
589                                 }
590                         }
591
592                         const Modifiers mod = Modifiers.COMPILER_GENERATED | Modifiers.PRIVATE;
593                         var field = new StackField (this, new TypeExpression (type, Location), mod, new MemberName ("<s>$" + locals_captured++.ToString ("X"), Location));
594                         AddField (field);
595
596                         field.Define ();
597
598                         if (existing_fields == null) {
599                                 existing_fields = new List<StackField> ();
600                                 stack_fields.Add (type, existing_fields);
601                         }
602
603                         existing_fields.Add (field);
604
605                         return field;
606                 }
607
608                 protected override bool DoDefineMembers ()
609                 {
610                         action = Module.PredefinedTypes.Action.Resolve ();
611
612                         PredefinedType builder_type;
613                         PredefinedMember<MethodSpec> bf;
614                         PredefinedMember<MethodSpec> sr;
615                         PredefinedMember<MethodSpec> se;
616                         bool has_task_return_type = false;
617                         var pred_members = Module.PredefinedMembers;
618
619                         if (return_type.Kind == MemberKind.Void) {
620                                 builder_type = Module.PredefinedTypes.AsyncVoidMethodBuilder;
621                                 bf = pred_members.AsyncVoidMethodBuilderCreate;
622                                 sr = pred_members.AsyncVoidMethodBuilderSetResult;
623                                 se = pred_members.AsyncVoidMethodBuilderSetException;
624                         } else if (return_type == Module.PredefinedTypes.Task.TypeSpec) {
625                                 builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilder;
626                                 bf = pred_members.AsyncTaskMethodBuilderCreate;
627                                 sr = pred_members.AsyncTaskMethodBuilderSetResult;
628                                 se = pred_members.AsyncTaskMethodBuilderSetException;
629                                 task = pred_members.AsyncTaskMethodBuilderTask.Get ();
630                         } else {
631                                 builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilderGeneric;
632                                 bf = pred_members.AsyncTaskMethodBuilderGenericCreate;
633                                 sr = pred_members.AsyncTaskMethodBuilderGenericSetResult;
634                                 se = pred_members.AsyncTaskMethodBuilderGenericSetException;
635                                 task = pred_members.AsyncTaskMethodBuilderGenericTask.Get ();
636                                 has_task_return_type = true;
637                         }
638
639                         set_result = sr.Get ();
640                         set_exception = se.Get ();
641                         var builder_factory = bf.Get ();
642                         if (!builder_type.Define () || set_result == null || builder_factory == null || set_exception == null) {
643                                 Report.Error (1993, Location,
644                                         "Cannot find compiler required types for asynchronous functions support. Are you targeting the wrong framework version?");
645                                 return base.DoDefineMembers ();
646                         }
647
648                         var bt = builder_type.TypeSpec;
649
650                         //
651                         // Inflate generic Task types
652                         //
653                         if (has_task_return_type) {
654                                 var task_return_type = return_type.TypeArguments;
655                                 if (mutator != null)
656                                         task_return_type = mutator.Mutate (task_return_type);
657
658                                 bt = bt.MakeGenericType (Module, task_return_type);
659                                 builder_factory = MemberCache.GetMember<MethodSpec> (bt, builder_factory);
660                                 set_result = MemberCache.GetMember<MethodSpec> (bt, set_result);
661                                 set_exception = MemberCache.GetMember<MethodSpec> (bt, set_exception);
662
663                                 if (task != null)
664                                         task = MemberCache.GetMember<PropertySpec> (bt, task);
665                         }
666
667                         builder = AddCompilerGeneratedField ("$builder", new TypeExpression (bt, Location));
668
669                         var ctor = DefineDefaultConstructor (false);
670
671                         if (!base.DoDefineMembers ())
672                                 return false;
673
674                         Block block = ctor.Block;
675
676                         var mg = MethodGroupExpr.CreatePredefined (builder_factory, bt, Location);
677                         block.AddStatement (
678                                 new StatementExpression (new SimpleAssign (
679                                         new FieldExpr (builder, Location),
680                                         new Invocation (mg, new Arguments (0)),
681                                 Location)));
682
683                         if (has_task_return_type) {
684                                 hoisted_return = LocalVariable.CreateCompilerGenerated (bt.TypeArguments[0], block, Location);
685                         }
686
687                         return true;
688                 }
689
690                 public Expression EmitContinuationInitialization (EmitContext ec)
691                 {
692                         //
693                         // When more than 1 awaiter has been used in the block we
694                         // introduce class scope field to cache continuation delegate
695                         //
696                         if (awaiters > 1) {
697                                 if (continuation == null) {
698                                         continuation = AddCompilerGeneratedField ("$continuation", new TypeExpression (action, Location), true);
699                                         continuation.Define ();
700                                 }
701
702                                 var fexpr = new FieldExpr (continuation, Location);
703                                 fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location);
704
705                                 //
706                                 // if ($continuation == null)
707                                 //    $continuation = new Action (MoveNext);
708                                 //
709                                 fexpr.Emit (ec);
710
711                                 var skip_cont_init = ec.DefineLabel ();
712                                 ec.Emit (OpCodes.Brtrue_S, skip_cont_init);
713
714                                 ec.EmitThis ();
715                                 EmitActionLoad (ec);
716                                 ec.Emit (OpCodes.Stfld, continuation.Spec);
717                                 ec.MarkLabel (skip_cont_init);
718
719                                 return fexpr;
720                         }
721
722                         //
723                         // Otherwise simply use temporary local variable
724                         //
725                         var field = LocalVariable.CreateCompilerGenerated (action, OriginalSourceBlock, Location);
726                         EmitActionLoad (ec);
727                         field.EmitAssign (ec);
728                         return new LocalVariableReference (field, Location);
729                 }
730
731                 void EmitActionLoad (EmitContext ec)
732                 {
733                         ec.EmitThis ();
734                         ec.Emit (OpCodes.Ldftn, StateMachineMethod.Spec);
735                         ec.Emit (OpCodes.Newobj, (MethodSpec) MemberCache.FindMember (action, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly));
736                 }
737
738                 public void EmitSetException (EmitContext ec, LocalVariableReference exceptionVariable)
739                 {
740                         //
741                         // $builder.SetException (Exception)
742                         //
743                         var mg = MethodGroupExpr.CreatePredefined (set_exception, set_exception.DeclaringType, Location);
744                         mg.InstanceExpression = new FieldExpr (Builder, Location) {
745                                 InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location)
746                         };
747
748                         Arguments args = new Arguments (1);
749                         args.Add (new Argument (exceptionVariable));
750
751                         mg.EmitCall (ec, args);
752                 }
753
754                 public void EmitSetResult (EmitContext ec)
755                 {
756                         //
757                         // $builder.SetResult ();
758                         // $builder.SetResult<return-type> (value);
759                         //
760                         var mg = MethodGroupExpr.CreatePredefined (set_result, set_result.DeclaringType, Location);
761                         mg.InstanceExpression = new FieldExpr (Builder, Location) {
762                                 InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location)
763                         };
764
765                         Arguments args;
766                         if (hoisted_return == null) {
767                                 args = new Arguments (0);
768                         } else {
769                                 args = new Arguments (1);
770                                 args.Add (new Argument (new LocalVariableReference (hoisted_return, Location)));
771                         }
772
773                         mg.EmitCall (ec, args);
774                 }
775         }
776
777         class StackField : Field
778         {
779                 public StackField (TypeDefinition parent, FullNamedExpression type, Modifiers mod, MemberName name)
780                         : base (parent, type, mod, name, null)
781                 {
782                 }
783
784                 public bool CanBeReused { get; set; }
785         }
786
787         class StackFieldExpr : FieldExpr
788         {
789                 public StackFieldExpr (Field field)
790                         : base (field, Location.Null)
791                 {
792                 }
793
794                 public override void Emit (EmitContext ec)
795                 {
796                         base.Emit (ec);
797
798                         var field = (StackField) spec.MemberDefinition;
799                         field.CanBeReused = true;
800                 }
801         }
802 }