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

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/anonymous.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
// anonymous.cs: Support for anonymous methods and types
 
3
//
 
4
// Author:
 
5
//   Miguel de Icaza (miguel@ximain.com)
 
6
//   Marek Safar (marek.safar@gmail.com)
 
7
//
 
8
// Dual licensed under the terms of the MIT X11 or GNU GPL
 
9
// Copyright 2003-2011 Novell, Inc.
 
10
// Copyright 2011 Xamarin Inc
 
11
//
 
12
 
 
13
using System;
 
14
using System.Collections.Generic;
 
15
using Mono.CompilerServices.SymbolWriter;
 
16
using System.Diagnostics;
 
17
 
 
18
#if STATIC
 
19
using IKVM.Reflection;
 
20
using IKVM.Reflection.Emit;
 
21
using System.Diagnostics;
 
22
#else
 
23
using System.Reflection;
 
24
using System.Reflection.Emit;
 
25
#endif
 
26
 
 
27
namespace Mono.CSharp {
 
28
 
 
29
        public abstract class CompilerGeneratedContainer : ClassOrStruct
 
30
        {
 
31
                protected CompilerGeneratedContainer (TypeContainer parent, MemberName name, Modifiers mod)
 
32
                        : this (parent, name, mod, MemberKind.Class)
 
33
                {
 
34
                }
 
35
 
 
36
                protected CompilerGeneratedContainer (TypeContainer parent, MemberName name, Modifiers mod, MemberKind kind)
 
37
                        : base (parent, name, null, kind)
 
38
                {
 
39
                        Debug.Assert ((mod & Modifiers.AccessibilityMask) != 0);
 
40
 
 
41
                        ModFlags = mod | Modifiers.COMPILER_GENERATED | Modifiers.SEALED;
 
42
                        spec = new TypeSpec (Kind, null, this, null, ModFlags);
 
43
                }
 
44
 
 
45
                protected void CheckMembersDefined ()
 
46
                {
 
47
                        if (HasMembersDefined)
 
48
                                throw new InternalErrorException ("Helper class already defined!");
 
49
                }
 
50
 
 
51
                protected override bool DoDefineMembers ()
 
52
                {
 
53
                        if (Kind == MemberKind.Class && !IsStatic && !PartialContainer.HasInstanceConstructor) {
 
54
                                DefineDefaultConstructor (false);
 
55
                        }
 
56
 
 
57
                        return base.DoDefineMembers ();
 
58
                }
 
59
 
 
60
                protected static MemberName MakeMemberName (MemberBase host, string name, int unique_id, TypeParameters tparams, Location loc)
 
61
                {
 
62
                        string host_name = host == null ? null : host is InterfaceMemberBase ? ((InterfaceMemberBase)host).GetFullName (host.MemberName) : host.MemberName.Name;
 
63
                        string tname = MakeName (host_name, "c", name, unique_id);
 
64
                        TypeParameters args = null;
 
65
                        if (tparams != null) {
 
66
                                args = new TypeParameters (tparams.Count);
 
67
 
 
68
                                // Type parameters will be filled later when we have TypeContainer
 
69
                                // instance, for now we need only correct arity to create valid name
 
70
                                for (int i = 0; i < tparams.Count; ++i)
 
71
                                        args.Add ((TypeParameter) null);
 
72
                        }
 
73
 
 
74
                        return new MemberName (tname, args, loc);
 
75
                }
 
76
 
 
77
                public static string MakeName (string host, string typePrefix, string name, int id)
 
78
                {
 
79
                        return "<" + host + ">" + typePrefix + "__" + name + id.ToString ("X");
 
80
                }
 
81
 
 
82
                protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class)
 
83
                {
 
84
                        base_type = Compiler.BuiltinTypes.Object;
 
85
 
 
86
                        base_class = null;
 
87
                        return null;
 
88
                }
 
89
        }
 
90
 
 
91
        public class HoistedStoreyClass : CompilerGeneratedContainer
 
92
        {
 
93
                public sealed class HoistedField : Field
 
94
                {
 
95
                        public HoistedField (HoistedStoreyClass parent, FullNamedExpression type, Modifiers mod, string name,
 
96
                                  Attributes attrs, Location loc)
 
97
                                : base (parent, type, mod, new MemberName (name, loc), attrs)
 
98
                        {
 
99
                        }
 
100
 
 
101
                        protected override bool ResolveMemberType ()
 
102
                        {
 
103
                                if (!base.ResolveMemberType ())
 
104
                                        return false;
 
105
 
 
106
                                HoistedStoreyClass parent = ((HoistedStoreyClass) Parent).GetGenericStorey ();
 
107
                                if (parent != null && parent.Mutator != null)
 
108
                                        member_type = parent.Mutator.Mutate (MemberType);
 
109
 
 
110
                                return true;
 
111
                        }
 
112
                }
 
113
 
 
114
                protected TypeParameterMutator mutator;
 
115
 
 
116
                public HoistedStoreyClass (TypeDefinition parent, MemberName name, TypeParameters tparams, Modifiers mods, MemberKind kind)
 
117
                        : base (parent, name, mods | Modifiers.PRIVATE, kind)
 
118
                {
 
119
 
 
120
                        if (tparams != null) {
 
121
                                var type_params = name.TypeParameters;
 
122
                                var src = new TypeParameterSpec[tparams.Count];
 
123
                                var dst = new TypeParameterSpec[tparams.Count];
 
124
 
 
125
                                for (int i = 0; i < tparams.Count; ++i) {
 
126
                                        type_params[i] = tparams[i].CreateHoistedCopy (spec);
 
127
 
 
128
                                        src[i] = tparams[i].Type;
 
129
                                        dst[i] = type_params[i].Type;
 
130
                                }
 
131
 
 
132
                                // A copy is not enough, inflate any type parameter constraints
 
133
                                // using a new type parameters
 
134
                                var inflator = new TypeParameterInflator (this, null, src, dst);
 
135
                                for (int i = 0; i < tparams.Count; ++i) {
 
136
                                        src[i].InflateConstraints (inflator, dst[i]);
 
137
                                }
 
138
 
 
139
                                mutator = new TypeParameterMutator (tparams, type_params);
 
140
                        }
 
141
                }
 
142
 
 
143
                #region Properties
 
144
 
 
145
                public TypeParameterMutator Mutator {
 
146
                        get {
 
147
                                return mutator;
 
148
                        }
 
149
                        set {
 
150
                                mutator = value;
 
151
                        }
 
152
                }
 
153
 
 
154
                #endregion
 
155
 
 
156
                public HoistedStoreyClass GetGenericStorey ()
 
157
                {
 
158
                        TypeContainer storey = this;
 
159
                        while (storey != null && storey.CurrentTypeParameters == null)
 
160
                                storey = storey.Parent;
 
161
 
 
162
                        return storey as HoistedStoreyClass;
 
163
                }
 
164
        }
 
165
 
 
166
 
 
167
        //
 
168
        // Anonymous method storey is created when an anonymous method uses
 
169
        // variable or parameter from outer scope. They are then hoisted to
 
170
        // anonymous method storey (captured)
 
171
        //
 
172
        public class AnonymousMethodStorey : HoistedStoreyClass
 
