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

« back to all changes in this revision

Viewing changes to contrib/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, source.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
 
                        for (int i = 0; i < Parameters.Count; ++i) {
1105
 
                                if (type_inference.ExactInference (Parameters.Types[i], d_params.Types[i]) == 0)
1106
 
                                        return false;
1107
 
                        }
1108
 
 
1109
 
                        return true;
1110
 
                }
1111
 
 
1112
 
                public TypeSpec InferReturnType (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegate_type)
1113
 
                {
1114
 
                        Expression expr;
1115
 
                        AnonymousExpression am;
1116
 
 
1117
 
                        if (compatibles.TryGetValue (delegate_type, out expr)) {
1118
 
                                am = expr as AnonymousExpression;
1119
 
                                return am == null ? null : am.ReturnType;
1120
 
                        }
1121
 
 
1122
 
                        using (ec.Set (ResolveContext.Options.ProbingMode | ResolveContext.Options.InferReturnType)) {
1123
 
                                ReportPrinter prev;
1124
 
                                if (TypeInferenceReportPrinter != null) {
1125
 
                                        prev = ec.Report.SetPrinter (TypeInferenceReportPrinter);
1126
 
                                } else {
1127
 
                                        prev = null;
1128
 
                                }
1129
 
 
1130
 
                                var body = CompatibleMethodBody (ec, tic, null, delegate_type);
1131
 
                                if (body != null) {
1132
 
                                        am = body.Compatible (ec, body);
1133
 
                                } else {
1134
 
                                        am = null;
1135
 
                                }
1136
 
 
1137
 
                                if (TypeInferenceReportPrinter != null) {
1138
 
                                        ec.Report.SetPrinter (prev);
1139
 
                                }
1140
 
                        }
1141
 
 
1142
 
                        if (am == null)
1143
 
                                return null;
1144
 
 
1145
 
//                      compatibles.Add (delegate_type, am);
1146
 
                        return am.ReturnType;
1147
 
                }
1148
 
 
1149
 
                public override bool ContainsEmitWithAwait ()
1150
 
                {
1151
 
                        return false;
1152
 
                }
1153
 
 
1154
 
                //
1155
 
                // Returns AnonymousMethod container if this anonymous method
1156
 
                // expression can be implicitly converted to the delegate type `delegate_type'
1157
 
                //
1158
 
                public Expression Compatible (ResolveContext ec, TypeSpec type)
1159
 
                {
1160
 
                        Expression am;
1161
 
                        if (compatibles.TryGetValue (type, out am))
1162
 
                                return am;
1163
 
 
1164
 
                        TypeSpec delegate_type = CompatibleChecks (ec, type);
1165
 
                        if (delegate_type == null)
1166
 
                                return null;
1167
 
 
1168
 
                        //
1169
 
                        // At this point its the first time we know the return type that is 
1170
 
                        // needed for the anonymous method.  We create the method here.
1171
 
                        //
1172
 
 
1173
 
                        var invoke_mb = Delegate.GetInvokeMethod (delegate_type);
1174
 
                        TypeSpec return_type = invoke_mb.ReturnType;
1175
 
 
1176
 
                        //
1177
 
                        // Second: the return type of the delegate must be compatible with 
1178
 
                        // the anonymous type.   Instead of doing a pass to examine the block
1179
 
                        // we satisfy the rule by setting the return type on the EmitContext
1180
 
                        // to be the delegate type return type.
1181
 
                        //
1182
 
 
1183
 
                        var body = CompatibleMethodBody (ec, null, return_type, delegate_type);
1184
 
                        if (body == null)
1185
 
                                return null;
1186
 
 
1187
 
                        bool etree_conversion = delegate_type != type;
1188
 
 
1189
 
                        try {
1190
 
                                if (etree_conversion) {
1191
 
                                        if (ec.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
1192
 
                                                //
1193
 
                                                // Nested expression tree lambda use same scope as parent
1194
 
                                                // lambda, this also means no variable capturing between this
1195
 
                                                // and parent scope
1196
 
                                                //
1197
 
                                                am = body.Compatible (ec, ec.CurrentAnonymousMethod);
1198
 
 
1199
 
                                                //
1200
 
                                                // Quote nested expression tree
1201
 
                                                //
1202
 
                                                if (am != null)
1203
 
                                                        am = new Quote (am);
1204
 
                                        } else {
1205
 
                                                int errors = ec.Report.Errors;
1206
 
 
1207
 
                                                if (Block.IsAsync) {
1208
 
                                                        ec.Report.Error (1989, loc, "Async lambda expressions cannot be converted to expression trees");
1209
 
                                                }
1210
 
 
1211
 
                                                using (ec.Set (ResolveContext.Options.ExpressionTreeConversion)) {
1212
 
                                                        am = body.Compatible (ec);
1213
 
                                                }
1214
 
 
1215
 
                                                //
1216
 
                                                // Rewrite expressions into expression tree when targeting Expression<T>
1217
 
                                                //
1218
 
                                                if (am != null && errors == ec.Report.Errors)
1219
 
                                                        am = CreateExpressionTree (ec, delegate_type);
1220
 
                                        }
1221
 
                                } else {
1222
 
                                        am = body.Compatible (ec);
1223
 
                                }
1224
 
                        } catch (CompletionResult) {
1225
 
                                throw;
1226
 
                        } catch (FatalException) {
1227
 
                                throw;
1228
 
                        } catch (Exception e) {
1229
 
                                throw new InternalErrorException (e, loc);
1230
 
                        }
1231
 
 
1232
 
                        if (!ec.IsInProbingMode) {
1233
 
                                compatibles.Add (type, am ?? EmptyExpression.Null);
1234
 
                        }
1235
 
 
1236
 
                        return am;
1237
 
                }
1238
 
 
1239
 
                protected virtual Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type)
1240
 
                {
1241
 
                        return CreateExpressionTree (ec);
1242
 
                }
1243
 
 
1244
 
                public override Expression CreateExpressionTree (ResolveContext ec)
1245
 
                {
1246
 
                        ec.Report.Error (1946, loc, "An anonymous method cannot be converted to an expression tree");
1247
 
                        return null;
1248
 
                }
1249
 
 
1250
 
                protected virtual ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegate_type)
