~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/async.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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-2012 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;
 
20
using IKVM.Reflection.Emit;
 
21
#else
 
22
using System.Reflection;
 
23
using System.Reflection.Emit;
 
24
#endif
 
25
 
 
26
namespace Mono.CSharp
 
27
{
 
28
        public class Await : ExpressionStatement
 
29
        {
 
30
                Expression expr;
 
31
                AwaitStatement stmt;
 
32
                
 
33
                public Expression Expression {
 
34
                        get {
 
35
                                return expr;
 
36
                        }
 
37
                }
 
38
                
 
39
                public Await (Expression expr, Location loc)
 
40
                {
 
41
                        this.expr = expr;
 
42
                        this.loc = loc;
 
43
                }
 
44
 
 
45
                public Expression Expr {
 
46
                        get {
 
47
                                return expr;
 
48
                        }
 
49
                }
 
50
 
 
51
                public AwaitStatement Statement {
 
52
                        get {
 
53
                                return stmt;
 
54
                        }
 
55
                }
 
56
 
 
57
                protected override void CloneTo (CloneContext clonectx, Expression target)
 
58
                {
 
59
                        var t = (Await) target;
 
60
 
 
61
                        t.expr = expr.Clone (clonectx);
 
62
                }
 
63
 
 
64
                public override Expression CreateExpressionTree (ResolveContext ec)
 
65
                {
 
66
                        throw new NotImplementedException ("ET");
 
67
                }
 
68
 
 
69
                public override bool ContainsEmitWithAwait ()
 
70
                {
 
71
                        return true;
 
72
                }
 
73
 
 
74
                protected override Expression DoResolve (ResolveContext rc)
 
75
                {
 
76
                        if (rc.HasSet (ResolveContext.Options.LockScope)) {
 
77
                                rc.Report.Error (1996, loc,
 
78
                                        "The `await' operator cannot be used in the body of a lock statement");
 
79
                        }
 
80
 
 
81
                        if (rc.IsUnsafe) {
 
82
                                rc.Report.Error (4004, loc,
 
83
                                        "The `await' operator cannot be used in an unsafe context");
 
84
                        }
 
85
 
 
86
                        var bc = (BlockContext) rc;
 
87
 
 
88
                        stmt = new AwaitStatement (expr, loc);
 
89
                        if (!stmt.Resolve (bc))
 
90
                                return null;
 
91
 
 
92
                        type = stmt.ResultType;
 
93
                        eclass = ExprClass.Variable;
 
94
                        return this;
 
95
                }
 
96
 
 
97
                public override void Emit (EmitContext ec)
 
98
                {
 
99
                        stmt.EmitPrologue (ec);
 
100
 
 
101
                        using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
 
102
                                stmt.Emit (ec);
 
103
                        }
 
104
                }
 
105
                
 
106
                public override Expression EmitToField (EmitContext ec)
 
107
                {
 
108
                        stmt.EmitPrologue (ec);
 
109
                        return stmt.GetResultExpression (ec);
 
110
                }
 
111
                
 
112
                public void EmitAssign (EmitContext ec, FieldExpr field)
 
113
                {
 
114
                        stmt.EmitPrologue (ec);
 
115
                        field.InstanceExpression.Emit (ec);
 
116
                        stmt.Emit (ec);
 
117
                }
 
118
 
 
119
                public override void EmitStatement (EmitContext ec)
 
120
                {
 
121
                        stmt.EmitStatement (ec);
 
122
                }
 
123
 
 
124
                public override object Accept (StructuralVisitor visitor)
 
125
                {
 
126
                        return visitor.Visit (this);
 
127
                }
 
128
        }
 
129
 
 
130
        public class AwaitStatement : YieldStatement<AsyncInitializer>
 