173
        {
 
174
                struct StoreyFieldPair
 
175
                {
 
176
                        public readonly AnonymousMethodStorey Storey;
 
177
                        public readonly Field Field;
 
178
 
 
179
                        public StoreyFieldPair (AnonymousMethodStorey storey, Field field)
 
180
                        {
 
181
                                this.Storey = storey;
 
182
                                this.Field = field;
 
183
                        }
 
184
                }
 
185
 
 
186
                //
 
187
                // Needed to delay hoisted _this_ initialization. When an anonymous
 
188
                // method is used inside ctor and _this_ is hoisted, base ctor has to
 
189
                // be called first, otherwise _this_ will be initialized with 
 
190
                // uninitialized value.
 
191
                //
 
192
                sealed class ThisInitializer : Statement
 
193
                {
 
194
                        readonly HoistedThis hoisted_this;
 
195
 
 
196
                        public ThisInitializer (HoistedThis hoisted_this)
 
197
                        {
 
198
                                this.hoisted_this = hoisted_this;
 
199
                        }
 
200
 
 
201
                        protected override void DoEmit (EmitContext ec)
 
202
                        {
 
203
                                hoisted_this.EmitAssign (ec, new CompilerGeneratedThis (ec.CurrentType, loc), false, false);
 
204
                        }
 
205
 
 
206
                        protected override void CloneTo (CloneContext clonectx, Statement target)
 
207
                        {
 
208
                                // Nothing to clone
 
209
                        }
 
210
                }
 
211
 
 
212
                // Unique storey ID
 
213
                public readonly int ID;
 
214
 
 
215
                public readonly ExplicitBlock OriginalSourceBlock;
 
216
 
 
217
                // A list of StoreyFieldPair with local field keeping parent storey instance
 
218
                List<StoreyFieldPair> used_parent_storeys;
 
219
                List<ExplicitBlock> children_references;
 
220
 
 
221
                // A list of hoisted parameters
 
222
                protected List<HoistedParameter> hoisted_params;
 
223
                List<HoistedParameter> hoisted_local_params;
 
224
                protected List<HoistedVariable> hoisted_locals;
 
225
 
 
226
                // Hoisted this
 
227
                protected HoistedThis hoisted_this;
 
228
 
 
229
                // Local variable which holds this storey instance
 
230
                public Expression Instance;
 
231
 
 
232
                bool initialize_hoisted_this;
 
233
 
 
234
                public AnonymousMethodStorey (ExplicitBlock block, TypeDefinition parent, MemberBase host, TypeParameters tparams, string name, MemberKind kind)
 
235
                        : base (parent, MakeMemberName (host, name, parent.Module.CounterAnonymousContainers, tparams, block.StartLocation),
 
236
                                tparams, 0, kind)
 
237
                {
 
238
                        OriginalSourceBlock = block;
 
239
                        ID = parent.Module.CounterAnonymousContainers++;
 
240
                }
 
241
 
 
242
                public void AddCapturedThisField (EmitContext ec)
 
243
                {
 
244
                        TypeExpr type_expr = new TypeExpression (ec.CurrentType, Location);
 
245
                        Field f = AddCompilerGeneratedField ("$this", type_expr);
 
246
                        hoisted_this = new HoistedThis (this, f);
 
247
 
 
248
                        initialize_hoisted_this = true;
 
249
                }
 
250
 
 
251
                public Field AddCapturedVariable (string name, TypeSpec type)
 
252
                {
 
253
                        CheckMembersDefined ();
 
254
 
 
255
                        FullNamedExpression field_type = new TypeExpression (type, Location);
 
256
                        if (!spec.IsGenericOrParentIsGeneric)
 
257
                                return AddCompilerGeneratedField (name, field_type);
 
258
 
 
259
                        const Modifiers mod = Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED;
 
260
                        Field f = new HoistedField (this, field_type, mod, name, null, Location);
 
261
                        AddField (f);
 
262
                        return f;
 
263
                }
 
264
 
 
265
                protected Field AddCompilerGeneratedField (string name, FullNamedExpression type)
 
266
                {
 
267
                        return AddCompilerGeneratedField (name, type, false);
 
268
                }
 
269
 
 
270
                protected Field AddCompilerGeneratedField (string name, FullNamedExpression type, bool privateAccess)
 
271
                {
 
272
                        Modifiers mod = Modifiers.COMPILER_GENERATED | (privateAccess ? Modifiers.PRIVATE : Modifiers.INTERNAL);
 
273
                        Field f = new Field (this, type, mod, new MemberName (name, Location), null);
 
274
                        AddField (f);
 
275
                        return f;
 
276
                }
 
277
 
 
278
                //
 
279
                // Creates a link between hoisted variable block and the anonymous method storey
 
280
                //
 
281
                // An anonymous method can reference variables from any outer block, but they are
 
282
                // hoisted in their own ExplicitBlock. When more than one block is referenced we
 
283
                // need to create another link between those variable storeys
 
284
                //
 
285
                public void AddReferenceFromChildrenBlock (ExplicitBlock block)
 
286
                {
 
287
                        if (children_references == null)
 
288
                                children_references = new List<ExplicitBlock> ();
 
289
 
 
290
                        if (!children_references.Contains (block))
 
291
                                children_references.Add (block);
 
292
                }
 
293
 
 
294
                public void AddParentStoreyReference (EmitContext ec, AnonymousMethodStorey storey)
 
295
                {
 
296
                        CheckMembersDefined ();
 
297
 
 
298
                        if (used_parent_storeys == null)
 
299
                                used_parent_storeys = new List<StoreyFieldPair> ();
 
300
                        else if (used_parent_storeys.Exists (i => i.Storey == storey))
 
301
                                return;
 
302
 
 
303
                        TypeExpr type_expr = storey.CreateStoreyTypeExpression (ec);
 
304
                        Field f = AddCompilerGeneratedField ("<>f__ref$" + storey.ID, type_expr);
 
305
                        used_parent_storeys.Add (new StoreyFieldPair (storey, f));
 
306
                }
 
307
 
 
308
                public void CaptureLocalVariable (ResolveContext ec, LocalVariable localVariable)
 
309
                {
 
310
                        if (this is StateMachine) {
 
311
                                if (ec.CurrentBlock.ParametersBlock != localVariable.Block.ParametersBlock)
 
312
                                        ec.CurrentBlock.Explicit.HasCapturedVariable = true;
 
313
                        } else {
 
314
                                ec.CurrentBlock.Explicit.HasCapturedVariable = true;
 
315
                        }
 
316
 
 
317
                        var hoisted = localVariable.HoistedVariant;
 
318
                        if (hoisted != null && hoisted.Storey != this && hoisted.Storey is StateMachine) {
 
319
                                // TODO: It's too late the field is defined in HoistedLocalVariable ctor
 
320
                                hoisted.Storey.hoisted_locals.Remove (hoisted);
 
321
                                hoisted = null;
 
322
                        }
 
323
 
 
324
                        if (hoisted == null) {
 
325
                                hoisted = new HoistedLocalVariable (this, localVariable, GetVariableMangledName (localVariable));
 
326
                                localVariable.HoistedVariant = hoisted;
 
327
 
 
328
                                if (hoisted_locals == null)
 
329
                                        hoisted_locals = new List<HoistedVariable> ();
 
330
 
 
331
                                hoisted_locals.Add (hoisted);
 
332
                        }
 
333
 
 
334
                        if (ec.CurrentBlock.Explicit != localVariable.Block.Explicit && !(hoisted.Storey is StateMachine))
 
335
                                hoisted.Storey.AddReferenceFromChildrenBlock (ec.CurrentBlock.Explicit);
 
336
                }
 
337
 
 
338
                public void CaptureParameter (ResolveContext ec, ParametersBlock.ParameterInfo parameterInfo, ParameterReference parameterReference)
 
339
                {
 
340
                        if (!(this is StateMachine)) {
 
341
                                ec.CurrentBlock.Explicit.HasCapturedVariable = true;
 
342
                        }
 
343
 
 
344
                        var hoisted = parameterInfo.Parameter.HoistedVariant;
 
345
 
 
346
                        if (parameterInfo.Block.StateMachine != null) {
 
347
                                //
 
348
                                // Another storey in same block exists but state machine does not
 
349
                                // have parameter captured. We need to add it there as well to
 
350
                                // proxy parameter value correctly.
 
351
                                //
 
352
                                if (hoisted == null && parameterInfo.Block.StateMachine != this) {
 
353
                                        var storey = parameterInfo.Block.StateMachine;
 
354
 
 
355
                                        hoisted = new HoistedParameter (storey, parameterReference);
 
356
                                        parameterInfo.Parameter.HoistedVariant = hoisted;
 
357
 
 
358
                                        if (storey.hoisted_params == null)
 
359
                                                storey.hoisted_params = new List<HoistedParameter> ();
 
360
 
 
361
                                        storey.hoisted_params.Add (hoisted);
 
362
                                }
 
363
 
 
364
                                //
 
365
                                // Lift captured parameter from value type storey to reference type one. Otherwise
 
366
                                // any side effects would be done on a copy
 
367
                                //
 
368
                                if (hoisted != null && hoisted.Storey != this && hoisted.Storey is StateMachine) {
 
369
                                        if (hoisted_local_params == null)
 
370
                                                hoisted_local_params = new List<HoistedParameter> ();
 
371
 
 
372
                                        hoisted_local_params.Add (hoisted);
 
373
                                        hoisted = null;
 
374
                                }
 
375
                        }
 
376
 
 
377
                        if (hoisted == null) {
 
378
                                hoisted = new HoistedParameter (this, parameterReference);
 
379
                                parameterInfo.Parameter.HoistedVariant = hoisted;
 
380
 
 
381
                                if (hoisted_params == null)
 
382
                                        hoisted_params = new List<HoistedParameter> ();
 
383
 
 
384
                                hoisted_params.Add (hoisted);
 
385
                        }
 
386
 
 
387
                        //
 
388
                        // Register link between current block and parameter storey. It will
 
389
                        // be used when setting up storey definition to deploy storey reference
 
390
                        // when parameters are used from multiple blocks
 
391
                        //
 
392
                        if (ec.CurrentBlock.Explicit != parameterInfo.Block) {
 
393
                                hoisted.Storey.AddReferenceFromChildrenBlock (ec.CurrentBlock.Explicit);
 
394
                        }
 
395
                }
 
396
 
 
397
                TypeExpr CreateStoreyTypeExpression (EmitContext ec)
 
398
                {
 
399
                        //
 
400
                        // Create an instance of storey type
 
401
                        //
 
402
                        TypeExpr storey_type_expr;
 
403
                        if (CurrentTypeParameters != null) {
 
404
                                //
 
405
                                // Use current method type parameter (MVAR) for top level storey only. All
 
406
                                // nested storeys use class type parameter (VAR)
 
407
                                //
 
408
                                var tparams = ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null ?
 
409
                                        ec.CurrentAnonymousMethod.Storey.CurrentTypeParameters :
 
410
                                        ec.CurrentTypeParameters;
 
411
 
 
412
                                TypeArguments targs = new TypeArguments ();
 
413
 
 
414
                                //
 
415
                                // Use type parameter name instead of resolved type parameter
 
416
                                // specification to resolve to correctly nested type parameters
 
417
                                //
 
418
                                for (int i = 0; i < tparams.Count; ++i)
 
419
                                        targs.Add (new SimpleName (tparams [i].Name, Location)); //  new TypeParameterExpr (tparams[i], Location));
 
420
 
 
421
                                storey_type_expr = new GenericTypeExpr (Definition, targs, Location);
 
422
                        } else {
 
423
                                storey_type_expr = new TypeExpression (CurrentType, Location);
 
424
                        }
 
425
 
 
426
                        return storey_type_expr;
 
427
                }
 
428
 
 
429
                public void SetNestedStoryParent (AnonymousMethodStorey parentStorey)
 
430
                {
 
431
                        Parent = parentStorey;
 
432
                        spec.IsGeneric = false;
 
433
                        spec.DeclaringType = parentStorey.CurrentType;
 
434
                        MemberName.TypeParameters = null;
 
435
                }
 
436
 
 
437
                protected override bool DoResolveTypeParameters ()
 
438
                {
 
439
                        // Although any storey can have type parameters they are all clones of method type
 
440
                        // parameters therefore have to mutate MVAR references in any of cloned constraints
 
441
                        if (CurrentTypeParameters != null) {
 
442
                                for (int i = 0; i < CurrentTypeParameters.Count; ++i) {
 
443
                                        var spec = CurrentTypeParameters[i].Type;
 
444
                                        spec.BaseType = mutator.Mutate (spec.BaseType);
 
445
                                        if (spec.InterfacesDefined != null) {
 
446
                                                var mutated = new TypeSpec[spec.InterfacesDefined.Length];
 
447
                                                for (int ii = 0; ii < mutated.Length; ++ii) {
 
448
                                                        mutated[ii] = mutator.Mutate (spec.InterfacesDefined[ii]);
 
449
                                                }
 
450
 
 
451
                                                spec.InterfacesDefined = mutated;
 
452
                                        }
 
453
 
 
454
                                        if (spec.TypeArguments != null) {
 
455
                                                spec.TypeArguments = mutator.Mutate (spec.TypeArguments);
 
456
                                        }
 
457
                                }
 
458
                        }
 
459
 
 
460
                        //
 
461
                        // Update parent cache as we most likely passed the point
 
462
                        // where the cache was constructed
 
463
                        //
 
464
                        Parent.CurrentType.MemberCache.AddMember (this.spec);
 
465
 
 
466
                        return true;
 
467
                }
 
468
 
 
469
                //
 
470
                // Initializes all hoisted variables
 
471
                //
 
472
                public void EmitStoreyInstantiation (EmitContext ec, ExplicitBlock block)
 
473
                {
 
474
                        // There can be only one instance variable for each storey type
 
475
                        if (Instance != null)
 
476
                                throw new InternalErrorException ();
 
477
 
 
478
                        //
 
479
                        // Create an instance of this storey
 
480
                        //
 
481
                        ResolveContext rc = new ResolveContext (ec.MemberContext);
 
482
                        rc.CurrentBlock = block;
 
483
 
 
484
                        var storey_type_expr = CreateStoreyTypeExpression (ec);
 
485
                        var source = new New (storey_type_expr, null, Location).Resolve (rc);
 
486
 
 
487
                        //
 
488
                        // When the current context is async (or iterator) lift local storey
 
489
                        // instantiation to the currect storey
 
490
                        //
 
491
                        if (ec.CurrentAnonymousMethod is StateMachineInitializer && (block.HasYield || block.HasAwait)) {
 
492
                                //
 
493
                                // Unfortunately, normal capture mechanism could not be used because we are
 
494
                                // too late in the pipeline and standart assign cannot be used either due to
 
495
                                // recursive nature of GetStoreyInstanceExpression
 
496
                                //
 
497
                                var field = ec.CurrentAnonymousMethod.Storey.AddCompilerGeneratedField (
 
498
                                        LocalVariable.GetCompilerGeneratedName (block), storey_type_expr, true);
 
499
 
 
500
                                field.Define ();
 
501
                                field.Emit ();
 
502
 
 
503
                                var fexpr = new FieldExpr (field, Location);
 
504
                                fexpr.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location);
 
505
                                fexpr.EmitAssign (ec, source, false, false);
 
506
                                Instance = fexpr;
 
507
                        } else {
 
508
                                var local = TemporaryVariableReference.Create (source.Type, block, Location);
 
509
                                if (source.Type.IsStruct) {
 
510
                                        local.LocalInfo.CreateBuilder (ec);
 
511
                                } else {
 
512
                                        local.EmitAssign (ec, source);
 
513
                                }
 
514
 
 
515
                                Instance = local;
 
516
                        }
 
517
 
 
518
                        EmitHoistedFieldsInitialization (rc, ec);
 
519
 
 
520
                        // TODO: Implement properly
 
521
                        //SymbolWriter.DefineScopeVariable (ID, Instance.Builder);
 
522
                }
 
523
 
 
524
                void EmitHoistedFieldsInitialization (ResolveContext rc, EmitContext ec)
 