1251
 
                {
1252
 
                        var delegate_parameters = Delegate.GetParameters (delegate_type);
1253
 
 
1254
 
                        if (Parameters == ParametersCompiled.Undefined) {
1255
 
                                //
1256
 
                                // We provide a set of inaccessible parameters
1257
 
                                //
1258
 
                                Parameter[] fixedpars = new Parameter[delegate_parameters.Count];
1259
 
 
1260
 
                                for (int i = 0; i < delegate_parameters.Count; i++) {
1261
 
                                        Parameter.Modifier i_mod = delegate_parameters.FixedParameters [i].ModFlags;
1262
 
                                        if ((i_mod & Parameter.Modifier.OUT) != 0) {
1263
 
                                                if (!ec.IsInProbingMode) {
1264
 
                                                        ec.Report.Error (1688, loc,
1265
 
                                                                "Cannot convert anonymous method block without a parameter list to delegate type `{0}' because it has one or more `out' parameters",
1266
 
                                                                delegate_type.GetSignatureForError ());
1267
 
                                                }
1268
 
 
1269
 
                                                return null;
1270
 
                                        }
1271
 
                                        fixedpars[i] = new Parameter (
1272
 
                                                new TypeExpression (delegate_parameters.Types [i], loc), null,
1273
 
                                                delegate_parameters.FixedParameters [i].ModFlags, null, loc);
1274
 
                                }
1275
 
 
1276
 
                                return ParametersCompiled.CreateFullyResolved (fixedpars, delegate_parameters.Types);
1277
 
                        }
1278
 
 
1279
 
                        if (!VerifyExplicitParameters (ec, delegate_type, delegate_parameters)) {
1280
 
                                return null;
1281
 
                        }
1282
 
 
1283
 
                        return Parameters;
1284
 
                }
1285
 
 
1286
 
                protected override Expression DoResolve (ResolveContext ec)
1287
 
                {
1288
 
                        if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
1289
 
                                ec.Report.Error (1706, loc, "Anonymous methods and lambda expressions cannot be used in the current context");
1290
 
                                return null;
1291
 
                        }
1292
 
 
1293
 
                        //
1294
 
                        // Set class type, set type
1295
 
                        //
1296
 
 
1297
 
                        eclass = ExprClass.Value;
1298
 
 
1299
 
                        //
1300
 
                        // This hack means `The type is not accessible
1301
 
                        // anywhere', we depend on special conversion
1302
 
                        // rules.
1303
 
                        // 
1304
 
                        type = InternalType.AnonymousMethod;
1305
 
 
1306
 
                        if (!DoResolveParameters (ec))
1307
 
                                return null;
1308
 
 
1309
 
#if !STATIC
1310
 
                        // FIXME: The emitted code isn't very careful about reachability
1311
 
                        // so, ensure we have a 'ret' at the end
1312
 
                        BlockContext bc = ec as BlockContext;
1313
 
                        if (bc != null && bc.CurrentBranching != null && bc.CurrentBranching.CurrentUsageVector.IsUnreachable)
1314
 
                                bc.NeedReturnLabel ();
1315
 
#endif
1316
 
                        return this;
1317
 
                }
1318
 
 
1319
 
                protected virtual bool DoResolveParameters (ResolveContext rc)
1320
 
                {
1321
 
                        return Parameters.Resolve (rc);
1322
 
                }
1323
 
 
1324
 
                public override void Emit (EmitContext ec)
1325
 
                {
1326
 
                        // nothing, as we only exist to not do anything.
1327
 
                }
1328
 
 
1329
 
                public static void Error_AddressOfCapturedVar (ResolveContext ec, IVariableReference var, Location loc)
1330
 
                {
1331
 
                        ec.Report.Error (1686, loc,
1332
 
                                "Local variable or parameter `{0}' cannot have their address taken and be used inside an anonymous method, lambda expression or query expression",
1333
 
                                var.Name);
1334
 
                }
1335
 
 
1336
 
                public override string GetSignatureForError ()
1337
 
                {
1338
 
                        return ExprClassName;
1339
 
                }
1340
 
 
1341
 
                AnonymousMethodBody CompatibleMethodBody (ResolveContext ec, TypeInferenceContext tic, TypeSpec return_type, TypeSpec delegate_type)
1342
 
                {
1343
 
                        ParametersCompiled p = ResolveParameters (ec, tic, delegate_type);
1344
 
                        if (p == null)
1345
 
                                return null;
1346
 
 
1347
 
                        ParametersBlock b = ec.IsInProbingMode ? (ParametersBlock) Block.PerformClone () : Block;
1348
 
 
1349
 
                        if (b.IsAsync) {
1350
 
                                var rt = return_type;
1351
 
                                if (rt != null && rt.Kind != MemberKind.Void && rt != ec.Module.PredefinedTypes.Task.TypeSpec && !rt.IsGenericTask) {
1352
 
                                        ec.Report.Error (4010, loc, "Cannot convert async {0} to delegate type `{1}'",
1353
 
                                                GetSignatureForError (), delegate_type.GetSignatureForError ());
1354
 
 
1355
 
                                        return null;
1356
 
                                }
1357
 
 
1358
 
                                b = b.ConvertToAsyncTask (ec, ec.CurrentMemberDefinition.Parent.PartialContainer, p, return_type, loc);
1359
 
                        }
1360
 
 
1361
 
                        return CompatibleMethodFactory (return_type ?? InternalType.Arglist, delegate_type, p, b);
1362
 
                }
1363
 
 
1364
 
                protected virtual AnonymousMethodBody CompatibleMethodFactory (TypeSpec return_type, TypeSpec delegate_type, ParametersCompiled p, ParametersBlock b)
1365
 
                {
1366
 
                        return new AnonymousMethodBody (p, b, return_type, delegate_type, loc);
1367
 
                }
1368
 
 
1369
 
                protected override void CloneTo (CloneContext clonectx, Expression t)
1370
 
                {
1371
 
                        AnonymousMethodExpression target = (AnonymousMethodExpression) t;
1372
 
 
1373
 
                        target.Block = (ParametersBlock) clonectx.LookupBlock (Block);
1374
 
                }
1375
 
                
1376
 
                public override object Accept (StructuralVisitor visitor)
1377
 
                {
1378
 
                        return visitor.Visit (this);
1379
 
                }