131
        {
 
132
                public sealed class AwaitableMemberAccess : MemberAccess
 
133
                {
 
134
                        public AwaitableMemberAccess (Expression expr)
 
135
                                : base (expr, "GetAwaiter")
 
136
                        {
 
137
                        }
 
138
 
 
139
                        public bool ProbingMode { get; set; }
 
140
 
 
141
                        protected override void Error_TypeDoesNotContainDefinition (ResolveContext rc, TypeSpec type, string name)
 
142
                        {
 
143
                                Error_OperatorCannotBeApplied (rc, type);
 
144
                        }
 
145
 
 
146
                        protected override void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
 
147
                        {
 
148
                                if (ProbingMode)
 
149
                                        return;
 
150
 
 
151
                                var invocation = LeftExpression as Invocation;
 
152
                                if (invocation != null && invocation.MethodGroup != null && (invocation.MethodGroup.BestCandidate.Modifiers & Modifiers.ASYNC) != 0) {
 
153
                                        rc.Report.Error (4008, loc, "Cannot await void method `{0}'. Consider changing method return type to `Task'",
 
154
                                                invocation.GetSignatureForError ());
 
155
                                } else {
 
156
                                        rc.Report.Error (4001, loc, "Cannot await `{0}' expression", type.GetSignatureForError ());
 
157
                                }
 
158
                        }
 
159
                }
 
160
 
 
161
                sealed class GetResultInvocation : Invocation
 
162
                {
 
163
                        public GetResultInvocation (MethodGroupExpr mge, Arguments arguments)
 
164
                                : base (null, arguments)
 
165
                        {
 
166
                                mg = mge;
 
167
                                type = mg.BestCandidateReturnType;
 
168
                        }
 
169
 
 
170
                        public override Expression EmitToField (EmitContext ec)
 
171
                        {
 
172
                                return this;
 
173
                        }
 
174
                }
 
175
 
 
176
                Field awaiter;
 
177
                AwaiterDefinition awaiter_definition;
 
178
                TypeSpec type;
 
179
                TypeSpec result_type;
 
180
 
 
181
                public AwaitStatement (Expression expr, Location loc)
 
182
                        : base (expr, loc)
 
183
                {
 
184
                }
 
185
 
 
186
                #region Properties
 
187
 
 
188
                bool IsDynamic {
 
189
                        get {
 
190
                                return awaiter_definition == null;
 
191
                        }
 
192
                }
 
193
 
 
194
                public TypeSpec ResultType {
 
195
                        get {
 
196
                                return result_type;
 
197
                        }
 
198
                }
 
199
 
 
200
                #endregion
 
201
 
 
202
                protected override void DoEmit (EmitContext ec)
 
203
                {
 
204
                        GetResultExpression (ec).Emit (ec);
 
205
                }
 
206
 
 
207
                public Expression GetResultExpression (EmitContext ec)
 
208
                {
 
209
                        var fe_awaiter = new FieldExpr (awaiter, loc);
 
210
                        fe_awaiter.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
 
211
 
 
212
                        //
 
213
                        // result = awaiter.GetResult ();
 
214
                        //
 
215
                        if (IsDynamic) {
 
216
                                var rc = new ResolveContext (ec.MemberContext);
 
217
                                return new Invocation (new MemberAccess (fe_awaiter, "GetResult"), new Arguments (0)).Resolve (rc);
 
218
                        }
 
219
                        
 
220
                        var mg_result = MethodGroupExpr.CreatePredefined (awaiter_definition.GetResult, fe_awaiter.Type, loc);
 
221
                        mg_result.InstanceExpression = fe_awaiter;
 
222
 
 
223
                        return new GetResultInvocation (mg_result, new Arguments (0));
 
224
                }
 
225
 
 
226
                public void EmitPrologue (EmitContext ec)
 
227
                {
 
228
                        awaiter = ((AsyncTaskStorey) machine_initializer.Storey).AddAwaiter (expr.Type, loc);
 
229
 
 
230
                        var fe_awaiter = new FieldExpr (awaiter, loc);
 
231
                        fe_awaiter.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
 
232
 
 
233
                        //
 
234
                        // awaiter = expr.GetAwaiter ();
 
235
                        //
 
236
                        using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
 
237
                                fe_awaiter.EmitAssign (ec, expr, false, false);
 
238
                        }
 
239
 
 
240
                        Label skip_continuation = ec.DefineLabel ();
 
241
 
 
242
                        Expression completed_expr;
 
243
                        if (IsDynamic) {
 
244
                                var rc = new ResolveContext (ec.MemberContext);
 
245
 
 
246
                                Arguments dargs = new Arguments (1);
 
247
                                dargs.Add (new Argument (fe_awaiter));
 
248
                                completed_expr = new DynamicMemberBinder ("IsCompleted", dargs, loc).Resolve (rc);
 
249
 
 
250
                                dargs = new Arguments (1);
 
251
                                dargs.Add (new Argument (completed_expr));
 
252
                                completed_expr = new DynamicConversion (ec.Module.Compiler.BuiltinTypes.Bool, 0, dargs, loc).Resolve (rc);
 
253
                        } else {
 
254
                                var pe = PropertyExpr.CreatePredefined (awaiter_definition.IsCompleted, loc);
 
255
                                pe.InstanceExpression = fe_awaiter;
 
256
                                completed_expr = pe;
 
257
                        }
 
258
 
 
259
                        completed_expr.EmitBranchable (ec, skip_continuation, true);
 
260
 
 
261
                        base.DoEmit (ec);
 
262
 
 
263
                        //
 
264
                        // The stack has to be empty before calling await continuation. We handle this
 
265
                        // by lifting values which would be left on stack into class fields. The process
 
266
                        // is quite complicated and quite hard to test because any expression can possibly
 
267
                        // leave a value on the stack.
 
268
                        //
 
269
                        // Following assert fails when some of expression called before is missing EmitToField
 
270
                        // or parent expression fails to find await in children expressions
 
271
                        //
 
272
                        ec.AssertEmptyStack ();
 
273
 
 
274
                        var storey = (AsyncTaskStorey) machine_initializer.Storey;
 
275
                        if (IsDynamic) {
 
276
                                storey.EmitAwaitOnCompletedDynamic (ec, fe_awaiter);
 
277
                        } else {
 
278
                                storey.EmitAwaitOnCompleted (ec, fe_awaiter);
 
279
                        }
 
280
 
 
281
                        // Return ok
 
282
                        machine_initializer.EmitLeave (ec, unwind_protect);
 
283
 
 
284
                        ec.MarkLabel (resume_point);
 
285
                        ec.MarkLabel (skip_continuation);
 
286
                }
 