525
                {
 
526
                        //
 
527
                        // Initialize all storey reference fields by using local or hoisted variables
 
528
                        //
 
529
                        if (used_parent_storeys != null) {
 
530
                                foreach (StoreyFieldPair sf in used_parent_storeys) {
 
531
                                        //
 
532
                                        // Get instance expression of storey field
 
533
                                        //
 
534
                                        Expression instace_expr = GetStoreyInstanceExpression (ec);
 
535
                                        var fs = sf.Field.Spec;
 
536
                                        if (TypeManager.IsGenericType (instace_expr.Type))
 
537
                                                fs = MemberCache.GetMember (instace_expr.Type, fs);
 
538
 
 
539
                                        FieldExpr f_set_expr = new FieldExpr (fs, Location);
 
540
                                        f_set_expr.InstanceExpression = instace_expr;
 
541
 
 
542
                                        // TODO: CompilerAssign expression
 
543
                                        SimpleAssign a = new SimpleAssign (f_set_expr, sf.Storey.GetStoreyInstanceExpression (ec));
 
544
                                        if (a.Resolve (rc) != null)
 
545
                                                a.EmitStatement (ec);
 
546
                                }
 
547
                        }
 
548
 
 
549
                        //
 
550
                        // Initialize hoisted `this' only once, everywhere else will be
 
551
                        // referenced indirectly
 
552
                        //
 
553
                        if (initialize_hoisted_this) {
 
554
                                rc.CurrentBlock.AddScopeStatement (new ThisInitializer (hoisted_this));
 
555
                        }
 
556
 
 
557
                        //
 
558
                        // Setting currect anonymous method to null blocks any further variable hoisting
 
559
                        //
 
560
                        AnonymousExpression ae = ec.CurrentAnonymousMethod;
 
561
                        ec.CurrentAnonymousMethod = null;
 
562
 
 
563
                        if (hoisted_params != null) {
 
564
                                EmitHoistedParameters (ec, hoisted_params);
 
565
                        }
 
566
 
 
567
                        ec.CurrentAnonymousMethod = ae;
 
568
                }
 
569
 
 
570
                protected virtual void EmitHoistedParameters (EmitContext ec, List<HoistedParameter> hoisted)
 
571
                {
 
572
                        foreach (HoistedParameter hp in hoisted) {
 
573
                                //
 
574
                                // Parameters could be proxied via local fields for value type storey
 
575
                                //
 
576
                                if (hoisted_local_params != null) {
 
577
                                        var local_param = hoisted_local_params.Find (l => l.Parameter.Parameter == hp.Parameter.Parameter);
 
578
                                        var source = new FieldExpr (local_param.Field, Location);
 
579
                                        source.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location);
 
580
                                        hp.EmitAssign (ec, source, false, false);
 
581
                                        continue;
 
582
                                }
 
583
 
 
584
                                hp.EmitHoistingAssignment (ec);
 
585
                        }
 
586
                }
 
587
 
 
588
                //
 
589
                // Returns a field which holds referenced storey instance
 
590
                //
 
591
                Field GetReferencedStoreyField (AnonymousMethodStorey storey)
 
592
                {
 
593
                        if (used_parent_storeys == null)
 
594
                                return null;
 
595
 
 
596
                        foreach (StoreyFieldPair sf in used_parent_storeys) {
 
597
                                if (sf.Storey == storey)
 
598
                                        return sf.Field;
 
599
                        }
 
600
 
 
601
                        return null;
 
602
                }
 
603
 
 
604
                //
 
605
                // Creates storey instance expression regardless of currect IP
 
606
                //
 
607
                public Expression GetStoreyInstanceExpression (EmitContext ec)
 
608
                {
 
609
                        AnonymousExpression am = ec.CurrentAnonymousMethod;
 
610
 
 
611
                        //
 
612
                        // Access from original block -> storey
 
613
                        //
 
614
                        if (am == null)
 
615
                                return Instance;
 
616
 
 
617
                        //
 
618
                        // Access from anonymous method implemented as a static -> storey
 
619
                        //
 
620
                        if (am.Storey == null)
 
621
                                return Instance;
 
622
 
 
623
                        Field f = am.Storey.GetReferencedStoreyField (this);
 
624
                        if (f == null) {
 
625
                                if (am.Storey == this) {
 
626
                                        //
 
627
                                        // Access from inside of same storey (S -> S)
 
628
                                        //
 
629
                                        return new CompilerGeneratedThis (CurrentType, Location);
 
630
                                }
 
631
 
 
632
                                //
 
633
                                // External field access
 
634
                                //
 
635
                                return Instance;
 
636
                        }
 
637
 
 
638
                        //
 
639
                        // Storey was cached to local field
 
640
                        //
 
641
                        FieldExpr f_ind = new FieldExpr (f, Location);
 
642
                        f_ind.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location);
 
643
                        return f_ind;
 
644
                }
 
645
 
 
646
                protected virtual string GetVariableMangledName (LocalVariable local_info)
 
647
                {
 
648
                        //
 
649
                        // No need to mangle anonymous method hoisted variables cause they
 
650
                        // are hoisted in their own scopes
 
651
                        //
 
652
                        return local_info.Name;
 
653
                }
 
654
 
 
655
                public HoistedThis HoistedThis {
 
656
                        get {
 
657
                                return hoisted_this;
 
658
                        }
 
659
                        set {
 
660
                                hoisted_this = value;
 
661
                        }
 
662
                }
 
663
 
 
664
                public IList<ExplicitBlock> ReferencesFromChildrenBlock {
 
665
                        get { return children_references; }
 
666
                }
 
667
        }
 
668
 
 
669
        public abstract class HoistedVariable
 
670
        {
 
671
                //
 
672
                // Hoisted version of variable references used in expression
 
673
                // tree has to be delayed until we know its location. The variable
 
674
                // doesn't know its location until all stories are calculated
 
675
                //
 
676
                class ExpressionTreeVariableReference : Expression
 
677
                {
 
678
                        readonly HoistedVariable hv;
 
679
 
 
680
                        public ExpressionTreeVariableReference (HoistedVariable hv)
 
681
                        {
 
682
                                this.hv = hv;
 
683
                        }
 
684
 
 
685
                        public override bool ContainsEmitWithAwait ()
 
686
                        {
 
687
                                return false;
 
688
                        }
 
689
 
 
690
                        public override Expression CreateExpressionTree (ResolveContext ec)
 
691
                        {
 
692
                                return hv.CreateExpressionTree ();
 
693
                        }
 
694
 
 
695
                        protected override Expression DoResolve (ResolveContext ec)
 
696
                        {
 
697
                                eclass = ExprClass.Value;
 
698
                                type = ec.Module.PredefinedTypes.Expression.Resolve ();
 
699
                                return this;
 
700
                        }
 
701
 
 
702
                        public override void Emit (EmitContext ec)
 
703
                        {
 
704
                                ResolveContext rc = new ResolveContext (ec.MemberContext);
 
705
                                Expression e = hv.GetFieldExpression (ec).CreateExpressionTree (rc, false);
 
706
                                // This should never fail
 
707
                                e = e.Resolve (rc);
 
708
                                if (e != null)
 
709
                                        e.Emit (ec);
 
710
                        }
 
711
                }
 
712
        
 
713
                protected readonly AnonymousMethodStorey storey;
 
714
                protected Field field;
 
715
                Dictionary<AnonymousExpression, FieldExpr> cached_inner_access; // TODO: Hashtable is too heavyweight
 
716
                FieldExpr cached_outer_access;
 
717
 
 
718
                protected HoistedVariable (AnonymousMethodStorey storey, string name, TypeSpec type)
 
719
                        : this (storey, storey.AddCapturedVariable (name, type))
 
720
                {
 
721
                }
 
722
 
 
723
                protected HoistedVariable (AnonymousMethodStorey storey, Field field)
 
724
                {
 
725
                        this.storey = storey;
 
726
                        this.field = field;
 
727
                }
 
728
 
 
729
                public AnonymousMethodStorey Storey {
 
730
                        get {
 
731
                                return storey;
 
732
                        }
 
733
                }
 
734
 
 
735
                public void AddressOf (EmitContext ec, AddressOp mode)
 
736
                {
 
737
                        GetFieldExpression (ec).AddressOf (ec, mode);
 
738
                }
 
739
 
 
740
                public Expression CreateExpressionTree ()
 
741
                {
 
742
                        return new ExpressionTreeVariableReference (this);
 
743
                }
 
744
 
 
745
                public void Emit (EmitContext ec)
 
746
                {
 
747
                        GetFieldExpression (ec).Emit (ec);
 
748
                }
 
749
 
 
750
                public Expression EmitToField (EmitContext ec)
 
751
                {
 
752
                        return GetFieldExpression (ec);
 
753
                }
 
754
 
 
755
                //
 
756
                // Creates field access expression for hoisted variable
 
757
                //
 
758
                protected virtual FieldExpr GetFieldExpression (EmitContext ec)
 
759
                {
 
760
                        if (ec.CurrentAnonymousMethod == null || ec.CurrentAnonymousMethod.Storey == null) {
 
761
                                if (cached_outer_access != null)
 
762
                                        return cached_outer_access;
 
763
 
 
764
                                //
 
765
                                // When setting top-level hoisted variable in generic storey
 
766
                                // change storey generic types to method generic types (VAR -> MVAR)
 
767
                                //
 
768
                                if (storey.Instance.Type.IsGenericOrParentIsGeneric) {
 
769
                                        var fs = MemberCache.GetMember (storey.Instance.Type, field.Spec);
 
770
                                        cached_outer_access = new FieldExpr (fs, field.Location);
 
771
                                } else {
 
772
                                        cached_outer_access = new FieldExpr (field, field.Location);
 
773
                                }
 
774
 
 
775
                                cached_outer_access.InstanceExpression = storey.GetStoreyInstanceExpression (ec);
 
776
                                return cached_outer_access;
 
777
                        }
 
778
 
 
779
                        FieldExpr inner_access;
 
780
                        if (cached_inner_access != null) {
 
781
                                if (!cached_inner_access.TryGetValue (ec.CurrentAnonymousMethod, out inner_access))
 
782
                                        inner_access = null;
 
783
                        } else {
 
784
                                inner_access = null;
 
785
                                cached_inner_access = new Dictionary<AnonymousExpression, FieldExpr> (4);
 
786
                        }
 
787
 
 
788
                        if (inner_access == null) {
 
789
                                if (field.Parent.IsGenericOrParentIsGeneric) {
 
790
                                        var fs = MemberCache.GetMember (field.Parent.CurrentType, field.Spec);
 
791
                                        inner_access = new FieldExpr (fs, field.Location);
 
792
                                } else {
 
793
                                        inner_access = new FieldExpr (field, field.Location);
 
794
                                }
 
795
 
 
796
                                inner_access.InstanceExpression = storey.GetStoreyInstanceExpression (ec);
 
797
                                cached_inner_access.Add (ec.CurrentAnonymousMethod, inner_access);
 
798
                        }
 
799
 
 
800
                        return inner_access;
 
801
                }
 
802
 
 
803
                public void Emit (EmitContext ec, bool leave_copy)
 
804
                {
 
805
                        GetFieldExpression (ec).Emit (ec, leave_copy);
 
806
                }
 
807
 
 
808
                public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
 
809
                {
 
810
                        GetFieldExpression (ec).EmitAssign (ec, source, leave_copy, false);
 
811
                }
 
812
        }
 
813
 
 
814
        public class HoistedParameter : HoistedVariable
 
815
        {
 
816
                sealed class HoistedFieldAssign : CompilerAssign
 
817
                {
 
818
                        public HoistedFieldAssign (Expression target, Expression source)
 
819
                                : base (target, source, target.Location)
 
820
                        {
 
821
                        }
 
822
 
 
823
                        protected override Expression ResolveConversions (ResolveContext ec)
 
824
                        {
 
825
                                //
 
826
                                // Implicit conversion check fails for hoisted type arguments
 
827
                                // as they are of different types (!!0 x !0)
 
828
                                //
 
829
                                return this;
 
830
                        }
 
831
                }
 
832
 
 
833
                readonly ParameterReference parameter;
 
834
 
 
835
                public HoistedParameter (AnonymousMethodStorey scope, ParameterReference par)
 
836
                        : base (scope, par.Name, par.Type)
 
837
                {
 
838
                        this.parameter = par;
 
839
                }
 
840
 
 
841
                public HoistedParameter (HoistedParameter hp, string name)
 
842
                        : base (hp.storey, name, hp.parameter.Type)
 
843
                {
 
844
                        this.parameter = hp.parameter;
 
845
                }
 
846
 
 
847
                #region Properties
 
848
 
 
849
                public Field Field {
 
850
                        get {
 
851
                                return field;
 
852
                        }
 
853
                }
 
854
 
 
855
                public ParameterReference Parameter {
 
856
                        get {
 
857
                                return parameter;
 
858
                        }
 
859
                }
 
860
 
 
861
                #endregion
 
862
 
 
863
                public void EmitHoistingAssignment (EmitContext ec)
 
864
                {
 
865
                        //
 
866
                        // Remove hoisted redirection to emit assignment from original parameter
 
867
                        //
 
868
                        var temp = parameter.Parameter.HoistedVariant;
 
869
                        parameter.Parameter.HoistedVariant = null;
 
870
 
 
871
                        var a = new HoistedFieldAssign (GetFieldExpression (ec), parameter);
 
872
                        a.EmitStatement (ec);
 
873
 
 
874
                        parameter.Parameter.HoistedVariant = temp;
 
875
                }
 
876
        }
 