1380
 
        }
1381
 
 
1382
 
        //
1383
 
        // Abstract expression for any block which requires variables hoisting
1384
 
        //
1385
 
        public abstract class AnonymousExpression : ExpressionStatement
1386
 
        {
1387
 
                protected class AnonymousMethodMethod : Method
1388
 
                {
1389
 
                        public readonly AnonymousExpression AnonymousMethod;
1390
 
                        public readonly AnonymousMethodStorey Storey;
1391
 
 
1392
 
                        public AnonymousMethodMethod (TypeDefinition parent, AnonymousExpression am, AnonymousMethodStorey storey,
1393
 
                                                          TypeExpr return_type,
1394
 
                                                          Modifiers mod, MemberName name,
1395
 
                                                          ParametersCompiled parameters)
1396
 
                                : base (parent, return_type, mod | Modifiers.COMPILER_GENERATED,
1397
 
                                                name, parameters, null)
1398
 
                        {
1399
 
                                this.AnonymousMethod = am;
1400
 
                                this.Storey = storey;
1401
 
 
1402
 
                                Parent.PartialContainer.Members.Add (this);
1403
 
                                Block = new ToplevelBlock (am.block, parameters);
1404
 
                        }
1405
 
 
1406
 
                        public override EmitContext CreateEmitContext (ILGenerator ig, SourceMethodBuilder sourceMethod)
1407
 
                        {
1408
 
                                EmitContext ec = new EmitContext (this, ig, ReturnType, sourceMethod);
1409
 
                                ec.CurrentAnonymousMethod = AnonymousMethod;
1410
 
                                return ec;
1411
 
                        }
1412
 
 
1413
 
                        protected override void DefineTypeParameters ()
1414
 
                        {
1415
 
                                // Type parameters were cloned
1416
 
                        }
1417
 
 
1418
 
                        protected override bool ResolveMemberType ()
1419
 
                        {
1420
 
                                if (!base.ResolveMemberType ())
1421
 
                                        return false;
1422
 
 
1423
 
                                if (Storey != null && Storey.Mutator != null) {
1424
 
                                        if (!parameters.IsEmpty) {
1425
 
                                                var mutated = Storey.Mutator.Mutate (parameters.Types);
1426
 
                                                if (mutated != parameters.Types)
1427
 
                                                        parameters = ParametersCompiled.CreateFullyResolved ((Parameter[]) parameters.FixedParameters, mutated);
1428
 
                                        }
1429
 
 
1430
 
                                        member_type = Storey.Mutator.Mutate (member_type);
1431
 
                                }
1432
 
 
1433
 
                                return true;
1434
 
                        }
1435
 
 
1436
 
                        public override void Emit ()
1437
 
                        {
1438
 
                                if (MethodBuilder == null) {
1439
 
                                        Define ();
1440
 
                                }
1441
 
 
1442
 
                                base.Emit ();
1443
 
                        }
1444
 
                }
1445
 
 
1446
 
                protected ParametersBlock block;
1447
 
 
1448
 
                public TypeSpec ReturnType;
1449
 
 
1450
 
                protected AnonymousExpression (ParametersBlock block, TypeSpec return_type, Location loc)
1451
 
                {
1452
 
                        this.ReturnType = return_type;
1453
 
                        this.block = block;
1454
 
                        this.loc = loc;
1455
 
                }
1456
 
 
1457
 
                public abstract string ContainerType { get; }
1458
 
                public abstract bool IsIterator { get; }
1459
 
                public abstract AnonymousMethodStorey Storey { get; }
1460
 
 
1461
 
                //
1462
 
                // The block that makes up the body for the anonymous method
1463
 
                //
1464
 
                public ParametersBlock Block {
1465
 
                        get {
1466
 
                                return block;
1467
 
                        }
1468
 
                }
1469
 
 
1470
 
                public AnonymousExpression Compatible (ResolveContext ec)
1471
 
                {
1472
 
                        return Compatible (ec, this);
1473
 
                }
1474
 
 
1475
 
                public AnonymousExpression Compatible (ResolveContext ec, AnonymousExpression ae)
1476
 
                {
1477
 
                        if (block.Resolved)
1478
 
                                return this;
1479
 
 
1480
 
                        // TODO: Implement clone
1481
 
                        BlockContext aec = new BlockContext (ec, block, ReturnType);
1482
 
                        aec.CurrentAnonymousMethod = ae;
1483
 
 
1484
 
                        ResolveContext.Options flags = 0;
1485
 
 
1486
 
                        var am = this as AnonymousMethodBody;
1487
 
 
1488
 
                        if (ec.HasSet (ResolveContext.Options.InferReturnType) && am != null) {
1489
 
                                am.ReturnTypeInference = new TypeInferenceContext ();
1490
 
                        }
1491
 
 
1492
 
                        if (ec.IsInProbingMode)
1493
 
                                flags |= ResolveContext.Options.ProbingMode;
1494
 
 
1495
 
                        if (ec.HasSet (ResolveContext.Options.FieldInitializerScope))
1496
 
                                flags |= ResolveContext.Options.FieldInitializerScope;
1497
 
 
1498
 
                        if (ec.HasSet (ResolveContext.Options.ExpressionTreeConversion))
1499
 
                                flags |= ResolveContext.Options.ExpressionTreeConversion;
1500
 
 
1501
 
                        aec.Set (flags);
1502
 
 
1503
 
                        var errors = ec.Report.Errors;
1504
 
 
1505
 
                        bool res = Block.Resolve (ec.CurrentBranching, aec, null);
1506
 
 
1507
 
                        if (am != null && am.ReturnTypeInference != null) {
1508
 
                                am.ReturnTypeInference.FixAllTypes (ec);
1509
 
                                ReturnType = am.ReturnTypeInference.InferredTypeArguments [0];
1510
 
                                am.ReturnTypeInference = null;
1511
 
 
1512
 
                                //
1513
 
                                // If e is synchronous the inferred return type is T
1514
 
                                // If e is asynchronous the inferred return type is Task<T>
1515
 
                                //
1516
 
                                if (block.IsAsync && ReturnType != null) {
1517
 
                                        ReturnType = ec.Module.PredefinedTypes.TaskGeneric.TypeSpec.MakeGenericType (ec, new [] { ReturnType });
1518
 
                                }
1519
 
                        }
1520
 
 
1521
 
                        if (res && errors != ec.Report.Errors)
1522
 
                                return null;
1523
 
 
1524
 
                        return res ? this : null;
1525
 
                }
1526
 
 
1527
 
                public override bool ContainsEmitWithAwait ()
1528
 
                {
1529
 
                        return false;
1530
 
                }
1531
 
 
1532
 
                public void SetHasThisAccess ()
1533
 
                {
1534
 
                        ExplicitBlock b = block;
1535
 
                        do {
1536
 
                                if (b.HasCapturedThis)
1537
 
                                        return;
1538
 
 
1539
 
                                b.HasCapturedThis = true;
1540
 
                                b = b.Parent == null ? null : b.Parent.Explicit;
1541
 
                        } while (b != null);
1542
 
                }
1543
 
        }