287
 
 
288
                public void EmitStatement (EmitContext ec)
 
289
                {
 
290
                        EmitPrologue (ec);
 
291
                        DoEmit (ec);
 
292
 
 
293
                        awaiter.IsAvailableForReuse = true;
 
294
 
 
295
                        if (ResultType.Kind != MemberKind.Void)
 
296
                                ec.Emit (OpCodes.Pop);
 
297
                }
 
298
 
 
299
                void Error_WrongAwaiterPattern (ResolveContext rc, TypeSpec awaiter)
 
300
                {
 
301
                        rc.Report.Error (4011, loc, "The awaiter type `{0}' must have suitable IsCompleted and GetResult members",
 
302
                                awaiter.GetSignatureForError ());
 
303
                }
 
304
 
 
305
                public override bool Resolve (BlockContext bc)
 
306
                {
 
307
                        if (bc.CurrentBlock is Linq.QueryBlock) {
 
308
                                bc.Report.Error (1995, loc,
 
309
                                        "The `await' operator may only be used in a query expression within the first collection expression of the initial `from' clause or within the collection expression of a `join' clause");
 
310
                                return false;
 
311
                        }
 
312
 
 
313
                        if (!base.Resolve (bc))
 
314
                                return false;
 
315
 
 
316
                        type = expr.Type;
 
317
                        Arguments args = new Arguments (0);
 
318
 
 
319
                        //
 
320
                        // The await expression is of dynamic type
 
321
                        //
 
322
                        if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
 
323
                                result_type = type;
 
324
                                expr = new Invocation (new MemberAccess (expr, "GetAwaiter"), args).Resolve (bc);
 
325
                                return true;
 
326
                        }
 
327
 
 
328
                        //
 
329
                        // Check whether the expression is awaitable
 
330
                        //
 
331
                        Expression ama = new AwaitableMemberAccess (expr).Resolve (bc);
 
332
                        if (ama == null)
 
333
                                return false;
 
334
 
 
335
                        var errors_printer = new SessionReportPrinter ();
 
336
                        var old = bc.Report.SetPrinter (errors_printer);
 
337
                        ama = new Invocation (ama, args).Resolve (bc);
 
338
                        bc.Report.SetPrinter (old);
 
339
 
 
340
                        if (errors_printer.ErrorsCount > 0 || !MemberAccess.IsValidDotExpression (ama.Type)) {
 
341
                                bc.Report.Error (1986, expr.Location,
 
342
                                        "The `await' operand type `{0}' must have suitable GetAwaiter method",
 
343
                                        expr.Type.GetSignatureForError ());
 
344
 
 
345
                                return false;
 
346
                        }
 
347
 
 
348
                        var awaiter_type = ama.Type;
 
349
 
 
350
                        awaiter_definition = bc.Module.GetAwaiter (awaiter_type);
 
351
 
 
352
                        if (!awaiter_definition.IsValidPattern) {
 
353
                                Error_WrongAwaiterPattern (bc, awaiter_type);
 
354
                                return false;
 
355
                        }
 
356
 
 
357
                        if (!awaiter_definition.INotifyCompletion) {
 
358
                                bc.Report.Error (4027, loc, "The awaiter type `{0}' must implement interface `{1}'",
 
359
                                        awaiter_type.GetSignatureForError (), bc.Module.PredefinedTypes.INotifyCompletion.GetSignatureForError ());
 
360
                                return false;
 
361
                        }
 
362
 
 
363
                        expr = ama;
 
364
                        result_type = awaiter_definition.GetResult.ReturnType;
 
365
 
 
366
                        return true;
 
367
                }
 
368
        }
 
369
 
 
370
        public class AsyncInitializer : StateMachineInitializer
 