877
 
 
878
        class HoistedLocalVariable : HoistedVariable
 
879
        {
 
880
                public HoistedLocalVariable (AnonymousMethodStorey storey, LocalVariable local, string name)
 
881
                        : base (storey, name, local.Type)
 
882
                {
 
883
                }
 
884
        }
 
885
 
 
886
        public class HoistedThis : HoistedVariable
 
887
        {
 
888
                public HoistedThis (AnonymousMethodStorey storey, Field field)
 
889
                        : base (storey, field)
 
890
                {
 
891
                }
 
892
 
 
893
                public Field Field {
 
894
                        get {
 
895
                                return field;
 
896
                        }
 
897
                }
 
898
        }
 
899
 
 
900
        //
 
901
        // Anonymous method expression as created by parser
 
902
        //
 
903
        public class AnonymousMethodExpression : Expression
 
904
        {
 
905
                //
 
906
                // Special conversion for nested expression tree lambdas
 
907
                //
 
908
                class Quote : ShimExpression
 
909
                {
 
910
                        public Quote (Expression expr)
 
911
                                : base (expr)
 
912
                        {
 
913
                        }
 
914
 
 
915
                        public override Expression CreateExpressionTree (ResolveContext ec)
 
916
                        {
 
917
                                var args = new Arguments (1);
 
918
                                args.Add (new Argument (expr.CreateExpressionTree (ec)));
 
919
                                return CreateExpressionFactoryCall (ec, "Quote", args);
 
920
                        }
 
921
 
 
922
                        protected override Expression DoResolve (ResolveContext rc)
 
923
                        {
 
924
                                expr = expr.Resolve (rc);
 
925
                                if (expr == null)
 
926
                                        return null;
 
927
 
 
928
                                eclass = expr.eclass;
 
929
                                type = expr.Type;
 
930
                                return this;
 
931
                        }
 
932
                }
 
933
 
 
934
                readonly Dictionary<TypeSpec, Expression> compatibles;
 
935
 
 
936
                public ParametersBlock Block;
 
937
 
 
938
                public AnonymousMethodExpression (Location loc)
 
939
                {
 
940
                        this.loc = loc;
 
941
                        this.compatibles = new Dictionary<TypeSpec, Expression> ();
 
942
                }
 
943
 
 
944
                #region Properties
 
945
 
 
946
                public override string ExprClassName {
 
947
                        get {
 
948
                                return "anonymous method";
 
949
                        }
 
950
                }
 
951
 
 
952
                public virtual bool HasExplicitParameters {
 
953
                        get {
 
954
                                return Parameters != ParametersCompiled.Undefined;
 
955
                        }
 
956
                }
 
957
 
 
958
                public ParametersCompiled Parameters {
 
959
                        get {
 
960
                                return Block.Parameters;
 
961
                        }
 
962
                }
 
963
 
 
964
                public bool IsAsync {
 
965
                        get;
 
966
                        internal set;
 
967
                }
 
968
 
 
969
                public ReportPrinter TypeInferenceReportPrinter {
 
970
                        get; set;
 
971
                }
 
972
 
 
973
                #endregion
 
974
 
 
975
                //
 
976
                // Returns true if the body of lambda expression can be implicitly
 
977
                // converted to the delegate of type `delegate_type'
 
978
                //
 
979
                public bool ImplicitStandardConversionExists (ResolveContext ec, TypeSpec delegate_type)
 
980
                {
 
981
                        using (ec.With (ResolveContext.Options.InferReturnType, false)) {
 
982
                                using (ec.Set (ResolveContext.Options.ProbingMode)) {
 
983
                                        var prev = ec.Report.SetPrinter (TypeInferenceReportPrinter ?? new NullReportPrinter ());
 
984
 
 
985
                                        var res = Compatible (ec, delegate_type) != null;
 
986
 
 
987
                                        ec.Report.SetPrinter (prev);
 
988
 
 
989
                                        return res;
 
990
                                }
 
991
                        }
 
992
                }
 
993
 
 
994
                TypeSpec CompatibleChecks (ResolveContext ec, TypeSpec delegate_type)
 
995
                {
 
996
                        if (delegate_type.IsDelegate)
 
997
                                return delegate_type;
 
998
 
 
999
                        if (delegate_type.IsExpressionTreeType) {
 
1000
                                delegate_type = delegate_type.TypeArguments [0];
 
1001
                                if (delegate_type.IsDelegate)
 
1002
                                        return delegate_type;
 
1003
 
 
1004
                                ec.Report.Error (835, loc, "Cannot convert `{0}' to an expression tree of non-delegate type `{1}'",
 
1005
                                        GetSignatureForError (), TypeManager.CSharpName (delegate_type));
 
1006
                                return null;
 
1007
                        }
 
1008
 
 
1009
                        ec.Report.Error (1660, loc, "Cannot convert `{0}' to non-delegate type `{1}'",
 
1010
                                      GetSignatureForError (), TypeManager.CSharpName (delegate_type));
 
1011
                        return null;
 
1012
                }
 
1013
 
 
1014
                protected bool VerifyExplicitParameters (ResolveContext ec, TypeSpec delegate_type, AParametersCollection parameters)
 
1015
                {
 
1016
                        if (VerifyParameterCompatibility (ec, delegate_type, parameters, ec.IsInProbingMode))
 
1017
                                return true;
 
1018
 
 
1019
                        if (!ec.IsInProbingMode)
 
1020
                                ec.Report.Error (1661, loc,
 
1021
                                        "Cannot convert `{0}' to delegate type `{1}' since there is a parameter mismatch",
 
1022
                                        GetSignatureForError (), TypeManager.CSharpName (delegate_type));
 
1023
 
 
1024
                        return false;
 
1025
                }
 
1026
 
 
1027
                protected bool VerifyParameterCompatibility (ResolveContext ec, TypeSpec delegate_type, AParametersCollection invoke_pd, bool ignore_errors)
 
1028
                {
 
1029
                        if (Parameters.Count != invoke_pd.Count) {
 
1030
                                if (ignore_errors)
 
1031
                                        return false;
 
1032
                                
 
1033
                                ec.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
 
1034
                                              TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
 
1035
                                return false;
 
1036
                        }
 
1037
 
 
1038
                        bool has_implicit_parameters = !HasExplicitParameters;
 
1039
                        bool error = false;
 
1040
 
 
1041
                        for (int i = 0; i < Parameters.Count; ++i) {
 
1042
                                Parameter.Modifier p_mod = invoke_pd.FixedParameters [i].ModFlags;
 
1043
                                if (Parameters.FixedParameters [i].ModFlags != p_mod && p_mod != Parameter.Modifier.PARAMS) {
 
1044
                                        if (ignore_errors)
 
1045
                                                return false;
 
1046
                                        
 
1047
                                        if (p_mod == Parameter.Modifier.NONE)
 
1048
                                                ec.Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
 
1049
                                                              (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.FixedParameters [i].ModFlags));
 
1050
                                        else
 
1051
                                                ec.Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
 
1052
                                                              (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
 
1053
                                        error = true;
 
1054
                                }
 
1055
 
 
1056
                                if (has_implicit_parameters)
 
1057
                                        continue;
 
1058
 
 
1059
                                TypeSpec type = invoke_pd.Types [i];
 
1060
                                
 
1061
                                // We assume that generic parameters are always inflated
 
1062
                                if (TypeManager.IsGenericParameter (type))
 
1063
                                        continue;
 
1064
                                
 
1065
                                if (TypeManager.HasElementType (type) && TypeManager.IsGenericParameter (TypeManager.GetElementType (type)))
 
1066
                                        continue;
 
1067
                                
 
1068
                                if (!TypeSpecComparer.IsEqual (invoke_pd.Types [i], Parameters.Types [i])) {
 
1069
                                        if (ignore_errors)
 
1070
                                                return false;
 
1071
                                        
 
1072
                                        ec.Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
 
1073
                                                      (i+1).ToString (),
 
1074
                                                      TypeManager.CSharpName (Parameters.Types [i]),
 
1075
                                                      TypeManager.CSharpName (invoke_pd.Types [i]));
 
1076
                                        error = true;
 
1077
                                }
 
1078
                        }
 
1079
 
 
1080
                        return !error;
 
1081
                }
 
1082
 
 
1083
                //
 
1084
                // Infers type arguments based on explicit arguments
 
1085
                //
 
1086
                public bool ExplicitTypeInference (ResolveContext ec, TypeInferenceContext type_inference, TypeSpec delegate_type)
 
1087
                {
 
1088
                        if (!HasExplicitParameters)
 
1089
                                return false;
 
1090
 
 
1091
                        if (!delegate_type.IsDelegate) {
 
1092
                                if (!delegate_type.IsExpressionTreeType)
 
1093
                                        return false;
 
1094
 
 
1095
                                delegate_type = TypeManager.GetTypeArguments (delegate_type) [0];
 
1096
                                if (!delegate_type.IsDelegate)
 
1097
                                        return false;
 
1098
                        }
 
1099
                        
 
1100
                        AParametersCollection d_params = Delegate.GetParameters (delegate_type);
 
1101
                        if (d_params.Count != Parameters.Count)
 
1102
                                return false;
 
1103
 
 
1104
                        var ptypes = Parameters.Types;
 
1105
                        var dtypes = d_params.Types;
 
1106
                        for (int i = 0; i < Parameters.Count; ++i) {
 
1107
                                if (type_inference.ExactInference (ptypes[i], dtypes[i]) == 0) {
 
1108
                                        //
 
1109
                                        // Continue when 0 (quick path) does not mean inference failure. Checking for
 
1110
                                        // same type handles cases like int -> int
 
1111
                                        //
 
1112
                                        if (ptypes[i] == dtypes[i])
 
1113
                                                continue;
 
1114
 
 
1115
                                        return false;
 
1116
                                }
 
1117
                        }
 
1118
 
 
1119
                        return true;
 
1120
                }
 
1121
 
 
1122
                public TypeSpec InferReturnType (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegate_type)
 
1123
                {
 
1124
                        Expression expr;
 
1125
                        AnonymousExpression am;
 
1126
 
 
1127
                        if (compatibles.TryGetValue (delegate_type, out expr)) {
 
1128
                                am = expr as AnonymousExpression;
 
1129
                                return am == null ? null : am.ReturnType;
 
1130
                        }
 
1131
 
 
1132
                        using (ec.Set (ResolveContext.Options.ProbingMode | ResolveContext.Options.InferReturnType)) {
 
1133
                                ReportPrinter prev;
 
1134
                                if (TypeInferenceReportPrinter != null) {
 
1135
                                        prev = ec.Report.SetPrinter (TypeInferenceReportPrinter);
 
1136
                                } else {
 
1137
                                        prev = null;
 
1138
                                }
 
1139
 
 
1140
                                var body = CompatibleMethodBody (ec, tic, null, delegate_type);
 
1141
                                if (body != null) {
 
1142
                                        am = body.Compatible (ec, body);
 
1143
                                } else {
 
1144
                                        am = null;
 
1145
                                }
 
1146
 
 
1147
                                if (TypeInferenceReportPrinter != null) {
 
1148
                                        ec.Report.SetPrinter (prev);
 
1149
                                }
 
1150
                        }
 
1151
 
 
1152
                        if (am == null)
 
1153
                                return null;
 
1154
 
 
1155
//                      compatibles.Add (delegate_type, am);
 
1156
                        return am.ReturnType;
 
1157
                }
 