1544
 
 
1545
 
        public class AnonymousMethodBody : AnonymousExpression
1546
 
        {
1547
 
                protected readonly ParametersCompiled parameters;
1548
 
                AnonymousMethodStorey storey;
1549
 
 
1550
 
                AnonymousMethodMethod method;
1551
 
                Field am_cache;
1552
 
                string block_name;
1553
 
                TypeInferenceContext return_inference;
1554
 
 
1555
 
                public AnonymousMethodBody (ParametersCompiled parameters,
1556
 
                                        ParametersBlock block, TypeSpec return_type, TypeSpec delegate_type,
1557
 
                                        Location loc)
1558
 
                        : base (block, return_type, loc)
1559
 
                {
1560
 
                        this.type = delegate_type;
1561
 
                        this.parameters = parameters;
1562
 
                }
1563
 
 
1564
 
                #region Properties
1565
 
 
1566
 
                public override string ContainerType {
1567
 
                        get { return "anonymous method"; }
1568
 
                }
1569
 
 
1570
 
                public override bool IsIterator {
1571
 
                        get {
1572
 
                                return false;
1573
 
                        }
1574
 
                }
1575
 
 
1576
 
                public ParametersCompiled Parameters {
1577
 
                        get {
1578
 
                                return parameters;
1579
 
                        }
1580
 
                }
1581
 
 
1582
 
                public TypeInferenceContext ReturnTypeInference {
1583
 
                        get {
1584
 
                                return return_inference;
1585
 
                        }
1586
 
                        set {
1587
 
                                return_inference = value;
1588
 
                        }
1589
 
                }
1590
 
 
1591
 
                public override AnonymousMethodStorey Storey {
1592
 
                        get { return storey; }
1593
 
                }
1594
 
 
1595
 
                #endregion
1596
 
 
1597
 
                public override Expression CreateExpressionTree (ResolveContext ec)
1598
 
                {
1599
 
                        ec.Report.Error (1945, loc, "An expression tree cannot contain an anonymous method expression");
1600
 
                        return null;
1601
 
                }
1602
 
 
1603
 
                bool Define (ResolveContext ec)
1604
 
                {
1605
 
                        if (!Block.Resolved && Compatible (ec) == null)
1606
 
                                return false;
1607
 
 
1608
 
                        if (block_name == null) {
1609
 
                                MemberCore mc = (MemberCore) ec.MemberContext;
1610
 
                                block_name = mc.MemberName.Basename;
1611
 
                        }
1612
 
 
1613
 
                        return true;
1614
 
                }
1615
 
 
1616
 
                //
1617
 
                // Creates a host for the anonymous method
1618
 
                //
1619
 
                AnonymousMethodMethod DoCreateMethodHost (EmitContext ec)
1620
 
                {
1621
 
                        //
1622
 
                        // Anonymous method body can be converted to
1623
 
                        //
1624
 
                        // 1, an instance method in current scope when only `this' is hoisted
1625
 
                        // 2, a static method in current scope when neither `this' nor any variable is hoisted
1626
 
                        // 3, an instance method in compiler generated storey when any hoisted variable exists
1627
 
                        //
1628
 
 
1629
 
                        Modifiers modifiers;
1630
 
                        TypeDefinition parent = null;
1631
 
 
1632
 
                        var src_block = Block.Original.Explicit;
1633
 
                        if (src_block.HasCapturedVariable || src_block.HasCapturedThis) {
1634
 
                                parent = storey = FindBestMethodStorey ();
1635
 
 
1636
 
                                if (storey == null) {
1637
 
                                        var sm = src_block.ParametersBlock.TopBlock.StateMachine;
1638
 
 
1639
 
                                        //
1640
 
                                        // Remove hoisted this demand when simple instance method is enough
1641
 
                                        //
1642
 
                                        if (src_block.HasCapturedThis) {
1643
 
                                                src_block.ParametersBlock.TopBlock.RemoveThisReferenceFromChildrenBlock (src_block);
1644
 
 
1645
 
                                                //
1646
 
                                                // Special case where parent class is used to emit instance method
1647
 
                                                // because currect storey is of value type (async host) and we don't
1648
 
                                                // want to create another childer storey to host this reference only
1649
 
                                                //
1650
 
                                                if (sm != null && sm.Kind == MemberKind.Struct)
1651
 
                                                        parent = sm.Parent.PartialContainer;
1652
 
                                        }
1653
 
 
1654
 
                                        //
1655
 
                                        // For iterators we can host everything in one class
1656
 
                                        //
1657
 
                                        if (sm is IteratorStorey)
1658
 
                                                parent = storey = sm;
1659
 
                                }
1660
 
 
1661
 
                                modifiers = storey != null ? Modifiers.INTERNAL : Modifiers.PRIVATE;
1662
 
                        } else {
1663
 
                                if (ec.CurrentAnonymousMethod != null)
1664
 
                                        parent = storey = ec.CurrentAnonymousMethod.Storey;
1665
 
 
1666
 
                                modifiers = Modifiers.STATIC | Modifiers.PRIVATE;
1667
 
                        }
1668
 
 
1669
 
                        if (parent == null)
1670
 
                                parent = ec.CurrentTypeDefinition.Parent.PartialContainer;
1671
 
 
1672
 
                        string name = CompilerGeneratedContainer.MakeName (parent != storey ? block_name : null,
1673
 
                                "m", null, ec.Module.CounterAnonymousMethods++);
1674
 
 
1675
 
                        MemberName member_name;
1676
 
                        if (storey == null && ec.CurrentTypeParameters != null) {
1677
 
 
1678
 
                                var hoisted_tparams = ec.CurrentTypeParameters;
1679
 
                                var type_params = new TypeParameters (hoisted_tparams.Count);
1680
 
                                for (int i = 0; i < hoisted_tparams.Count; ++i) {
1681
 
                                    type_params.Add (hoisted_tparams[i].CreateHoistedCopy (null));
1682
 
                                }
1683
 
 
1684
 
                                member_name = new MemberName (name, type_params, Location);
1685
 
                        } else {
1686
 
                                member_name = new MemberName (name, Location);
1687
 
                        }
1688
 
 
1689
 
                        return new AnonymousMethodMethod (parent,
1690
 
                                this, storey, new TypeExpression (ReturnType, Location), modifiers,
1691
 
                                member_name, parameters);
1692
 
                }
1693
 
 
1694
 
                protected override Expression DoResolve (ResolveContext ec)
1695
 
                {
1696
 
                        if (!Define (ec))
1697
 
                                return null;
1698
 
 
1699
 
                        eclass = ExprClass.Value;
1700
 
                        return this;
1701
 
                }
1702
 
 
1703
 
                public override void Emit (EmitContext ec)
1704
 
                {
1705
 
                        //
1706
 
                        // Use same anonymous method implementation for scenarios where same
1707
 
                        // code is used from multiple blocks, e.g. field initializers
1708
 
                        //
1709
 
                        if (method == null) {
1710
 
                                //
1711
 
                                // Delay an anonymous method definition to avoid emitting unused code
1712
 
                                // for unreachable blocks or expression trees
1713
 
                                //
1714
 
                                method = DoCreateMethodHost (ec);
1715
 
                                method.Define ();
1716
 
                        }
1717
 
 
1718
 
                        bool is_static = (method.ModFlags & Modifiers.STATIC) != 0;
1719
 
                        if (is_static && am_cache == null) {
1720
 
                                //
1721
 
                                // Creates a field cache to store delegate instance if it's not generic
1722
 
                                //
1723
 
                                if (!method.MemberName.IsGeneric) {
1724
 
                                        var parent = method.Parent.PartialContainer;
1725
 
                                        int id = parent.AnonymousMethodsCounter++;
1726
 
                                        var cache_type = storey != null && storey.Mutator != null ? storey.Mutator.Mutate (type) : type;
1727
 
 
1728
 
                                        am_cache = new Field (parent, new TypeExpression (cache_type, loc),
1729
 
                                                Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
1730
 
                                                new MemberName (CompilerGeneratedContainer.MakeName (null, "f", "am$cache", id), loc), null);
1731
 
                                        am_cache.Define ();
1732
 
                                        parent.AddField (am_cache);
1733
 
                                } else {
1734
 
                                        // TODO: Implement caching of generated generic static methods
1735
 
                                        //
1736
 
                                        // Idea:
1737
 
                                        //
1738
 
                                        // Some extra class is needed to capture variable generic type
1739
 
                                        // arguments. Maybe we could re-use anonymous types, with a unique
1740
 
                                        // anonymous method id, but they are quite heavy.
1741
 
                                        //
1742
 
                                        // Consider : "() => typeof(T);"
1743
 
                                        //
1744
 
                                        // We need something like
1745
 
                                        // static class Wrap<Tn, Tm, DelegateType> {
1746
 
                                        //              public static DelegateType cache;
1747
 
                                        // }
1748
 
                                        //
1749
 
                                        // We then specialize local variable to capture all generic parameters
1750
 
                                        // and delegate type, e.g. "Wrap<Ta, Tb, DelegateTypeInst> cache;"
1751
 
                                        //
1752
 
                                }
1753
 
                        }
1754
 
 
1755
 
                        Label l_initialized = ec.DefineLabel ();
1756
 
 
1757
 
                        if (am_cache != null) {
1758
 
                                ec.Emit (OpCodes.Ldsfld, am_cache.Spec);
1759
 
                                ec.Emit (OpCodes.Brtrue_S, l_initialized);
1760
 
                        }
1761
 
 
1762
 
                        //
1763
 
                        // Load method delegate implementation
1764
 
                        //
1765
 
 
1766
 
                        if (is_static) {
1767
 
                                ec.EmitNull ();
1768
 
                        } else if (storey != null) {
1769
 
                                Expression e = storey.GetStoreyInstanceExpression (ec).Resolve (new ResolveContext (ec.MemberContext));
1770
 
                                if (e != null) {
1771
 
                                        e.Emit (ec);
1772
 
                                }
1773
 
                        } else {
1774
 
                                ec.EmitThis ();
1775
 
 
1776
 
                                //
1777
 
                                // Special case for value type storey where this is not lifted but
1778
 
                                // droped off to parent class
1779
 
                                //
1780
 
                                for (var b = Block.Parent; b != null; b = b.Parent) {
1781
 
                                        if (b.ParametersBlock.StateMachine != null) {
1782
 
                                                ec.Emit (OpCodes.Ldfld, b.ParametersBlock.StateMachine.HoistedThis.Field.Spec);
1783
 
                                                break;
1784
 
                                        }
1785
 
                                }
1786
 
                        }
1787
 
 
1788
 
                        var delegate_method = method.Spec;
1789
 
                        if (storey != null && storey.MemberName.IsGeneric) {
1790
 
                                TypeSpec t = storey.Instance.Type;
1791
 
 
1792
 
                                //
1793
 
                                // Mutate anonymous method instance type if we are in nested
1794
 
                                // hoisted generic anonymous method storey
1795
 
                                //
1796
 
                                if (ec.IsAnonymousStoreyMutateRequired) {
1797
 
                                        t = storey.Mutator.Mutate (t);
1798
 
                                }
1799
 
 
1800
 
                                ec.Emit (OpCodes.Ldftn, TypeBuilder.GetMethod (t.GetMetaInfo (), (MethodInfo) delegate_method.GetMetaInfo ()));
1801
 
                        } else {
1802
 
                                if (delegate_method.IsGeneric)
1803
 
                                        delegate_method = delegate_method.MakeGenericMethod (ec.MemberContext, method.TypeParameters);
1804
 
 
1805
 
                                ec.Emit (OpCodes.Ldftn, delegate_method);
1806
 
                        }
1807
 
 
1808
 
                        var constructor_method = Delegate.GetConstructor (type);
1809
 
                        ec.Emit (OpCodes.Newobj, constructor_method);
1810
 
 
1811
 
                        if (am_cache != null) {
1812
 
                                ec.Emit (OpCodes.Stsfld, am_cache.Spec);
1813
 
                                ec.MarkLabel (l_initialized);
1814
 
                                ec.Emit (OpCodes.Ldsfld, am_cache.Spec);
1815
 
                        }
1816
 
                }
1817
 
 
1818
 
                public override void EmitStatement (EmitContext ec)
1819
 
                {
1820
 
                        throw new NotImplementedException ();
1821
 
                }
1822
 
 
1823
 
                //
1824
 
                // Look for the best storey for this anonymous method
1825
 
                //
1826
 
                AnonymousMethodStorey FindBestMethodStorey ()
1827
 
                {
1828
 
                        //
1829
 
                        // Use the nearest parent block which has a storey
1830
 
                        //
1831
 
                        for (Block b = Block.Parent; b != null; b = b.Parent) {
1832
 
                                AnonymousMethodStorey s = b.Explicit.AnonymousMethodStorey;
1833
 
                                if (s != null)
1834
 
                                        return s;
1835
 
                        }
1836
 
                                        
1837
 
                        return null;
1838
 
                }
1839
 
 
1840
 
                public override string GetSignatureForError ()
1841
 
                {
1842
 
                        return TypeManager.CSharpName (type);
1843
 
                }
1844
 
        }