371
        {
 
372
                TypeInferenceContext return_inference;
 
373
 
 
374
                public AsyncInitializer (ParametersBlock block, TypeDefinition host, TypeSpec returnType)
 
375
                        : base (block, host, returnType)
 
376
                {
 
377
                }
 
378
 
 
379
                #region Properties
 
380
 
 
381
                public override string ContainerType {
 
382
                        get {
 
383
                                return "async state machine block";
 
384
                        }
 
385
                }
 
386
 
 
387
                public override bool IsIterator {
 
388
                        get {
 
389
                                return false;
 
390
                        }
 
391
                }
 
392
 
 
393
                public TypeInferenceContext ReturnTypeInference {
 
394
                        get {
 
395
                                return return_inference;
 
396
                        }
 
397
                }
 
398
 
 
399
                #endregion
 
400
 
 
401
                protected override BlockContext CreateBlockContext (ResolveContext rc)
 
402
                {
 
403
                        var ctx = base.CreateBlockContext (rc);
 
404
                        var lambda = rc.CurrentAnonymousMethod as LambdaMethod;
 
405
                        if (lambda != null)
 
406
                                return_inference = lambda.ReturnTypeInference;
 
407
 
 
408
                        ctx.StartFlowBranching (this, rc.CurrentBranching);
 
409
                        return ctx;
 
410
                }
 
411
 
 
412
                public override Expression CreateExpressionTree (ResolveContext ec)
 
413
                {
 
414
                        return base.CreateExpressionTree (ec);
 
415
                }
 
416
 
 
417
                public override void Emit (EmitContext ec)
 
418
                {
 
419
                        throw new NotImplementedException ();
 
420
                }
 
421
 
 
422
                protected override void EmitMoveNextEpilogue (EmitContext ec)
 
423
                {
 
424
                        var storey = (AsyncTaskStorey) Storey;
 
425
                        storey.EmitSetResult (ec);
 
426
                }
 
427
 
 
428
                public override void EmitStatement (EmitContext ec)
 
429
                {
 
430
                        var storey = (AsyncTaskStorey) Storey;
 
431
                        storey.EmitInitializer (ec);
 
432
                        ec.Emit (OpCodes.Ret);
 
433
                }
 
434
        }
 
435
 
 
436
        class AsyncTaskStorey : StateMachine
 