1158
 
 
1159
                public override bool ContainsEmitWithAwait ()
 
1160
                {
 
1161
                        return false;
 
1162
                }
 
1163
 
 
1164
                //
 
1165
                // Returns AnonymousMethod container if this anonymous method
 
1166
                // expression can be implicitly converted to the delegate type `delegate_type'
 
1167
                //
 
1168
                public Expression Compatible (ResolveContext ec, TypeSpec type)
 
1169
                {
 
1170
                        Expression am;
 
1171
                        if (compatibles.TryGetValue (type, out am))
 
1172
                                return am;
 
1173
 
 
1174
                        TypeSpec delegate_type = CompatibleChecks (ec, type);
 
1175
                        if (delegate_type == null)
 
1176
                                return null;
 
1177
 
 
1178
                        //
 
1179
                        // At this point its the first time we know the return type that is 
 
1180
                        // needed for the anonymous method.  We create the method here.
 
1181
                        //
 
1182
 
 
1183
                        var invoke_mb = Delegate.GetInvokeMethod (delegate_type);
 
1184
                        TypeSpec return_type = invoke_mb.ReturnType;
 
1185
 
 
1186
                        //
 
1187
                        // Second: the return type of the delegate must be compatible with 
 
1188
                        // the anonymous type.   Instead of doing a pass to examine the block
 
1189
                        // we satisfy the rule by setting the return type on the EmitContext
 
1190
                        // to be the delegate type return type.
 
1191
                        //
 
1192
 
 
1193
                        var body = CompatibleMethodBody (ec, null, return_type, delegate_type);
 
1194
                        if (body == null)
 
1195
                                return null;
 
1196
 
 
1197
                        bool etree_conversion = delegate_type != type;
 
1198
 
 
1199
                        try {
 
1200
                                if (etree_conversion) {
 
1201
                                        if (ec.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
 
1202
                                                //
 
1203
                                                // Nested expression tree lambda use same scope as parent
 
1204
                                                // lambda, this also means no variable capturing between this
 
1205
                                                // and parent scope
 
1206
                                                //
 
1207
                                                am = body.Compatible (ec, ec.CurrentAnonymousMethod);
 
1208
 
 
1209
                                                //
 
1210
                                                // Quote nested expression tree
 
1211
                                                //
 
1212
                                                if (am != null)
 
1213
                                                        am = new Quote (am);
 
1214
                                        } else {
 
1215
                                                int errors = ec.Report.Errors;
 
1216
 
 
1217
                                                if (Block.IsAsync) {
 
1218
                                                        ec.Report.Error (1989, loc, "Async lambda expressions cannot be converted to expression trees");
 
1219
                                                }
 
1220
 
 
1221
                                                using (ec.Set (ResolveContext.Options.ExpressionTreeConversion)) {
 
1222
                                                        am = body.Compatible (ec);
 
1223
                                                }
 
1224
 
 
1225
                                                //
 
1226
                                                // Rewrite expressions into expression tree when targeting Expression<T>
 
1227
                                                //
 
1228
                                                if (am != null && errors == ec.Report.Errors)
 
1229
                                                        am = CreateExpressionTree (ec, delegate_type);
 
1230
                                        }
 
1231
                                } else {
 
1232
                                        am = body.Compatible (ec);
 
1233
 
 
1234
                                        if (body.DirectMethodGroupConversion != null) {
 
1235
                                                var errors_printer = new SessionReportPrinter ();
 
1236
                                                var old = ec.Report.SetPrinter (errors_printer);
 
1237
                                                var expr = new ImplicitDelegateCreation (delegate_type, body.DirectMethodGroupConversion, loc) {
 
1238
                                                        AllowSpecialMethodsInvocation = true
 
1239
                                                }.Resolve (ec);
 
1240
                                                ec.Report.SetPrinter (old);
 
1241
                                                if (expr != null && errors_printer.ErrorsCount == 0)
 
1242
                                                        am = expr;
 
1243
                                        }
 
1244
                                }
 
1245
                        } catch (CompletionResult) {
 
1246
                                throw;
 
1247
                        } catch (FatalException) {
 
1248
                                throw;
 
1249
                        } catch (Exception e) {
 
1250
                                throw new InternalErrorException (e, loc);
 
1251
                        }
 
1252
 
 
1253
                        if (!ec.IsInProbingMode) {
 
1254
                                compatibles.Add (type, am ?? EmptyExpression.Null);
 
1255
                        }
 
1256
 
 
1257
                        return am;
 
1258
                }
 
1259
 
 
1260
                protected virtual Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type)
 
1261
                {
 
1262
                        return CreateExpressionTree (ec);
 
1263
                }
 
1264
 
 
1265
                public override Expression CreateExpressionTree (ResolveContext ec)
 
1266
                {
 
1267
                        ec.Report.Error (1946, loc, "An anonymous method cannot be converted to an expression tree");
 
1268
                        return null;
 
1269
                }
 
1270
 
 
1271
                protected virtual ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegate_type)
 
1272
                {
 
1273
                        var delegate_parameters = Delegate.GetParameters (delegate_type);
 
1274
 
 
1275
                        if (Parameters == ParametersCompiled.Undefined) {
 
1276
                                //
 
1277
                                // We provide a set of inaccessible parameters
 
1278
                                //
 
1279
                                Parameter[] fixedpars = new Parameter[delegate_parameters.Count];
 
1280
 
 
1281
                                for (int i = 0; i < delegate_parameters.Count; i++) {
 
1282
                                        Parameter.Modifier i_mod = delegate_parameters.FixedParameters [i].ModFlags;
 
1283
                                        if ((i_mod & Parameter.Modifier.OUT) != 0) {
 
1284
                                                if (!ec.IsInProbingMode) {
 
1285
                                                        ec.Report.Error (1688, loc,
 
1286
                                                                "Cannot convert anonymous method block without a parameter list to delegate type `{0}' because it has one or more `out' parameters",
 
1287
                                                                delegate_type.GetSignatureForError ());
 
1288
                                                }
 
1289
 
 
1290
                                                return null;
 
1291
                                        }
 
1292
                                        fixedpars[i] = new Parameter (
 
1293
                                                new TypeExpression (delegate_parameters.Types [i], loc), null,
 
1294
                                                delegate_parameters.FixedParameters [i].ModFlags, null, loc);
 
1295
                                }
 
1296
 
 
1297
                                return ParametersCompiled.CreateFullyResolved (fixedpars, delegate_parameters.Types);
 
1298
                        }
 
1299
 
 
1300
                        if (!VerifyExplicitParameters (ec, delegate_type, delegate_parameters)) {
 
1301
                                return null;
 
1302
                        }
 
1303
 
 
1304
                        return Parameters;
 
1305
                }
 
1306
 
 
1307
                protected override Expression DoResolve (ResolveContext ec)
 
1308
                {
 
1309
                        if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
 
1310
                                ec.Report.Error (1706, loc, "Anonymous methods and lambda expressions cannot be used in the current context");
 
1311
                                return null;
 
1312
                        }
 
1313
 
 
1314
                        //
 
1315
                        // Set class type, set type
 
1316
                        //
 
1317
 
 
1318
                        eclass = ExprClass.Value;
 
1319
 
 
1320
                        //
 
1321
                        // This hack means `The type is not accessible
 
1322
                        // anywhere', we depend on special conversion
 
1323
                        // rules.
 
1324
                        // 
 
1325
                        type = InternalType.AnonymousMethod;
 
1326
 
 
1327
                        if (!DoResolveParameters (ec))
 
1328
                                return null;
 
1329
 
 
1330
#if !STATIC
 
1331
                        // FIXME: The emitted code isn't very careful about reachability
 
1332
                        // so, ensure we have a 'ret' at the end
 
1333
                        BlockContext bc = ec as BlockContext;
 
1334
                        if (bc != null && bc.CurrentBranching != null && bc.CurrentBranching.CurrentUsageVector.IsUnreachable)
 
1335
                                bc.NeedReturnLabel ();
 
1336
#endif
 
1337
                        return this;
 
1338
                }
 
1339
 
 
1340
                protected virtual bool DoResolveParameters (ResolveContext rc)
 
1341
                {
 
1342
                        return Parameters.Resolve (rc);
 
1343
                }
 
1344
 
 
1345
                public override void Emit (EmitContext ec)
 
1346
                {
 
1347
                        // nothing, as we only exist to not do anything.
 
1348
                }
 
1349
 
 
1350
                public static void Error_AddressOfCapturedVar (ResolveContext ec, IVariableReference var, Location loc)
 
1351
                {
 
1352
                        ec.Report.Error (1686, loc,
 
1353
                                "Local variable or parameter `{0}' cannot have their address taken and be used inside an anonymous method, lambda expression or query expression",
 
1354
                                var.Name);
 
1355
                }
 
1356
 
 
1357
                public override string GetSignatureForError ()
 
1358
                {
 
1359
                        return ExprClassName;
 
1360
                }
 
1361
 
 
1362
                AnonymousMethodBody CompatibleMethodBody (ResolveContext ec, TypeInferenceContext tic, TypeSpec return_type, TypeSpec delegate_type)
 
1363
                {
 
1364
                        ParametersCompiled p = ResolveParameters (ec, tic, delegate_type);
 
1365
                        if (p == null)
 
1366
                                return null;
 
1367
 
 
1368
                        ParametersBlock b = ec.IsInProbingMode ? (ParametersBlock) Block.PerformClone () : Block;
 
1369
 
 
1370
                        if (b.IsAsync) {
 
1371
                                var rt = return_type;
 
1372
                                if (rt != null && rt.Kind != MemberKind.Void && rt != ec.Module.PredefinedTypes.Task.TypeSpec && !rt.IsGenericTask) {
 
1373
                                        ec.Report.Error (4010, loc, "Cannot convert async {0} to delegate type `{1}'",
 
1374
                                                GetSignatureForError (), delegate_type.GetSignatureForError ());
 
1375
 
 
1376
                                        return null;
 
1377
                                }
 
1378
 
 
1379
                                b = b.ConvertToAsyncTask (ec, ec.CurrentMemberDefinition.Parent.PartialContainer, p, return_type, loc);
 
1380
                        }
 
1381
 
 
1382
                        return CompatibleMethodFactory (return_type ?? InternalType.ErrorType, delegate_type, p, b);
 
1383
                }
 
1384
 
 
1385
                protected virtual AnonymousMethodBody CompatibleMethodFactory (TypeSpec return_type, TypeSpec delegate_type, ParametersCompiled p, ParametersBlock b)
 
1386
                {
 
1387
                        return new AnonymousMethodBody (p, b, return_type, delegate_type, loc);
 
1388
                }
 
1389
 
 
1390
                protected override void CloneTo (CloneContext clonectx, Expression t)
 
1391
                {
 
1392
                        AnonymousMethodExpression target = (AnonymousMethodExpression) t;
 
1393
 
 
1394
                        target.Block = (ParametersBlock) clonectx.LookupBlock (Block);
 
1395
                }
 
1396
                
 
1397
                public override object Accept (StructuralVisitor visitor)
 
1398
                {
 
1399
                        return visitor.Visit (this);
 
1400
                }
 
1401
        }
 
1402
 
 
1403
        //
 
1404
        // Abstract expression for any block which requires variables hoisting
 
1405
        //
 
1406
        public abstract class AnonymousExpression : ExpressionStatement
 