1845
 
 
1846
 
        //
1847
 
        // Anonymous type container
1848
 
        //
1849
 
        public class AnonymousTypeClass : CompilerGeneratedContainer
1850
 
        {
1851
 
                public const string ClassNamePrefix = "<>__AnonType";
1852
 
                public const string SignatureForError = "anonymous type";
1853
 
                
1854
 
                readonly IList<AnonymousTypeParameter> parameters;
1855
 
 
1856
 
                private AnonymousTypeClass (ModuleContainer parent, MemberName name, IList<AnonymousTypeParameter> parameters, Location loc)
1857
 
                        : base (parent, name, parent.Evaluator != null ? Modifiers.PUBLIC : Modifiers.INTERNAL)
1858
 
                {
1859
 
                        this.parameters = parameters;
1860
 
                }
1861
 
 
1862
 
                public static AnonymousTypeClass Create (TypeContainer parent, IList<AnonymousTypeParameter> parameters, Location loc)
1863
 
                {
1864
 
                        string name = ClassNamePrefix + parent.Module.CounterAnonymousTypes++;
1865
 
 
1866
 
                        ParametersCompiled all_parameters;
1867
 
                        TypeParameters tparams = null;
1868
 
                        SimpleName[] t_args;
1869
 
 
1870
 
                        if (parameters.Count == 0) {
1871
 
                                all_parameters = ParametersCompiled.EmptyReadOnlyParameters;
1872
 
                                t_args = null;
1873
 
                        } else {
1874
 
                                t_args = new SimpleName[parameters.Count];
1875
 
                                tparams = new TypeParameters ();
1876
 
                                Parameter[] ctor_params = new Parameter[parameters.Count];
1877
 
                                for (int i = 0; i < parameters.Count; ++i) {
1878
 
                                        AnonymousTypeParameter p = parameters[i];
1879
 
                                        for (int ii = 0; ii < i; ++ii) {
1880
 
                                                if (parameters[ii].Name == p.Name) {
1881
 
                                                        parent.Compiler.Report.Error (833, parameters[ii].Location,
1882
 
                                                                "`{0}': An anonymous type cannot have multiple properties with the same name",
1883
 
                                                                        p.Name);
1884
 
 
1885
 
                                                        p = new AnonymousTypeParameter (null, "$" + i.ToString (), p.Location);
1886
 
                                                        parameters[i] = p;
1887
 
                                                        break;
1888
 
                                                }
1889
 
                                        }
1890
 
 
1891
 
                                        t_args[i] = new SimpleName ("<" + p.Name + ">__T", p.Location);
1892
 
                                        tparams.Add (new TypeParameter (i, new MemberName (t_args[i].Name, p.Location), null, null, Variance.None));
1893
 
                                        ctor_params[i] = new Parameter (t_args[i], p.Name, Parameter.Modifier.NONE, null, p.Location);
1894
 
                                }
1895
 
 
1896
 
                                all_parameters = new ParametersCompiled (ctor_params);
1897
 
                        }
1898
 
 
1899
 
                        //
1900
 
                        // Create generic anonymous type host with generic arguments
1901
 
                        // named upon properties names
1902
 
                        //
1903
 
                        AnonymousTypeClass a_type = new AnonymousTypeClass (parent.Module, new MemberName (name, tparams, loc), parameters, loc);
1904
 
 
1905
 
                        Constructor c = new Constructor (a_type, name, Modifiers.PUBLIC | Modifiers.DEBUGGER_HIDDEN,
1906
 
                                null, all_parameters, loc);
1907
 
                        c.Block = new ToplevelBlock (parent.Module.Compiler, c.ParameterInfo, loc);
1908
 
 
1909
 
                        // 
1910
 
                        // Create fields and constructor body with field initialization
1911
 
                        //
1912
 
                        bool error = false;
1913
 
                        for (int i = 0; i < parameters.Count; ++i) {
1914
 
                                AnonymousTypeParameter p = parameters [i];
1915
 
 
1916
 
                                Field f = new Field (a_type, t_args [i], Modifiers.PRIVATE | Modifiers.READONLY | Modifiers.DEBUGGER_HIDDEN,
1917
 
                                        new MemberName ("<" + p.Name + ">", p.Location), null);
1918
 
 
1919
 
                                if (!a_type.AddField (f)) {
1920
 
                                        error = true;
1921
 
                                        continue;
1922
 
                                }
1923
 
 
1924
 
                                c.Block.AddStatement (new StatementExpression (
1925
 
                                        new SimpleAssign (new MemberAccess (new This (p.Location), f.Name),
1926
 
                                                c.Block.GetParameterReference (i, p.Location))));
1927
 
 
1928
 
                                ToplevelBlock get_block = new ToplevelBlock (parent.Module.Compiler, p.Location);
1929
 
                                get_block.AddStatement (new Return (
1930
 
                                        new MemberAccess (new This (p.Location), f.Name), p.Location));
1931
 
 
1932
 
                                Property prop = new Property (a_type, t_args [i], Modifiers.PUBLIC,
1933
 
                                        new MemberName (p.Name, p.Location), null);
1934
 
                                prop.Get = new Property.GetMethod (prop, 0, null, p.Location);
1935
 
                                prop.Get.Block = get_block;
1936
 
                                a_type.AddMember (prop);
1937
 
                        }
1938
 
 
1939
 
                        if (error)
1940
 
                                return null;
1941
 
 
1942
 
                        a_type.AddConstructor (c);
1943
 
                        return a_type;
1944
 
                }
1945
 
                
1946
 
                protected override bool DoDefineMembers ()
1947
 
                {
1948
 
                        if (!base.DoDefineMembers ())
1949
 
                                return false;
1950
 
 
1951
 
                        Location loc = Location;
1952
 
 
1953
 
                        var equals_parameters = ParametersCompiled.CreateFullyResolved (
1954
 
                                new Parameter (new TypeExpression (Compiler.BuiltinTypes.Object, loc), "obj", 0, null, loc), Compiler.BuiltinTypes.Object);
1955
 
 
1956
 
                        Method equals = new Method (this, new TypeExpression (Compiler.BuiltinTypes.Bool, loc),
1957
 
                                Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN, new MemberName ("Equals", loc),
1958
 
                                equals_parameters, null);
1959
 
 
1960
 
                        equals_parameters[0].Resolve (equals, 0);
1961
 
 
1962
 
                        Method tostring = new Method (this, new TypeExpression (Compiler.BuiltinTypes.String, loc),
1963
 
                                Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN, new MemberName ("ToString", loc),
1964
 
                                Mono.CSharp.ParametersCompiled.EmptyReadOnlyParameters, null);
1965
 
 
1966
 
                        ToplevelBlock equals_block = new ToplevelBlock (Compiler, equals.ParameterInfo, loc);
1967
 
 
1968
 
                        TypeExpr current_type;
1969
 
                        if (CurrentTypeParameters != null) {
1970
 
                                var targs = new TypeArguments ();
1971
 
                                for (int i = 0; i < CurrentTypeParameters.Count; ++i) {
1972
 
                                        targs.Add (new TypeParameterExpr (CurrentTypeParameters[i], Location));
1973
 
                                }
1974
 
 
1975
 
                                current_type = new GenericTypeExpr (Definition, targs, loc);
1976
 
                        } else {
1977
 
                                current_type = new TypeExpression (Definition, loc);
1978
 
                        }
1979
 
 
1980
 
                        var li_other = LocalVariable.CreateCompilerGenerated (CurrentType, equals_block, loc);
1981
 
                        equals_block.AddStatement (new BlockVariableDeclaration (new TypeExpression (li_other.Type, loc), li_other));
1982
 
                        var other_variable = new LocalVariableReference (li_other, loc);
1983
 
 
1984
 
                        MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
1985
 
                                new QualifiedAliasMember ("global", "System", loc), "Collections", loc), "Generic", loc);