437
        {
 
438
                int awaiters;
 
439
                Field builder;
 
440
                readonly TypeSpec return_type;
 
441
                MethodSpec set_result;
 
442
                MethodSpec set_exception;
 
443
                MethodSpec builder_factory;
 
444
                MethodSpec builder_start;
 
445
                PropertySpec task;
 
446
                LocalVariable hoisted_return;
 
447
                int locals_captured;
 
448
                Dictionary<TypeSpec, List<Field>> stack_fields;
 
449
                Dictionary<TypeSpec, List<Field>> awaiter_fields;
 
450
 
 
451
                public AsyncTaskStorey (ParametersBlock block, IMemberContext context, AsyncInitializer initializer, TypeSpec type)
 
452
                        : base (block, initializer.Host, context.CurrentMemberDefinition as MemberBase, context.CurrentTypeParameters, "async", MemberKind.Struct)
 
453
                {
 
454
                        return_type = type;
 
455
                        awaiter_fields = new Dictionary<TypeSpec, List<Field>> ();
 
456
                }
 
457
 
 
458
                #region Properties
 
459
 
 
460
                public LocalVariable HoistedReturn {
 
461
                        get {
 
462
                                return hoisted_return;
 
463
                        }
 
464
                }
 
465
 
 
466
                public TypeSpec ReturnType {
 
467
                        get {
 
468
                                return return_type;
 
469
                        }
 
470
                }
 
471
 
 
472
                public PropertySpec Task {
 
473
                        get {
 
474
                                return task;
 
475
                        }
 
476
                }
 
477
 
 
478
                protected override TypeAttributes TypeAttr {
 
479
                        get {
 
480
                                return base.TypeAttr & ~TypeAttributes.SequentialLayout;
 
481
                        }
 
482
                }
 
483
 
 
484
                #endregion
 
485
 
 
486
                public Field AddAwaiter (TypeSpec type, Location loc)
 
487
                {
 
488
                        if (mutator != null)
 
489
                                type = mutator.Mutate (type);
 
490
 
 
491
                        List<Field> existing_fields = null;
 
492
                        if (awaiter_fields.TryGetValue (type, out existing_fields)) {
 
493
                                foreach (var f in existing_fields) {
 
494
                                        if (f.IsAvailableForReuse) {
 
495
                                                f.IsAvailableForReuse = false;
 
496
                                                return f;
 
497
                                        }
 
498
                                }
 
499
                        }
 
500
 
 
501
                        var field = AddCompilerGeneratedField ("$awaiter" + awaiters++.ToString ("X"), new TypeExpression (type, Location), true);
 
502
                        field.Define ();
 
503
 
 
504
                        if (existing_fields == null) {
 
505
                                existing_fields = new List<Field> ();
 
506
                                awaiter_fields.Add (type, existing_fields);
 
507
                        }
 
508
 
 
509
                        existing_fields.Add (field);
 
510
                        return field;
 
511
                }
 
512
 
 
513
                public Field AddCapturedLocalVariable (TypeSpec type)
 
514
                {
 
515
                        if (mutator != null)
 
516
                                type = mutator.Mutate (type);
 
517
 
 
518
                        List<Field> existing_fields = null;
 
519
                        if (stack_fields == null) {
 
520
                                stack_fields = new Dictionary<TypeSpec, List<Field>> ();
 
521
                        } else if (stack_fields.TryGetValue (type, out existing_fields)) {
 
522
                                foreach (var f in existing_fields) {
 
523
                                        if (f.IsAvailableForReuse) {
 
524
                                                f.IsAvailableForReuse = false;
 
525
                                                return f;
 
526
                                        }
 
527
                                }
 
528
                        }
 
529
 
 
530
                        var field = AddCompilerGeneratedField ("$stack" + locals_captured++.ToString ("X"), new TypeExpression (type, Location), true);
 
531
                        field.Define ();
 
532
 
 
533
                        if (existing_fields == null) {
 
534
                                existing_fields = new List<Field> ();
 
535
                                stack_fields.Add (type, existing_fields);
 
536
                        }
 
537
 
 
538
                        existing_fields.Add (field);
 
539
 
 
540
                        return field;
 
541
                }
 
542
 
 
543
                protected override bool DoDefineMembers ()
 
544
                {
 
545
                        PredefinedType builder_type;
 
546
                        PredefinedMember<MethodSpec> bf;
 
547
                        PredefinedMember<MethodSpec> bs;
 
548
                        PredefinedMember<MethodSpec> sr;
 
549
                        PredefinedMember<MethodSpec> se;
 
550
                        PredefinedMember<MethodSpec> sm;
 
551
                        bool has_task_return_type = false;
 
552
                        var pred_members = Module.PredefinedMembers;
 
553
 
 
554
                        if (return_type.Kind == MemberKind.Void) {
 
555
                                builder_type = Module.PredefinedTypes.AsyncVoidMethodBuilder;
 
556
                                bf = pred_members.AsyncVoidMethodBuilderCreate;
 
557
                                bs = pred_members.AsyncVoidMethodBuilderStart;
 
558
                                sr = pred_members.AsyncVoidMethodBuilderSetResult;
 
559
                                se = pred_members.AsyncVoidMethodBuilderSetException;
 
560
                                sm = pred_members.AsyncVoidMethodBuilderSetStateMachine;
 
561
                        } else if (return_type == Module.PredefinedTypes.Task.TypeSpec) {
 
562
                                builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilder;
 
563
                                bf = pred_members.AsyncTaskMethodBuilderCreate;
 
564
                                bs = pred_members.AsyncTaskMethodBuilderStart;
 
565
                                sr = pred_members.AsyncTaskMethodBuilderSetResult;
 
566
                                se = pred_members.AsyncTaskMethodBuilderSetException;
 
567
                                sm = pred_members.AsyncTaskMethodBuilderSetStateMachine;
 
568
                                task = pred_members.AsyncTaskMethodBuilderTask.Get ();
 
569
                        } else {
 
570
                                builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilderGeneric;
 
571
                                bf = pred_members.AsyncTaskMethodBuilderGenericCreate;
 
572
                                bs = pred_members.AsyncTaskMethodBuilderGenericStart;
 
573
                                sr = pred_members.AsyncTaskMethodBuilderGenericSetResult;
 
574
                                se = pred_members.AsyncTaskMethodBuilderGenericSetException;
 
575
                                sm = pred_members.AsyncTaskMethodBuilderGenericSetStateMachine;
 
576
                                task = pred_members.AsyncTaskMethodBuilderGenericTask.Get ();
 
577
                                has_task_return_type = true;
 
578
                        }
 
579
 
 
580
                        set_result = sr.Get ();
 
581
                        set_exception = se.Get ();
 
582
                        builder_factory = bf.Get ();
 
583
                        builder_start = bs.Get ();
 
584
 
 
585
                        var istate_machine = Module.PredefinedTypes.IAsyncStateMachine;
 
586
                        var set_statemachine = sm.Get ();
 
587
 
 
588
                        if (!builder_type.Define () || !istate_machine.Define () || set_result == null || builder_factory == null ||
 
589
                                set_exception == null || set_statemachine == null || builder_start == null ||
 
590
                                !Module.PredefinedTypes.INotifyCompletion.Define ()) {
 
591
                                Report.Error (1993, Location,
 
592
                                        "Cannot find compiler required types for asynchronous functions support. Are you targeting the wrong framework version?");
 
593
                                return base.DoDefineMembers ();
 
594
                        }
 
595
 
 
596
                        var bt = builder_type.TypeSpec;
 
597
 
 
598
                        //
 
599
                        // Inflate generic Task types
 
600
                        //
 
601
                        if (has_task_return_type) {
 
602
                                var task_return_type = return_type.TypeArguments;
 
603
                                if (mutator != null)
 
604
                                        task_return_type = mutator.Mutate (task_return_type);
 
605
 
 
606
                                bt = bt.MakeGenericType (Module, task_return_type);
 
607
                                set_result = MemberCache.GetMember (bt, set_result);
 
608
                                set_exception = MemberCache.GetMember (bt, set_exception);
 
609
                                set_statemachine = MemberCache.GetMember (bt, set_statemachine);
 
610
 
 
611
                                if (task != null)
 
612
                                        task = MemberCache.GetMember (bt, task);
 
613
                        }
 
614
 
 
615
                        builder = AddCompilerGeneratedField ("$builder", new TypeExpression (bt, Location));
 
616
 
 
617
                        var set_state_machine = new Method (this, new TypeExpression (Compiler.BuiltinTypes.Void, Location),
 
618
                                Modifiers.COMPILER_GENERATED | Modifiers.DEBUGGER_HIDDEN | Modifiers.PUBLIC,
 
619
                                new MemberName ("SetStateMachine"),
 
620
                                ParametersCompiled.CreateFullyResolved (
 
621
                                        new Parameter (new TypeExpression (istate_machine.TypeSpec, Location), "stateMachine", Parameter.Modifier.NONE, null, Location),
 
622
                                        istate_machine.TypeSpec),
 
623
                                null);
 
624
 
 
625
                        ToplevelBlock block = new ToplevelBlock (Compiler, set_state_machine.ParameterInfo, Location);
 
626
                        block.IsCompilerGenerated = true;
 
627
                        set_state_machine.Block = block;
 
628
 
 
629
                        Members.Add (set_state_machine);
 
630
 
 
631
                        if (!base.DoDefineMembers ())
 
632
                                return false;
 
633
 
 
634
                        //
 
635
                        // Fabricates SetStateMachine method
 
636
                        //
 
637
                        // public void SetStateMachine (IAsyncStateMachine stateMachine)
 
638
                        // {
 
639
                        //    $builder.SetStateMachine (stateMachine);
 
640
                        // }
 
641
                        //
 
642
                        var mg = MethodGroupExpr.CreatePredefined (set_statemachine, bt, Location);
 
643
                        mg.InstanceExpression = new FieldExpr (builder, Location);
 
644
 
 
645
                        var param_reference = block.GetParameterReference (0, Location);
 
646
                        param_reference.Type = istate_machine.TypeSpec;
 
647
                        param_reference.eclass = ExprClass.Variable;
 
648
 
 
649
                        var args = new Arguments (1);
 
650
                        args.Add (new Argument (param_reference));
 
651
                        set_state_machine.Block.AddStatement (new StatementExpression (new Invocation (mg, args)));
 
652
 
 
653
                        if (has_task_return_type) {
 
654
                                hoisted_return = LocalVariable.CreateCompilerGenerated (bt.TypeArguments[0], StateMachineMethod.Block, Location);
 
655
                        }
 
656
 
 
657
                        return true;
 
658
                }
 
659
 
 
660
                public void EmitAwaitOnCompletedDynamic (EmitContext ec, FieldExpr awaiter)
 
661
                {
 
662
                        var critical = Module.PredefinedTypes.ICriticalNotifyCompletion;
 
663
                        if (!critical.Define ()) {
 
664
                                throw new NotImplementedException ();
 
665
                        }
 
666
 
 
667
                        var temp_critical = new LocalTemporary (critical.TypeSpec);
 
668
                        var label_critical = ec.DefineLabel ();
 
669
                        var label_end = ec.DefineLabel ();
 
670
 
 
671
                        //
 
672
                        // Special path for dynamic awaiters
 
673
                        //
 
674
                        // var awaiter = this.$awaiter as ICriticalNotifyCompletion;
 
675
                        // if (awaiter == null) {
 
676
                        //    var completion = (INotifyCompletion) this.$awaiter;
 
677
                        //    this.$builder.AwaitOnCompleted (ref completion, ref this);
 
678
                        // } else {
 
679
                        //    this.$builder.AwaitUnsafeOnCompleted (ref awaiter, ref this);
 
680
                        // }
 
681
                        //
 
682
                        awaiter.Emit (ec);
 
683
                        ec.Emit (OpCodes.Isinst, critical.TypeSpec);
 
684
                        temp_critical.Store (ec);
 
685
                        temp_critical.Emit (ec);
 
686
                        ec.Emit (OpCodes.Brtrue_S, label_critical);
 
687
 
 
688
                        var temp = new LocalTemporary (Module.PredefinedTypes.INotifyCompletion.TypeSpec);
 
689
                        awaiter.Emit (ec);
 
690
                        ec.Emit (OpCodes.Castclass, temp.Type);
 
691
                        temp.Store (ec);
 
692
                        EmitOnCompleted (ec, temp, false);
 
693
                        temp.Release (ec);
 
694
                        ec.Emit (OpCodes.Br_S, label_end);
 
695
 
 
696
                        ec.MarkLabel (label_critical);
 
697
 
 
698
                        EmitOnCompleted (ec, temp_critical, true);
 
699
 
 
700
                        ec.MarkLabel (label_end);
 
701
 
 
702
                        temp_critical.Release (ec);
 
703
                }
 
704
 
 
705
                public void EmitAwaitOnCompleted (EmitContext ec, FieldExpr awaiter)
 
706
                {
 
707
                        bool unsafe_version = false;
 
708
                        if (Module.PredefinedTypes.ICriticalNotifyCompletion.Define ()) {
 
709
                                unsafe_version = awaiter.Type.ImplementsInterface (Module.PredefinedTypes.ICriticalNotifyCompletion.TypeSpec, false);
 
710
                        }
 
711
 
 
712
                        EmitOnCompleted (ec, awaiter, unsafe_version);
 
713
                }
 
714
 
 
715
                void EmitOnCompleted (EmitContext ec, Expression awaiter, bool unsafeVersion)
 
716
                {
 
717
                        var pm = Module.PredefinedMembers;
 
718
                        PredefinedMember<MethodSpec> predefined;
 
719
                        bool has_task_return_type = false;
 
720
                        if (return_type.Kind == MemberKind.Void) {
 
721
                                predefined = unsafeVersion ? pm.AsyncVoidMethodBuilderOnCompletedUnsafe : pm.AsyncVoidMethodBuilderOnCompleted;
 
722
                        } else if (return_type == Module.PredefinedTypes.Task.TypeSpec) {
 
723
                                predefined = unsafeVersion ? pm.AsyncTaskMethodBuilderOnCompletedUnsafe : pm.AsyncTaskMethodBuilderOnCompleted;
 
724
                        } else {
 
725
                                predefined = unsafeVersion ? pm.AsyncTaskMethodBuilderGenericOnCompletedUnsafe : pm.AsyncTaskMethodBuilderGenericOnCompleted;
 
726
                                has_task_return_type = true;
 
727
                        }
 
728
 
 
729
                        var on_completed = predefined.Resolve (Location);
 
730
                        if (on_completed == null)
 
731
                                return;
 
732
 
 
733
                        if (has_task_return_type)
 
734
                                on_completed = MemberCache.GetMember<MethodSpec> (set_result.DeclaringType, on_completed);
 
735
 
 
736
                        on_completed = on_completed.MakeGenericMethod (this, awaiter.Type, ec.CurrentType);
 
737
 
 
738
                        var mg = MethodGroupExpr.CreatePredefined (on_completed, on_completed.DeclaringType, Location);
 
739
                        mg.InstanceExpression = new FieldExpr (builder, Location) {
 
740
                                InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location)
 
741
                        };
 
742
 
 
743
                        var args = new Arguments (2);
 
744
                        args.Add (new Argument (awaiter, Argument.AType.Ref));
 
745
                        args.Add (new Argument (new CompilerGeneratedThis (CurrentType, Location), Argument.AType.Ref));
 
746
                        mg.EmitCall (ec, args);
 
747
                }
 