1407
        {
 
1408
                protected class AnonymousMethodMethod : Method
 
1409
                {
 
1410
                        public readonly AnonymousExpression AnonymousMethod;
 
1411
                        public readonly AnonymousMethodStorey Storey;
 
1412
 
 
1413
                        public AnonymousMethodMethod (TypeDefinition parent, AnonymousExpression am, AnonymousMethodStorey storey,
 
1414
                                                          TypeExpr return_type,
 
1415
                                                          Modifiers mod, MemberName name,
 
1416
                                                          ParametersCompiled parameters)
 
1417
                                : base (parent, return_type, mod | Modifiers.COMPILER_GENERATED,
 
1418
                                                name, parameters, null)
 
1419
                        {
 
1420
                                this.AnonymousMethod = am;
 
1421
                                this.Storey = storey;
 
1422
 
 
1423
                                Parent.PartialContainer.Members.Add (this);
 
1424
                                Block = new ToplevelBlock (am.block, parameters);
 
1425
                        }
 
1426
 
 
1427
                        public override EmitContext CreateEmitContext (ILGenerator ig, SourceMethodBuilder sourceMethod)
 
1428
                        {
 
1429
                                EmitContext ec = new EmitContext (this, ig, ReturnType, sourceMethod);
 
1430
                                ec.CurrentAnonymousMethod = AnonymousMethod;
 
1431
                                return ec;
 
1432
                        }
 
1433
 
 
1434
                        protected override void DefineTypeParameters ()
 
1435
                        {
 
1436
                                // Type parameters were cloned
 
1437
                        }
 
1438
 
 
1439
                        protected override bool ResolveMemberType ()
 
1440
                        {
 
1441
                                if (!base.ResolveMemberType ())
 
1442
                                        return false;
 
1443
 
 
1444
                                if (Storey != null && Storey.Mutator != null) {
 
1445
                                        if (!parameters.IsEmpty) {
 
1446
                                                var mutated = Storey.Mutator.Mutate (parameters.Types);
 
1447
                                                if (mutated != parameters.Types)
 
1448
                                                        parameters = ParametersCompiled.CreateFullyResolved ((Parameter[]) parameters.FixedParameters, mutated);
 
1449
                                        }
 
1450
 
 
1451
                                        member_type = Storey.Mutator.Mutate (member_type);
 
1452
                                }
 
1453
 
 
1454
                                return true;
 
1455
                        }
 
1456
 
 
1457
                        public override void Emit ()
 
1458
                        {
 
1459
                                if (MethodBuilder == null) {
 
1460
                                        Define ();
 
1461
                                }
 
1462
 
 
1463
                                base.Emit ();
 
1464
                        }
 
1465
                }
 
1466
 
 
1467
                protected readonly ParametersBlock block;
 
1468
 
 
1469
                public TypeSpec ReturnType;
 
1470
 
 
1471
                protected AnonymousExpression (ParametersBlock block, TypeSpec return_type, Location loc)
 
1472
                {
 
1473
                        this.ReturnType = return_type;
 
1474
                        this.block = block;
 
1475
                        this.loc = loc;
 
1476
                }
 
1477
 
 
1478
                public abstract string ContainerType { get; }
 
1479
                public abstract bool IsIterator { get; }
 
1480
                public abstract AnonymousMethodStorey Storey { get; }
 
1481
 
 
1482
                //
 
1483
                // The block that makes up the body for the anonymous method
 
1484
                //
 
1485
                public ParametersBlock Block {
 
1486
                        get {
 
1487
                                return block;
 
1488
                        }
 
1489
                }
 
1490
 
 
1491
                public AnonymousExpression Compatible (ResolveContext ec)
 
1492
                {
 
1493
                        return Compatible (ec, this);
 
1494
                }
 
1495
 
 
1496
                public AnonymousExpression Compatible (ResolveContext ec, AnonymousExpression ae)
 
1497
                {
 
1498
                        if (block.Resolved)
 
1499
                                return this;
 
1500
 
 
1501
                        // TODO: Implement clone
 
1502
                        BlockContext aec = new BlockContext (ec, block, ReturnType);
 
1503
                        aec.CurrentAnonymousMethod = ae;
 
1504
 
 
1505
                        var am = this as AnonymousMethodBody;
 
1506
 
 
1507
                        if (ec.HasSet (ResolveContext.Options.InferReturnType) && am != null) {
 
1508
                                am.ReturnTypeInference = new TypeInferenceContext ();
 
1509
                        }
 
1510
 
 
1511
                        var bc = ec as BlockContext;
 
1512
                        if (bc != null)
 
1513
                                aec.FlowOffset = bc.FlowOffset;
 
1514
 
 
1515
                        var errors = ec.Report.Errors;
 
1516
 
 
1517
                        bool res = Block.Resolve (ec.CurrentBranching, aec, null);
 
1518
 
 
1519
                        if (am != null && am.ReturnTypeInference != null) {
 
1520
                                am.ReturnTypeInference.FixAllTypes (ec);
 
1521
                                ReturnType = am.ReturnTypeInference.InferredTypeArguments [0];
 
1522
                                am.ReturnTypeInference = null;
 
1523
 
 
1524
                                //
 
1525
                                // If e is synchronous the inferred return type is T
 
1526
                                // If e is asynchronous the inferred return type is Task<T>
 
1527
                                //
 
1528
                                if (block.IsAsync && ReturnType != null) {
 
1529
                                        ReturnType = ec.Module.PredefinedTypes.TaskGeneric.TypeSpec.MakeGenericType (ec, new [] { ReturnType });
 
1530
                                }
 
1531
                        }
 
1532
 
 
1533
                        if (res && errors != ec.Report.Errors)
 
1534
                                return null;
 
1535
 
 
1536
                        return res ? this : null;
 
1537
                }
 
1538
 
 
1539
                public override bool ContainsEmitWithAwait ()
 
1540
                {
 
1541
                        return false;
 
1542
                }
 
1543
 
 
1544
                public void SetHasThisAccess ()
 
1545
                {
 
1546
                        ExplicitBlock b = block;
 
1547
                        do {
 
1548
                                if (b.HasCapturedThis)
 
1549
                                        return;
 
1550
 
 
1551
                                b.HasCapturedThis = true;
 
1552
                                b = b.Parent == null ? null : b.Parent.Explicit;
 
1553
                        } while (b != null);
 
1554
                }
 
1555
        }
 
1556
 
 
1557
        public class AnonymousMethodBody : AnonymousExpression
 