1986
 
 
1987
 
                        Expression rs_equals = null;
1988
 
                        Expression string_concat = new StringConstant (Compiler.BuiltinTypes, "{", loc);
1989
 
                        Expression rs_hashcode = new IntConstant (Compiler.BuiltinTypes, -2128831035, loc);
1990
 
                        for (int i = 0; i < parameters.Count; ++i) {
1991
 
                                var p = parameters [i];
1992
 
                                var f = (Field) Members [i * 2];
1993
 
 
1994
 
                                MemberAccess equality_comparer = new MemberAccess (new MemberAccess (
1995
 
                                        system_collections_generic, "EqualityComparer",
1996
 
                                                new TypeArguments (new SimpleName (CurrentTypeParameters [i].Name, loc)), loc),
1997
 
                                                "Default", loc);
1998
 
 
1999
 
                                Arguments arguments_equal = new Arguments (2);
2000
 
                                arguments_equal.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
2001
 
                                arguments_equal.Add (new Argument (new MemberAccess (other_variable, f.Name)));
2002
 
 
2003
 
                                Expression field_equal = new Invocation (new MemberAccess (equality_comparer,
2004
 
                                        "Equals", loc), arguments_equal);
2005
 
 
2006
 
                                Arguments arguments_hashcode = new Arguments (1);
2007
 
                                arguments_hashcode.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
2008
 
                                Expression field_hashcode = new Invocation (new MemberAccess (equality_comparer,
2009
 
                                        "GetHashCode", loc), arguments_hashcode);
2010
 
 
2011
 
                                IntConstant FNV_prime = new IntConstant (Compiler.BuiltinTypes, 16777619, loc);                         
2012
 
                                rs_hashcode = new Binary (Binary.Operator.Multiply,
2013
 
                                        new Binary (Binary.Operator.ExclusiveOr, rs_hashcode, field_hashcode, loc),
2014
 
                                        FNV_prime, loc);
2015
 
 
2016
 
                                Expression field_to_string = new Conditional (new BooleanExpression (new Binary (Binary.Operator.Inequality,
2017
 
                                        new MemberAccess (new This (f.Location), f.Name), new NullLiteral (loc), loc)),
2018
 
                                        new Invocation (new MemberAccess (
2019
 
                                                new MemberAccess (new This (f.Location), f.Name), "ToString"), null),
2020
 
                                        new StringConstant (Compiler.BuiltinTypes, string.Empty, loc), loc);
2021
 
 
2022
 
                                if (rs_equals == null) {
2023
 
                                        rs_equals = field_equal;
2024
 
                                        string_concat = new Binary (Binary.Operator.Addition,
2025
 
                                                string_concat,
2026
 
                                                new Binary (Binary.Operator.Addition,
2027
 
                                                        new StringConstant (Compiler.BuiltinTypes, " " + p.Name + " = ", loc),
2028
 
                                                        field_to_string,
2029
 
                                                        loc),
2030
 
                                                loc);
2031
 
                                        continue;
2032
 
                                }
2033
 
 
2034
 
                                //
2035
 
                                // Implementation of ToString () body using string concatenation
2036
 
                                //                              
2037
 
                                string_concat = new Binary (Binary.Operator.Addition,
2038
 
                                        new Binary (Binary.Operator.Addition,
2039
 
                                                string_concat,
2040
 
                                                new StringConstant (Compiler.BuiltinTypes, ", " + p.Name + " = ", loc),
2041
 
                                                loc),
2042
 
                                        field_to_string,
2043
 
                                        loc);
2044
 
 
2045
 
                                rs_equals = new Binary (Binary.Operator.LogicalAnd, rs_equals, field_equal, loc);
2046
 
                        }