748
 
 
749
                public void EmitInitializer (EmitContext ec)
 
750
                {
 
751
                        //
 
752
                        // Some predefined types are missing
 
753
                        //
 
754
                        if (builder == null)
 
755
                                return;
 
756
 
 
757
                        var instance = (TemporaryVariableReference) Instance;
 
758
                        var builder_field = builder.Spec;
 
759
                        if (MemberName.Arity > 0) {
 
760
                                builder_field = MemberCache.GetMember (instance.Type, builder_field);
 
761
                        }
 
762
 
 
763
                        //
 
764
                        // Inflated factory method when task is of generic type
 
765
                        //
 
766
                        if (builder_factory.DeclaringType.IsGeneric) {
 
767
                                var task_return_type = return_type.TypeArguments;
 
768
                                var bt = builder_factory.DeclaringType.MakeGenericType (Module, task_return_type);
 
769
                                builder_factory = MemberCache.GetMember (bt, builder_factory);
 
770
                                builder_start = MemberCache.GetMember (bt, builder_start);
 
771
                        }
 
772
 
 
773
                        //
 
774
                        // stateMachine.$builder = AsyncTaskMethodBuilder<{task-type}>.Create();
 
775
                        //
 
776
                        instance.AddressOf (ec, AddressOp.Store);
 
777
                        ec.Emit (OpCodes.Call, builder_factory);
 
778
                        ec.Emit (OpCodes.Stfld, builder_field);
 
779
 
 
780
                        //
 
781
                        // stateMachine.$builder.Start<{storey-type}>(ref stateMachine);
 
782
                        //
 
783
                        instance.AddressOf (ec, AddressOp.Store);
 
784
                        ec.Emit (OpCodes.Ldflda, builder_field);
 
785
                        if (Task != null)
 
786
                                ec.Emit (OpCodes.Dup);
 
787
                        instance.AddressOf (ec, AddressOp.Store);
 
788
                        ec.Emit (OpCodes.Call, builder_start.MakeGenericMethod (Module, instance.Type));
 
789
 
 
790
                        //
 
791
                        // Emits return stateMachine.$builder.Task;
 
792
                        //
 
793
                        if (Task != null) {
 
794
                                var task_get = Task.Get;
 
795
 
 
796
                                if (MemberName.Arity > 0) {
 
797
                                        task_get = MemberCache.GetMember (builder_field.MemberType, task_get);
 
798
                                }
 
799
 
 
800
                                var pe_task = new PropertyExpr (Task, Location) {
 
801
                                        InstanceExpression = EmptyExpression.Null,      // Comes from the dup above
 
802
                                        Getter = task_get
 
803
                                };
 
804
 
 
805
                                pe_task.Emit (ec);
 
806
                        }
 
807
                }
 