1558
        {
 
1559
                protected readonly ParametersCompiled parameters;
 
1560
                AnonymousMethodStorey storey;
 
1561
 
 
1562
                AnonymousMethodMethod method;
 
1563
                Field am_cache;
 
1564
                string block_name;
 
1565
                TypeInferenceContext return_inference;
 
1566
 
 
1567
                public AnonymousMethodBody (ParametersCompiled parameters,
 
1568
                                        ParametersBlock block, TypeSpec return_type, TypeSpec delegate_type,
 
1569
                                        Location loc)
 
1570
                        : base (block, return_type, loc)
 
1571
                {
 
1572
                        this.type = delegate_type;
 
1573
                        this.parameters = parameters;
 
1574
                }
 
1575
 
 
1576
                #region Properties
 
1577
 
 
1578
                public override string ContainerType {
 
1579
                        get { return "anonymous method"; }
 
1580
                }
 
1581
 
 
1582
                //
 
1583
                // Method-group instance for lambdas which can be replaced with
 
1584
                // simple method group call
 
1585
                //
 
1586
                public MethodGroupExpr DirectMethodGroupConversion {
 
1587
                        get; set;
 
1588
                }
 
1589
 
 
1590
                public override bool IsIterator {
 
1591
                        get {
 
1592
                                return false;
 
1593
                        }
 
1594
                }
 
1595
 
 
1596
                public ParametersCompiled Parameters {
 
1597
                        get {
 
1598
                                return parameters;
 
1599
                        }
 
1600
                }
 
1601
 
 
1602
                public TypeInferenceContext ReturnTypeInference {
 
1603
                        get {
 
1604
                                return return_inference;
 
1605
                        }
 
1606
                        set {
 
1607
                                return_inference = value;
 
1608
                        }
 
1609
                }
 
1610
 
 
1611
                public override AnonymousMethodStorey Storey {
 
1612
                        get {
 
1613
                                return storey;
 
1614
                        }
 
1615
                }
 
1616
 
 
1617
                #endregion
 
1618
 
 
1619
                public override Expression CreateExpressionTree (ResolveContext ec)
 
1620
                {
 
1621
                        ec.Report.Error (1945, loc, "An expression tree cannot contain an anonymous method expression");
 
1622
                        return null;
 
1623
                }
 
1624
 
 
1625
                bool Define (ResolveContext ec)
 
1626
                {
 
1627
                        if (!Block.Resolved && Compatible (ec) == null)
 
1628
                                return false;
 
1629
 
 
1630
                        if (block_name == null) {
 
1631
                                MemberCore mc = (MemberCore) ec.MemberContext;
 
1632
                                block_name = mc.MemberName.Basename;
 
1633
                        }
 
1634
 
 
1635
                        return true;
 
1636
                }
 
1637
 
 
1638
                //
 
1639
                // Creates a host for the anonymous method
 
1640
                //
 
1641
                AnonymousMethodMethod DoCreateMethodHost (EmitContext ec)
 
1642
                {
 
1643
                        //
 
1644
                        // Anonymous method body can be converted to
 
1645
                        //
 
1646
                        // 1, an instance method in current scope when only `this' is hoisted
 
1647
                        // 2, a static method in current scope when neither `this' nor any variable is hoisted
 
1648
                        // 3, an instance method in compiler generated storey when any hoisted variable exists
 
1649
                        //
 
1650
 
 
1651
                        Modifiers modifiers;
 
1652
                        TypeDefinition parent = null;
 
1653
 
 
1654
                        var src_block = Block.Original.Explicit;
 
1655
                        if (src_block.HasCapturedVariable || src_block.HasCapturedThis) {
 
1656
                                parent = storey = FindBestMethodStorey ();
 
1657
 
 
1658
                                if (storey == null) {
 
1659
                                        var top_block = src_block.ParametersBlock.TopBlock;
 
1660
                                        var sm = top_block.StateMachine;
 
1661
 
 
1662
                                        if (src_block.HasCapturedThis) {
 
1663
                                                //
 
1664
                                                // Remove hoisted 'this' request when simple instance method is
 
1665
                                                // enough (no hoisted variables only 'this')
 
1666
                                                //
 
1667
                                                if (src_block.ParametersBlock.StateMachine == null)
 
1668
                                                        top_block.RemoveThisReferenceFromChildrenBlock (src_block);
 
1669
 
 
1670
                                                //
 
1671
                                                // Special case where parent class is used to emit instance method
 
1672
                                                // because currect storey is of value type (async host). We cannot
 
1673
                                                // use ldftn on non-boxed instances either to share mutated state
 
1674
                                                //
 
1675
                                                if (sm != null && sm.Kind == MemberKind.Struct) {
 
1676
                                                        parent = sm.Parent.PartialContainer;
 
1677
                                                }
 
1678
                                        }
 
1679
 
 
1680
                                        //
 
1681
                                        // For iterators we can host everything in one class
 
1682
                                        //
 
1683
                                        if (sm is IteratorStorey)
 
1684
                                                parent = storey = sm;
 
1685
                                }
 
1686
 
 
1687
                                modifiers = storey != null ? Modifiers.INTERNAL : Modifiers.PRIVATE;
 
1688
                        } else {
 
1689
                                if (ec.CurrentAnonymousMethod != null)
 
1690
                                        parent = storey = ec.CurrentAnonymousMethod.Storey;
 
1691
 
 
1692
                                modifiers = Modifiers.STATIC | Modifiers.PRIVATE;
 
1693
                        }
 
1694
 
 
1695
                        if (parent == null)
 
1696
                                parent = ec.CurrentTypeDefinition.Parent.PartialContainer;
 
1697
 
 
1698
                        string name = CompilerGeneratedContainer.MakeName (parent != storey ? block_name : null,
 
1699
                                "m", null, ec.Module.CounterAnonymousMethods++);
 
1700
 
 
1701
                        MemberName member_name;
 
1702
                        if (storey == null && ec.CurrentTypeParameters != null) {
 
1703
 
 
1704
                                var hoisted_tparams = ec.CurrentTypeParameters;
 
1705
                                var type_params = new TypeParameters (hoisted_tparams.Count);
 
1706
                                for (int i = 0; i < hoisted_tparams.Count; ++i) {
 
1707
                                    type_params.Add (hoisted_tparams[i].CreateHoistedCopy (null));
 
1708
                                }
 
1709
 
 
1710
                                member_name = new MemberName (name, type_params, Location);
 
1711
                        } else {
 
1712
                                member_name = new MemberName (name, Location);
 
1713
                        }
 
1714
 
 
1715
                        return new AnonymousMethodMethod (parent,
 
1716
                                this, storey, new TypeExpression (ReturnType, Location), modifiers,
 
1717
                                member_name, parameters);
 
1718
                }
 
1719
 
 
1720
                protected override Expression DoResolve (ResolveContext ec)
 
1721
                {
 
1722
                        if (!Define (ec))
 
1723
                                return null;
 
1724
 
 
1725
                        eclass = ExprClass.Value;
 
1726
                        return this;
 
1727
                }
 
1728
 
 
1729
                public override void Emit (EmitContext ec)
 
1730
                {
 
1731
                        //
 
1732
                        // Use same anonymous method implementation for scenarios where same
 
1733
                        // code is used from multiple blocks, e.g. field initializers
 
1734
                        //
 
1735
                        if (method == null) {
 
1736
                                //
 
1737
                                // Delay an anonymous method definition to avoid emitting unused code
 
1738
                                // for unreachable blocks or expression trees
 
1739
                                //
 
1740
                                method = DoCreateMethodHost (ec);
 
1741
                                method.Define ();
 
1742
                        }
 
1743
 
 
1744
                        bool is_static = (method.ModFlags & Modifiers.STATIC) != 0;
 
1745
                        if (is_static && am_cache == null) {
 
1746
                                //
 
1747
                                // Creates a field cache to store delegate instance if it's not generic
 
1748
                                //
 
1749
                                if (!method.MemberName.IsGeneric) {
 
1750
                                        var parent = method.Parent.PartialContainer;
 
1751
                                        int id = parent.AnonymousMethodsCounter++;
 
1752
                                        var cache_type = storey != null && storey.Mutator != null ? storey.Mutator.Mutate (type) : type;
 
1753
 
 
1754
                                        am_cache = new Field (parent, new TypeExpression (cache_type, loc),
 
1755
                                                Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
 
1756
                                                new MemberName (CompilerGeneratedContainer.MakeName (null, "f", "am$cache", id), loc), null);
 
1757
                                        am_cache.Define ();
 
1758
                                        parent.AddField (am_cache);
 
1759
                                } else {
 
1760
                                        // TODO: Implement caching of generated generic static methods
 
1761
                                        //
 
1762
                                        // Idea:
 
1763
                                        //
 
1764
                                        // Some extra class is needed to capture variable generic type
 
1765
                                        // arguments. Maybe we could re-use anonymous types, with a unique
 
1766
                                        // anonymous method id, but they are quite heavy.
 
1767
                                        //
 
1768
                                        // Consider : "() => typeof(T);"
 
1769
                                        //
 
1770
                                        // We need something like
 
1771
                                        // static class Wrap<Tn, Tm, DelegateType> {
 
1772
                                        //              public static DelegateType cache;
 
1773
                                        // }
 
1774
                                        //
 
1775
                                        // We then specialize local variable to capture all generic parameters
 
1776
                                        // and delegate type, e.g. "Wrap<Ta, Tb, DelegateTypeInst> cache;"
 
1777
                                        //
 
1778
                                }
 
1779
                        }
 
1780
 
 
1781
                        Label l_initialized = ec.DefineLabel ();
 
1782
 
 
1783
                        if (am_cache != null) {
 
1784
                                ec.Emit (OpCodes.Ldsfld, am_cache.Spec);
 
1785
                                ec.Emit (OpCodes.Brtrue_S, l_initialized);
 
1786
                        }
 
1787
 
 
1788
                        //
 
1789
                        // Load method delegate implementation
 
1790
                        //
 
1791
 
 
1792
                        if (is_static) {
 
1793
                                ec.EmitNull ();
 
1794
                        } else if (storey != null) {
 
1795
                                Expression e = storey.GetStoreyInstanceExpression (ec).Resolve (new ResolveContext (ec.MemberContext));
 
1796
                                if (e != null) {
 
1797
                                        e.Emit (ec);
 
1798
                                }
 
1799
                        } else {
 
1800
                                ec.EmitThis ();
 
1801
 
 
1802
                                //
 
1803
                                // Special case for value type storey where this is not lifted but
 
1804
                                // droped off to parent class
 
1805
                                //
 
1806
                                for (var b = Block.Parent; b != null; b = b.Parent) {
 
1807
                                        if (b.ParametersBlock.StateMachine != null) {
 
1808
                                                ec.Emit (OpCodes.Ldfld, b.ParametersBlock.StateMachine.HoistedThis.Field.Spec);
 
1809
                                                break;
 
1810
                                        }
 
1811
                                }
 
1812
                        }
 
1813
 
 
1814
                        var delegate_method = method.Spec;
 
1815
                        if (storey != null && storey.MemberName.IsGeneric) {
 
1816
                                TypeSpec t = storey.Instance.Type;
 
1817
 
 
1818
                                //
 
1819
                                // Mutate anonymous method instance type if we are in nested
 
1820
                                // hoisted generic anonymous method storey
 
1821
                                //
 
1822
                                if (ec.IsAnonymousStoreyMutateRequired) {
 
1823
                                        t = storey.Mutator.Mutate (t);
 
1824
                                }
 
1825
 
 
1826
                                ec.Emit (OpCodes.Ldftn, TypeBuilder.GetMethod (t.GetMetaInfo (), (MethodInfo) delegate_method.GetMetaInfo ()));
 
1827
                        } else {
 
1828
                                if (delegate_method.IsGeneric)
 
1829
                                        delegate_method = delegate_method.MakeGenericMethod (ec.MemberContext, method.TypeParameters);
 
1830
 
 
1831
                                ec.Emit (OpCodes.Ldftn, delegate_method);
 
1832
                        }
 
1833
 
 
1834
                        var constructor_method = Delegate.GetConstructor (type);
 
1835
                        ec.Emit (OpCodes.Newobj, constructor_method);
 
1836
 
 
1837
                        if (am_cache != null) {
 
1838
                                ec.Emit (OpCodes.Stsfld, am_cache.Spec);
 
1839
                                ec.MarkLabel (l_initialized);
 
1840
                                ec.Emit (OpCodes.Ldsfld, am_cache.Spec);
 
1841
                        }
 
1842
                }
 
1843
 
 
1844
                public override void EmitStatement (EmitContext ec)
 
1845
                {
 
1846
                        throw new NotImplementedException ();
 
1847
                }
 
1848
 
 
1849
                //
 
1850
                // Look for the best storey for this anonymous method
 
1851
                //
 
1852
                AnonymousMethodStorey FindBestMethodStorey ()
 
1853
                {
 
1854
                        //
 
1855
                        // Use the nearest parent block which has a storey
 
1856
                        //
 
1857
                        for (Block b = Block.Parent; b != null; b = b.Parent) {
 
1858
                                AnonymousMethodStorey s = b.Explicit.AnonymousMethodStorey;
 
1859
                                if (s != null)
 
1860
                                        return s;
 
1861
                        }
 
1862
                                        
 
1863
                        return null;
 
1864
                }
 
1865
 
 
1866
                public override string GetSignatureForError ()
 
1867
                {
 
1868
                        return TypeManager.CSharpName (type);
 
1869
                }
 
1870
        }
 
1871
 
 
1872
        //
 
1873
        // Anonymous type container
 
1874
        //
 
1875
        public class AnonymousTypeClass : CompilerGeneratedContainer
 
1876
        {
 
1877
                public const string ClassNamePrefix = "<>__AnonType";
 
1878
                public const string SignatureForError = "anonymous type";
 
1879
                
 
1880
                readonly IList<AnonymousTypeParameter> parameters;
 
1881
 
 
1882
                private AnonymousTypeClass (ModuleContainer parent, MemberName name, IList<AnonymousTypeParameter> parameters, Location loc)
 
1883
                        : base (parent, name, parent.Evaluator != null ? Modifiers.PUBLIC : Modifiers.INTERNAL)
 
1884
                {
 
1885
                        this.parameters = parameters;
 
1886
                }
 
1887
 
 
1888
                public static AnonymousTypeClass Create (TypeContainer parent, IList<AnonymousTypeParameter> parameters, Location loc)
 
1889
                {
 
1890
                        string name = ClassNamePrefix + parent.Module.CounterAnonymousTypes++;
 
1891
 
 
1892
                        ParametersCompiled all_parameters;
 
1893
                        TypeParameters tparams = null;
 
1894
                        SimpleName[] t_args;
 
1895
 
 
1896
                        if (parameters.Count == 0) {
 
1897
                                all_parameters = ParametersCompiled.EmptyReadOnlyParameters;
 
1898
                                t_args = null;
 
1899
                        } else {
 
1900
                                t_args = new SimpleName[parameters.Count];
 
1901
                                tparams = new TypeParameters ();
 
1902
                                Parameter[] ctor_params = new Parameter[parameters.Count];
 
1903
                                for (int i = 0; i < parameters.Count; ++i) {
 
1904
                                        AnonymousTypeParameter p = parameters[i];
 
1905
                                        for (int ii = 0; ii < i; ++ii) {
 
1906
                                                if (parameters[ii].Name == p.Name) {
 
1907
                                                        parent.Compiler.Report.Error (833, parameters[ii].Location,
 
1908
                                                                "`{0}': An anonymous type cannot have multiple properties with the same name",
 
1909
                                                                        p.Name);
 
1910
 
 
1911
                                                        p = new AnonymousTypeParameter (null, "$" + i.ToString (), p.Location);
 
1912
                                                        parameters[i] = p;
 
1913
                                                        break;
 
1914
                                                }
 
1915
                                        }
 
1916
 
 
1917
                                        t_args[i] = new SimpleName ("<" + p.Name + ">__T", p.Location);
 
1918
                                        tparams.Add (new TypeParameter (i, new MemberName (t_args[i].Name, p.Location), null, null, Variance.None));
 
1919
                                        ctor_params[i] = new Parameter (t_args[i], p.Name, Parameter.Modifier.NONE, null, p.Location);
 
1920
                                }
 
1921
 
 
1922
                                all_parameters = new ParametersCompiled (ctor_params);
 
1923
                        }
 
1924
 
 
1925
                        //
 
1926
                        // Create generic anonymous type host with generic arguments
 
1927
                        // named upon properties names
 
1928
                        //
 
1929
                        AnonymousTypeClass a_type = new AnonymousTypeClass (parent.Module, new MemberName (name, tparams, loc), parameters, loc);
 
1930
 
 
1931
                        Constructor c = new Constructor (a_type, name, Modifiers.PUBLIC | Modifiers.DEBUGGER_HIDDEN,
 
1932
                                null, all_parameters, loc);
 
1933
                        c.Block = new ToplevelBlock (parent.Module.Compiler, c.ParameterInfo, loc);
 
1934
 
 
1935
                        // 
 
1936
                        // Create fields and constructor body with field initialization
 
1937
                        //
 
1938
                        bool error = false;
 
1939
                        for (int i = 0; i < parameters.Count; ++i) {
 
1940
                                AnonymousTypeParameter p = parameters [i];
 
1941
 
 
1942
                                Field f = new Field (a_type, t_args [i], Modifiers.PRIVATE | Modifiers.READONLY | Modifiers.DEBUGGER_HIDDEN,
 
1943
                                        new MemberName ("<" + p.Name + ">", p.Location), null);
 
1944
 
 
1945
                                if (!a_type.AddField (f)) {
 
1946
                                        error = true;
 
1947
                                        continue;
 
1948
                                }
 
1949
 
 
1950
                                c.Block.AddStatement (new StatementExpression (
 
1951
                                        new SimpleAssign (new MemberAccess (new This (p.Location), f.Name),
 
1952
                                                c.Block.GetParameterReference (i, p.Location))));
 
1953
 
 
1954
                                ToplevelBlock get_block = new ToplevelBlock (parent.Module.Compiler, p.Location);
 
1955
                                get_block.AddStatement (new Return (
 
1956
                                        new MemberAccess (new This (p.Location), f.Name), p.Location));
 
1957
 
 
1958
                                Property prop = new Property (a_type, t_args [i], Modifiers.PUBLIC,
 
1959
                                        new MemberName (p.Name, p.Location), null);
 
1960
                                prop.Get = new Property.GetMethod (prop, 0, null, p.Location);
 
1961
                                prop.Get.Block = get_block;
 
1962
                                a_type.AddMember (prop);
 
1963
                        }
 
1964
 
 
1965
                        if (error)
 
1966
                                return null;
 
1967
 
 
1968
                        a_type.AddConstructor (c);
 
1969
                        return a_type;
 
1970
                }
 
1971
                
 
1972
                protected override bool DoDefineMembers ()
 
1973
                {
 
1974
                        if (!base.DoDefineMembers ())
 
1975
                                return false;
 
1976
 
 
1977
                        Location loc = Location;
 
1978
 
 
1979
                        var equals_parameters = ParametersCompiled.CreateFullyResolved (
 
1980
                                new Parameter (new TypeExpression (Compiler.BuiltinTypes.Object, loc), "obj", 0, null, loc), Compiler.BuiltinTypes.Object);
 
1981
 
 
1982
                        Method equals = new Method (this, new TypeExpression (Compiler.BuiltinTypes.Bool, loc),
 
1983
                                Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN, new MemberName ("Equals", loc),
 
1984
                                equals_parameters, null);
 
1985
 
 
1986
                        equals_parameters[0].Resolve (equals, 0);
 
1987
 
 
1988
                        Method tostring = new Method (this, new TypeExpression (Compiler.BuiltinTypes.String, loc),
 
1989
                                Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN, new MemberName ("ToString", loc),
 
1990
                                Mono.CSharp.ParametersCompiled.EmptyReadOnlyParameters, null);
 
1991
 
 
1992
                        ToplevelBlock equals_block = new ToplevelBlock (Compiler, equals.ParameterInfo, loc);
 
1993
 
 
1994
                        TypeExpr current_type;
 
1995
                        if (CurrentTypeParameters != null) {
 
1996
                                var targs = new TypeArguments ();
 
1997
                                for (int i = 0; i < CurrentTypeParameters.Count; ++i) {
 
1998
                                        targs.Add (new TypeParameterExpr (CurrentTypeParameters[i], Location));
 
1999
                                }
 
2000
 
 
2001
                                current_type = new GenericTypeExpr (Definition, targs, loc);
 
2002
                        } else {
 
2003
                                current_type = new TypeExpression (Definition, loc);
 
2004
                        }
 
2005
 
 
2006
                        var li_other = LocalVariable.CreateCompilerGenerated (CurrentType, equals_block, loc);
 
2007
                        equals_block.AddStatement (new BlockVariableDeclaration (new TypeExpression (li_other.Type, loc), li_other));
 
2008
                        var other_variable = new LocalVariableReference (li_other, loc);
 
2009
 
 
2010
                        MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
 
2011
                                new QualifiedAliasMember ("global", "System", loc), "Collections", loc), "Generic", loc);
 