2047
 
 
2048
 
                        string_concat = new Binary (Binary.Operator.Addition,
2049
 
                                string_concat,
2050
 
                                new StringConstant (Compiler.BuiltinTypes, " }", loc),
2051
 
                                loc);
2052
 
 
2053
 
                        //
2054
 
                        // Equals (object obj) override
2055
 
                        //              
2056
 
                        var other_variable_assign = new TemporaryVariableReference (li_other, loc);
2057
 
                        equals_block.AddStatement (new StatementExpression (
2058
 
                                new SimpleAssign (other_variable_assign,
2059
 
                                        new As (equals_block.GetParameterReference (0, loc),
2060
 
                                                current_type, loc), loc)));
2061
 
 
2062
 
                        Expression equals_test = new Binary (Binary.Operator.Inequality, other_variable, new NullLiteral (loc), loc);
2063
 
                        if (rs_equals != null)
2064
 
                                equals_test = new Binary (Binary.Operator.LogicalAnd, equals_test, rs_equals, loc);
2065
 
                        equals_block.AddStatement (new Return (equals_test, loc));
2066
 
 
2067
 
                        equals.Block = equals_block;
2068
 
                        equals.Define ();
2069
 
                        Members.Add (equals);
2070
 
 
2071
 
                        //
2072
 
                        // GetHashCode () override