808
 
 
809
                public void EmitSetException (EmitContext ec, LocalVariableReference exceptionVariable)
 
810
                {
 
811
                        //
 
812
                        // $builder.SetException (Exception)
 
813
                        //
 
814
                        var mg = MethodGroupExpr.CreatePredefined (set_exception, set_exception.DeclaringType, Location);
 
815
                        mg.InstanceExpression = new FieldExpr (builder, Location) {
 
816
                                InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location)
 
817
                        };
 
818
 
 
819
                        Arguments args = new Arguments (1);
 
820
                        args.Add (new Argument (exceptionVariable));
 
821
 
 
822
                        mg.EmitCall (ec, args);
 
823
                }
 
824
 
 
825
                public void EmitSetResult (EmitContext ec)
 
826
                {
 
827
                        //
 
828
                        // $builder.SetResult ();
 
829
                        // $builder.SetResult<return-type> (value);
 
830
                        //
 
831
                        var mg = MethodGroupExpr.CreatePredefined (set_result, set_result.DeclaringType, Location);
 
832
                        mg.InstanceExpression = new FieldExpr (builder, Location) {
 
833
                                InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location)
 
834
                        };
 
835
 
 
836
                        Arguments args;
 
837
                        if (hoisted_return == null) {
 
838
                                args = new Arguments (0);
 
839
                        } else {
 
840
                                args = new Arguments (1);
 
841
                                args.Add (new Argument (new LocalVariableReference (hoisted_return, Location)));
 
842
                        }
 