2012
 
 
2013
                        Expression rs_equals = null;
 
2014
                        Expression string_concat = new StringConstant (Compiler.BuiltinTypes, "{", loc);
 
2015
                        Expression rs_hashcode = new IntConstant (Compiler.BuiltinTypes, -2128831035, loc);
 
2016
                        for (int i = 0; i < parameters.Count; ++i) {
 
2017
                                var p = parameters [i];
 
2018
                                var f = (Field) Members [i * 2];
 
2019
 
 
2020
                                MemberAccess equality_comparer = new MemberAccess (new MemberAccess (
 
2021
                                        system_collections_generic, "EqualityComparer",
 
2022
                                                new TypeArguments (new SimpleName (CurrentTypeParameters [i].Name, loc)), loc),
 
2023
                                                "Default", loc);
 
2024
 
 
2025
                                Arguments arguments_equal = new Arguments (2);
 
2026
                                arguments_equal.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
 
2027
                                arguments_equal.Add (new Argument (new MemberAccess (other_variable, f.Name)));
 
2028
 
 
2029
                                Expression field_equal = new Invocation (new MemberAccess (equality_comparer,
 
2030
                                        "Equals", loc), arguments_equal);
 
2031
 
 
2032
                                Arguments arguments_hashcode = new Arguments (1);
 
2033
                                arguments_hashcode.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
 
2034
                                Expression field_hashcode = new Invocation (new MemberAccess (equality_comparer,
 
2035
                                        "GetHashCode", loc), arguments_hashcode);
 
2036
 
 
2037
                                IntConstant FNV_prime = new IntConstant (Compiler.BuiltinTypes, 16777619, loc);                         
 
2038
                                rs_hashcode = new Binary (Binary.Operator.Multiply,
 
2039
                                        new Binary (Binary.Operator.ExclusiveOr, rs_hashcode, field_hashcode),
 
2040
                                        FNV_prime);
 
2041
 
 
2042
                                Expression field_to_string = new Conditional (new BooleanExpression (new Binary (Binary.Operator.Inequality,
 
2043
                                        new MemberAccess (new This (f.Location), f.Name), new NullLiteral (loc))),
 
2044
                                        new Invocation (new MemberAccess (
 
2045
                                                new MemberAccess (new This (f.Location), f.Name), "ToString"), null),
 
2046
                                        new StringConstant (Compiler.BuiltinTypes, string.Empty, loc), loc);
 
2047
 
 
2048
                                if (rs_equals == null) {
 
2049
                                        rs_equals = field_equal;
 
2050
                                        string_concat = new Binary (Binary.Operator.Addition,
 
2051
                                                string_concat,
 
2052
                                                new Binary (Binary.Operator.Addition,
 
2053
                                                        new StringConstant (Compiler.BuiltinTypes, " " + p.Name + " = ", loc),
 
2054
                                                        field_to_string));
 
2055
                                        continue;
 
2056
                                }
 
2057
 
 
2058
                                //
 
2059
                                // Implementation of ToString () body using string concatenation
 
2060
                                //                              
 
2061
                                string_concat = new Binary (Binary.Operator.Addition,
 
2062
                                        new Binary (Binary.Operator.Addition,
 
2063
                                                string_concat,
 
2064
                                                new StringConstant (Compiler.BuiltinTypes, ", " + p.Name + " = ", loc)),
 
2065
                                        field_to_string);
 
2066
 
 
2067
                                rs_equals = new Binary (Binary.Operator.LogicalAnd, rs_equals, field_equal);
 
2068
                        }
 
2069
 
 
2070
                        string_concat = new Binary (Binary.Operator.Addition,
 
2071
                                string_concat,
 
2072
                                new StringConstant (Compiler.BuiltinTypes, " }", loc));
 
2073
 
 
2074
                        //
 
2075
                        // Equals (object obj) override
 
2076
                        //              
 
2077
                        var other_variable_assign = new TemporaryVariableReference (li_other, loc);
 
2078
                        equals_block.AddStatement (new StatementExpression (
 
2079
                                new SimpleAssign (other_variable_assign,
 
2080
                                        new As (equals_block.GetParameterReference (0, loc),
 
2081
                                                current_type, loc), loc)));
 
2082
 
 
2083
                        Expression equals_test = new Binary (Binary.Operator.Inequality, other_variable, new NullLiteral (loc));
 
2084
                        if (rs_equals != null)
 
2085
                                equals_test = new Binary (Binary.Operator.LogicalAnd, equals_test, rs_equals);
 
2086
                        equals_block.AddStatement (new Return (equals_test, loc));
 
2087
 
 
2088
                        equals.Block = equals_block;
 
2089
                        equals.Define ();
 
2090
                        Members.Add (equals);
 
2091
 
 
2092
                        //
 
2093
                        // GetHashCode () override
 
2094
                        //
 
2095
                        Method hashcode = new Method (this, new TypeExpression (Compiler.BuiltinTypes.Int, loc),
 
2096
                                Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN,
 
2097
                                new MemberName ("GetHashCode", loc),
 
2098
                                Mono.CSharp.ParametersCompiled.EmptyReadOnlyParameters, null);
 
2099
 
 
2100
                        //
 
2101
                        // Modified FNV with good avalanche behavior and uniform
 
2102
                        // distribution with larger hash sizes.
 
2103
                        //
 
2104
                        // const int FNV_prime = 16777619;
 
2105
                        // int hash = (int) 2166136261;
 
2106
                        // foreach (int d in data)
 
2107
                        //     hash = (hash ^ d) * FNV_prime;
 
2108
                        // hash += hash << 13;
 
2109
                        // hash ^= hash >> 7;
 
2110
                        // hash += hash << 3;
 
2111
                        // hash ^= hash >> 17;
 
2112
                        // hash += hash << 5;
 
2113
 
 
2114
                        ToplevelBlock hashcode_top = new ToplevelBlock (Compiler, loc);
 
2115
                        Block hashcode_block = new Block (hashcode_top, loc, loc);
 
2116
                        hashcode_top.AddStatement (new Unchecked (hashcode_block, loc));
 
2117
 
 
2118
                        var li_hash = LocalVariable.CreateCompilerGenerated (Compiler.BuiltinTypes.Int, hashcode_top, loc);
 
2119
                        hashcode_block.AddStatement (new BlockVariableDeclaration (new TypeExpression (li_hash.Type, loc), li_hash));
 
2120
                        LocalVariableReference hash_variable_assign = new LocalVariableReference (li_hash, loc);
 
2121
                        hashcode_block.AddStatement (new StatementExpression (
 
2122
                                new SimpleAssign (hash_variable_assign, rs_hashcode)));
 
2123
 
 
2124
                        var hash_variable = new LocalVariableReference (li_hash, loc);
 
2125
                        hashcode_block.AddStatement (new StatementExpression (
 
2126
                                new CompoundAssign (Binary.Operator.Addition, hash_variable,
 
2127
                                        new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 13, loc)))));
 
2128
                        hashcode_block.AddStatement (new StatementExpression (
 
2129
                                new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
 
2130
                                        new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 7, loc)))));
 
2131
                        hashcode_block.AddStatement (new StatementExpression (
 
2132
                                new CompoundAssign (Binary.Operator.Addition, hash_variable,
 
2133
                                        new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 3, loc)))));
 
2134
                        hashcode_block.AddStatement (new StatementExpression (
 
2135
                                new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
 
2136
                                        new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 17, loc)))));
 
2137
                        hashcode_block.AddStatement (new StatementExpression (
 
2138
                                new CompoundAssign (Binary.Operator.Addition, hash_variable,
 
2139
                                        new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 5, loc)))));
 
2140
 
 
2141
                        hashcode_block.AddStatement (new Return (hash_variable, loc));
 
2142
                        hashcode.Block = hashcode_top;
 
2143
                        hashcode.Define ();
 
2144
                        Members.Add (hashcode);
 
2145
 
 
2146
                        //
 
2147
                        // ToString () override
 
2148
                        //
 
2149
 
 
2150
                        ToplevelBlock tostring_block = new ToplevelBlock (Compiler, loc);
 
2151
                        tostring_block.AddStatement (new Return (string_concat, loc));
 
2152
                        tostring.Block = tostring_block;
 
2153
                        tostring.Define ();
 
2154
                        Members.Add (tostring);
 
2155
 
 
2156
                        return true;
 
2157
                }
 
2158
 
 
2159
                public override string GetSignatureForError ()
 
2160
                {
 
2161
                        return SignatureForError;
 
2162
                }
 
2163
 
 
2164
                public override CompilationSourceFile GetCompilationSourceFile ()
 
2165
                {
 
2166
                        return null;
 
2167
                }
 
2168
 
 
2169
                public IList<AnonymousTypeParameter> Parameters {
 
2170
                        get {
 
2171
                                return parameters;
 
2172
                        }
 
2173
                }
 
2174
        }
 
2175
}