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