843
 
 
844
                        mg.EmitCall (ec, args);
 
845
                }
 
846
 
 
847
                protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class)
 
848
                {
 
849
                        base_type = Compiler.BuiltinTypes.ValueType;
 
850
                        base_class = null;
 
851
 
 
852
                        var istate_machine = Module.PredefinedTypes.IAsyncStateMachine;
 
853
                        if (istate_machine.Define ()) {
 
854
                                return new[] { istate_machine.TypeSpec };
 
855
                        }
 
856
 
 
857
                        return null;
 
858
                }
 
859
        }
 
860
 
 
861
        class StackFieldExpr : FieldExpr, IExpressionCleanup
 
862
        {
 
863
                public StackFieldExpr (Field field)
 
864
                        : base (field, Location.Null)
 
865
                {
 
866
                }
 
867
 
 
868
                public override void AddressOf (EmitContext ec, AddressOp mode)
 
869
                {
 
870
                        base.AddressOf (ec, mode);
 
871
 
 
872
                        if (mode == AddressOp.Load) {
 
873
                                var field = (Field) spec.MemberDefinition;
 
874
                                field.IsAvailableForReuse = true;
 
875
                        }
 
876
                }
 
877
 
 
878
                public override void Emit (EmitContext ec)
 
879
                {
 
880
                        base.Emit (ec);
 
881
 
 
882
                        var field = (Field) spec.MemberDefinition;
 
883
                        field.IsAvailableForReuse = true;
 
884
 
 
885
                        //
 
886
                        // Release any captured reference type stack variables
 
887
                        // to imitate real stack behavour and help GC stuff early
 
888
                        //
 
889
                        if (TypeSpec.IsReferenceType (type)) {
 
890
                                ec.AddStatementEpilog (this);
 
891
                        }
 
892
                }
 
893
 
 
894
                void IExpressionCleanup.EmitCleanup (EmitContext ec)
 
895
                {
 
896
                        EmitAssign (ec, new NullConstant (type, loc), false, false);
 
897
                }
 
898
        }
 
899
}