2073
 
                        //
2074
 
                        Method hashcode = new Method (this, new TypeExpression (Compiler.BuiltinTypes.Int, loc),
2075
 
                                Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN,
2076
 
                                new MemberName ("GetHashCode", loc),
2077
 
                                Mono.CSharp.ParametersCompiled.EmptyReadOnlyParameters, null);
2078
 
 
2079
 
                        //
2080
 
                        // Modified FNV with good avalanche behavior and uniform
2081
 
                        // distribution with larger hash sizes.
2082
 
                        //
2083
 
                        // const int FNV_prime = 16777619;
2084
 
                        // int hash = (int) 2166136261;
2085
 
                        // foreach (int d in data)
2086
 
                        //     hash = (hash ^ d) * FNV_prime;
2087
 
                        // hash += hash << 13;
2088
 
                        // hash ^= hash >> 7;
2089
 
                        // hash += hash << 3;
2090
 
                        // hash ^= hash >> 17;
2091
 
                        // hash += hash << 5;
2092
 
 
2093
 
                        ToplevelBlock hashcode_top = new ToplevelBlock (Compiler, loc);
2094
 
                        Block hashcode_block = new Block (hashcode_top, loc, loc);
2095
 
                        hashcode_top.AddStatement (new Unchecked (hashcode_block, loc));
2096
 
 
2097
 
                        var li_hash = LocalVariable.CreateCompilerGenerated (Compiler.BuiltinTypes.Int, hashcode_top, loc);
2098
 
                        hashcode_block.AddStatement (new BlockVariableDeclaration (new TypeExpression (li_hash.Type, loc), li_hash));
2099
 
                        LocalVariableReference hash_variable_assign = new LocalVariableReference (li_hash, loc);
2100
 
                        hashcode_block.AddStatement (new StatementExpression (
2101
 
                                new SimpleAssign (hash_variable_assign, rs_hashcode)));
2102
 
 
2103
 
                        var hash_variable = new LocalVariableReference (li_hash, loc);
2104
 
                        hashcode_block.AddStatement (new StatementExpression (
2105
 
                                new CompoundAssign (Binary.Operator.Addition, hash_variable,
2106
 
                                        new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 13, loc), loc), loc)));
2107
 
                        hashcode_block.AddStatement (new StatementExpression (
2108
 
                                new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
2109
 
                                        new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 7, loc), loc), loc)));
2110
 
                        hashcode_block.AddStatement (new StatementExpression (
2111
 
                                new CompoundAssign (Binary.Operator.Addition, hash_variable,
2112
 
                                        new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 3, loc), loc), loc)));
2113
 
                        hashcode_block.AddStatement (new StatementExpression (
2114
 
                                new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
2115
 
                                        new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 17, loc), loc), loc)));
2116
 
                        hashcode_block.AddStatement (new StatementExpression (
2117
 
                                new CompoundAssign (Binary.Operator.Addition, hash_variable,
2118
 
                                        new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 5, loc), loc), loc)));
2119
 
 
2120
 
                        hashcode_block.AddStatement (new Return (hash_variable, loc));
2121
 
                        hashcode.Block = hashcode_top;
2122
 
                        hashcode.Define ();
2123
 
                        Members.Add (hashcode);
2124
 
 
2125
 
                        //
2126
 
                        // ToString () override
2127
 
                        //
2128
 
 
2129
 
                        ToplevelBlock tostring_block = new ToplevelBlock (Compiler, loc);
2130
 
                        tostring_block.AddStatement (new Return (string_concat, loc));
2131
 
                        tostring.Block = tostring_block;
2132
 
                        tostring.Define ();
2133
 
                        Members.Add (tostring);
2134
 
 
2135
 
                        return true;
2136
 
                }
2137
 
 
2138
 
                public override string GetSignatureForError ()
2139
 
                {
2140
 
                        return SignatureForError;
2141
 
                }
2142
 
 
2143
 
                public override CompilationSourceFile GetCompilationSourceFile ()
2144
 
                {
2145
 
                        return null;
2146
 
                }
2147
 
 
2148
 
                public IList<AnonymousTypeParameter> Parameters {
2149
 
                        get {
2150
 
                                return parameters;
2151
 
                        }
2152
 
                }
2153
 
        }
2154
 
}