Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Parser/mcs/anonymous.cs @ 11937

Last change on this file since 11937 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

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