d450c0e33463bdafbe215e692d864a81b7f29997
[mono.git] / mcs / mcs / anonymous.cs
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-2008 Novell, Inc.
10 //
11
12 using System;
13 using System.Text;
14 using System.Collections;
15 using System.Collections.Specialized;
16 using System.Reflection;
17 using System.Reflection.Emit;
18
19 namespace Mono.CSharp {
20
21         public abstract class CompilerGeneratedClass : Class
22         {
23                 public static string MakeName (string host, string typePrefix, string name, int id)
24                 {
25                         return "<" + host + ">" + typePrefix + "__" + name + id.ToString ();
26                 }
27                 
28                 protected CompilerGeneratedClass (DeclSpace parent, MemberName name, int mod)
29                         : base (parent.NamespaceEntry, parent, name, mod | Modifiers.COMPILER_GENERATED | Modifiers.SEALED, null)
30                 {
31                 }
32
33                 protected CompilerGeneratedClass (DeclSpace parent, GenericMethod generic, MemberName name, int mod)
34                         : this (parent, name, mod)
35                 {
36                         if (generic != null) {
37                                 ArrayList list = new ArrayList ();
38                                 foreach (TypeParameter tparam in generic.TypeParameters) {
39                                         if (tparam.Constraints != null)
40                                                 list.Add (tparam.Constraints.Clone ());
41                                 }
42                                 SetParameterInfo (list);
43                         }
44                 }
45
46                 protected void CheckMembersDefined ()
47                 {
48                         if (members_defined)
49                                 throw new InternalErrorException ("Helper class already defined!");
50                 }
51         }
52
53         //
54         // Anonymous method storey is created when an anonymous method uses
55         // variable or parameter from outer scope. They are then hoisted to
56         // anonymous method storey (captured)
57         //
58         public class AnonymousMethodStorey : CompilerGeneratedClass
59         {
60                 class StoreyFieldPair {
61                         public AnonymousMethodStorey Storey;
62                         public Field Field;
63
64                         public StoreyFieldPair (AnonymousMethodStorey storey)
65                         {
66                                 this.Storey = storey;
67                         }
68
69                         public override int GetHashCode ()
70                         {
71                                 return Storey.ID.GetHashCode ();
72                         }
73
74                         public override bool Equals (object obj)
75                         {
76                                 return (AnonymousMethodStorey)obj == Storey;
77                         }
78                 }
79
80                 class HoistedGenericField : Field
81                 {
82                         public HoistedGenericField (DeclSpace parent, FullNamedExpression type, int mod, string name,
83                                   Attributes attrs, Location loc)
84                                 : base (parent, type, mod, name, attrs, loc)
85                         {
86                         }
87
88                         public override bool Define ()
89                         {
90                                 type_name.Type = ((AnonymousMethodStorey) Parent).MutateType (type_name.Type);
91                                 return base.Define ();
92                         }
93                 }
94
95                 // TODO: Why is it required by debugger ?
96                 public readonly int ID;
97                 static int unique_id;
98
99                 public readonly Block OriginalSourceBlock;
100
101                 // A list of StoreyFieldPair with local field keeping parent storey instance
102                 ArrayList used_parent_storeys;
103
104                 // A list of hoisted parameters
105                 protected ArrayList hoisted_params;
106
107                 // Hoisted this
108                 HoistedThis hoisted_this;
109
110                 // Local variable which holds this storey instance
111                 public LocalTemporary Instance;
112
113                 bool references_defined;
114                 bool has_hoisted_variable;
115
116                 public AnonymousMethodStorey (Block block, DeclSpace parent, MemberBase host, GenericMethod generic, string name)
117                         : base (parent, generic, MakeMemberName (host, name, generic, block.StartLocation), Modifiers.PRIVATE)
118                 {
119                         Parent = parent;
120                         OriginalSourceBlock = block;
121                         ID = unique_id++;
122                 }
123
124                 static MemberName MakeMemberName (MemberBase host, string name, GenericMethod generic, Location loc)
125                 {
126                         string host_name = host == null ? null : host.Name;
127                         string tname = MakeName (host_name, "c", name, unique_id);
128                         TypeArguments args = null;
129                         if (generic != null) {
130                                 args = new TypeArguments (loc);
131                                 foreach (TypeParameter tparam in generic.CurrentTypeParameters)
132                                         args.Add (new SimpleName (tparam.Name, loc));
133                         }
134
135                         return new MemberName (tname, args, loc);
136                 }
137
138                 public Field AddCapturedVariable (string name, Type type)
139                 {
140                         CheckMembersDefined ();
141
142                         FullNamedExpression field_type = new TypeExpression (type, Location);
143                         if (!IsGeneric)
144                                 return AddCompilerGeneratedField (name, field_type);
145
146                         const int mod = Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED;
147                         Field f = new HoistedGenericField (this, field_type, mod, name, null, Location);
148                         AddField (f);
149                         return f;
150                 }
151
152                 protected Field AddCompilerGeneratedField (string name, FullNamedExpression type)
153                 {
154                         const int mod = Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED;
155                         Field f = new Field (this, type, mod, name, null, Location);
156                         AddField (f);
157                         return f;
158                 }
159
160                 public void AddParentStoreyReference (AnonymousMethodStorey s)
161                 {
162                         CheckMembersDefined ();
163
164                         if (used_parent_storeys == null)
165                                 used_parent_storeys = new ArrayList ();
166                         else if (used_parent_storeys.IndexOf (s) != -1)
167                                 return;
168
169                         has_hoisted_variable = true;
170                         used_parent_storeys.Add (new StoreyFieldPair (s));
171                 }
172
173                 public void CaptureLocalVariable (EmitContext ec, LocalInfo local_info)
174                 {
175                         if (local_info.HoistedVariableReference != null)
176                                 return;
177
178                         HoistedVariable var = new HoistedLocalVariable (this, local_info, GetVariableMangledName (local_info));
179                         local_info.HoistedVariableReference = var;
180                         has_hoisted_variable = true;
181                 }
182
183                 public void CaptureParameter (EmitContext ec, ParameterReference param_ref)
184                 {
185                         if (param_ref.HoistedVariable != null)
186                                 return;
187
188                         if (hoisted_params == null)
189                                 hoisted_params = new ArrayList ();
190
191                         HoistedVariable expr = new HoistedParameter (this, param_ref);
192                         param_ref.Parameter.HoistedVariableReference = expr;
193                         hoisted_params.Add (expr);
194                 }
195
196                 public HoistedThis CaptureThis (EmitContext ec, This t)
197                 {
198                         hoisted_this = new HoistedThis (this, t);
199                         return hoisted_this;
200                 }
201
202                 void DefineStoreyReferences ()
203                 {
204                         if (used_parent_storeys == null || references_defined)
205                                 return;
206
207                         references_defined = true;
208
209                         //
210                         // For each used variable from parent scope we allocate its local reference point
211                         //
212                         for (int i = 0; i < used_parent_storeys.Count; ++i) {
213                                 StoreyFieldPair sf = (StoreyFieldPair) used_parent_storeys [i];
214                                 AnonymousMethodStorey p_storey = sf.Storey;
215                                 TypeExpr type_expr = new TypeExpression (p_storey.TypeBuilder, Location);
216
217                                 sf.Field = AddCompilerGeneratedField ("<>f__ref$" + p_storey.ID, type_expr);
218                                 sf.Field.Define ();
219                         }
220                 }
221
222                 //
223                 // Initializes all hoisted variables
224                 //
225                 public void EmitHoistedVariables (EmitContext ec)
226                 {
227                         // There can be only one instance variable for each storey type
228                         if (Instance != null)
229                                 throw new InternalErrorException ();
230
231                         //
232                         // A storey with hoisted `this' is an instance method
233                         //
234                         if (!HasHoistedVariables) {
235                                 hoisted_this.RemoveHoisting ();
236                                 return;
237                         }
238
239                         DefineStoreyReferences ();
240
241                         //
242                         // Create an instance of storey type
243                         //
244                         Expression storey_type_expr;
245                         if (is_generic) {
246                                 //
247                                 // Use current method type parameter (MVAR) for top level storey only. All
248                                 // nested storeys use class type parameter (VAR)
249                                 //
250                                 TypeParameter[] tparams = ec.CurrentAnonymousMethod != null ?
251                                         ec.CurrentAnonymousMethod.Storey.CurrentTypeParameters :
252                                         ec.GenericDeclContainer.CurrentTypeParameters;
253
254                                 if (tparams.Length != CountTypeParameters) {
255                                         TypeParameter [] full = new TypeParameter [CountTypeParameters];
256                                         DeclSpace parent = ec.DeclContainer.Parent;
257                                         parent.CurrentTypeParameters.CopyTo (full, 0);
258                                         tparams.CopyTo (full, parent.CountTypeParameters);
259                                         tparams = full;
260                                 }
261
262                                 storey_type_expr = new ConstructedType (TypeBuilder, tparams, Location);
263                         } else {
264                                 storey_type_expr = new TypeExpression (TypeBuilder, Location);
265                         }
266
267                         Expression e = new New (storey_type_expr, new ArrayList (0), Location).Resolve (ec);
268                         e.Emit (ec);
269
270                         Instance = new LocalTemporary (storey_type_expr.Type);
271                         Instance.Store (ec);
272
273                         EmitHoistedFieldsInitialization (ec);
274                 }
275
276                 void EmitHoistedFieldsInitialization (EmitContext ec)
277                 {
278                         //
279                         // Initialize all storey reference fields by using local or hoisted variables
280                         //
281                         if (used_parent_storeys != null) {
282                                 foreach (StoreyFieldPair sf in used_parent_storeys) {
283                                         //
284                                         // Setting local field
285                                         //
286                                         Expression instace_expr = GetStoreyInstanceExpression (ec);
287                                         FieldExpr f_set_expr = TypeManager.IsGenericType (instace_expr.Type) ?
288                                                 new FieldExpr (sf.Field.FieldBuilder, instace_expr.Type, Location) :
289                                                 new FieldExpr (sf.Field.FieldBuilder, Location);
290                                         f_set_expr.InstanceExpression = instace_expr;
291
292                                         SimpleAssign a = new SimpleAssign (f_set_expr, sf.Storey.GetStoreyInstanceExpression (ec));
293                                         if (a.Resolve (ec) != null)
294                                                 a.EmitStatement (ec);
295                                 }
296                         }
297
298                         //
299                         // Setting currect anonymous method to null blocks any further variable hoisting
300                         //
301                         AnonymousExpression ae = ec.CurrentAnonymousMethod;
302                         ec.CurrentAnonymousMethod = null;
303
304                         if (hoisted_params != null) {
305                                 foreach (HoistedParameter hp in hoisted_params) {
306                                         hp.EmitHoistingAssignment (ec);
307                                 }
308                         }
309
310                         if (hoisted_this != null) {
311                                 hoisted_this.EmitHoistingAssignment (ec);
312                         }
313
314                         ec.CurrentAnonymousMethod = ae;
315                 }
316
317                 public override void EmitType ()
318                 {
319                         DefineStoreyReferences ();
320                         base.EmitType ();
321                 }
322
323                 //
324                 // Returns a field which holds referenced storey instance
325                 //
326                 Field GetReferencedStoreyField (AnonymousMethodStorey storey)
327                 {
328                         if (used_parent_storeys == null)
329                                 return null;
330
331                         foreach (StoreyFieldPair sf in used_parent_storeys) {
332                                 if (sf.Storey == storey)
333                                         return sf.Field;
334                         }
335
336                         return null;
337                 }
338
339                 //
340                 // Creates storey instance expression regardless of currect IP
341                 //
342                 public Expression GetStoreyInstanceExpression (EmitContext ec)
343                 {
344                         AnonymousExpression am = ec.CurrentAnonymousMethod;
345
346                         //
347                         // Access from original block -> storey
348                         //
349                         if (am == null)
350                                 return Instance;
351
352                         //
353                         // Access from anonymous method implemented as a static -> storey
354                         //
355                         if (am.Storey == null)
356                                 return Instance;
357
358                         Field f = am.Storey.GetReferencedStoreyField (this);
359                         if (f == null) {
360                                 if (am.Storey == this) {
361                                         //
362                                         // Access inside of same storey (S -> S)
363                                         //
364                                         return new CompilerGeneratedThis (TypeBuilder, Location);
365                                 }
366                                 //
367                                 // External field access
368                                 //
369                                 return Instance;
370                         }
371
372                         //
373                         // Storey was cached to local field
374                         //
375                         FieldExpr f_ind = new FieldExpr (f.FieldBuilder, Location);
376                         f_ind.InstanceExpression = new CompilerGeneratedThis (TypeBuilder, Location);
377                         return f_ind;
378                 }
379
380                 protected virtual string GetVariableMangledName (LocalInfo local_info)
381                 {
382                         //
383                         // No need to mangle anonymous method hoisted variables cause they
384                         // are hoisted in their own scopes
385                         //
386                         return local_info.Name;
387                 }
388
389                 //
390                 // Returns true when at least one local variable or parameter is
391                 // hoisted, or story is transitioned
392                 //
393                 public bool HasHoistedVariables {
394                         get {
395                                 return has_hoisted_variable || hoisted_params != null;
396                         }
397                         set {
398                                 has_hoisted_variable = value;
399                         }
400                 }
401
402                 //
403                 // Mutate type dispatcher
404                 //
405                 public Type MutateType (Type type)
406                 {
407 #if GMCS_SOURCE
408                         if (TypeManager.IsGenericType (type))
409                                 return MutateGenericType (type);
410
411                         if (TypeManager.IsGenericParameter (type))
412                                 return MutateGenericArgument (type);
413
414                         if (type.IsArray)
415                                 return MutateArrayType (type);
416 #endif
417                         return type;
418                 }
419
420                 //
421                 // Changes method type arguments (MVAR) to storey (VAR) type arguments
422                 //
423                 public MethodInfo MutateGenericMethod (MethodInfo method)
424                 {
425 #if GMCS_SOURCE
426                         Type [] t_args = TypeManager.GetGenericArguments (method);
427                         if (TypeManager.IsGenericType (method.DeclaringType)) {
428                                 Type t = MutateGenericType (method.DeclaringType);
429                                 if (t != method.DeclaringType) {
430                                         method = (MethodInfo) TypeManager.DropGenericMethodArguments (method);
431                                         if (method.Module == CodeGen.Module.Builder)
432                                                 method = TypeBuilder.GetMethod (t, method);
433                                         else
434                                                 method = (MethodInfo) MethodInfo.GetMethodFromHandle (method.MethodHandle, t.TypeHandle);
435                                 }                               
436                         }
437
438                         if (t_args == null || t_args.Length == 0)
439                                 return method;
440
441                         for (int i = 0; i < t_args.Length; ++i)
442                                 t_args [i] = MutateType (t_args [i]);
443
444                         return method.GetGenericMethodDefinition ().MakeGenericMethod (t_args);
445 #else
446                         throw new NotSupportedException ();
447 #endif
448                 }
449
450                 public ConstructorInfo MutateConstructor (ConstructorInfo ctor)
451                 {
452 #if GMCS_SOURCE         
453                         if (TypeManager.IsGenericType (ctor.DeclaringType)) {
454                                 Type t = MutateGenericType (ctor.DeclaringType);
455                                 if (t != ctor.DeclaringType) {
456                                         // TODO: It should throw on imported types
457                                         return TypeBuilder.GetConstructor (t, ctor);
458                                 }
459                         }
460 #endif
461                         return ctor;
462                 }
463                 
464                 public FieldInfo MutateField (FieldInfo field)
465                 {
466 #if GMCS_SOURCE
467                         if (TypeManager.IsGenericType (field.DeclaringType)) {
468                                 Type t = MutateGenericType (field.DeclaringType);
469                                 if (t != field.DeclaringType) {
470                                         // TODO: It should throw on imported types
471                                         return TypeBuilder.GetField (t, field);
472                                 }
473                         }
474 #endif
475                         return field;
476                 }               
477
478 #if GMCS_SOURCE
479                 protected Type MutateArrayType (Type array)
480                 {
481                         int rank = array.GetArrayRank ();
482                         Type element = TypeManager.GetElementType (array);
483                         if (element.IsArray)
484                                 throw new NotImplementedException ();
485
486                         if (TypeManager.IsGenericParameter (element)) {
487                                 element = MutateGenericArgument (element);
488                         } else if (TypeManager.IsGenericType (element)) {
489                                 element = MutateGenericType (element);
490                         } else {
491                                 return array;
492                         }
493
494                         return element.MakeArrayType (rank);
495                 }
496
497                 protected Type MutateGenericType (Type type)
498                 {
499                         Type [] t_args = TypeManager.GetTypeArguments (type);
500                         if (t_args == null || t_args.Length == 0)
501                                 return type;
502
503                         for (int i = 0; i < t_args.Length; ++i)
504                                 t_args [i] = MutateType (t_args [i]);
505
506                         return type.GetGenericTypeDefinition ().MakeGenericType (t_args);
507                 }
508 #endif
509
510                 //
511                 // Changes method generic argument (MVAR) to type generic argument (VAR)
512                 //
513                 public Type MutateGenericArgument (Type type)
514                 {
515                         foreach (TypeParameter tp in CurrentTypeParameters) {
516                                 if (tp.Name == type.Name) {
517                                         return tp.Type;
518                                 }
519                         }
520
521                         return type;
522                 }
523
524                 public static void Reset ()
525                 {
526                         unique_id = 0;
527                 }
528                 
529                 public void Undo ()
530                 {
531                         if (hoisted_this != null)
532                                 hoisted_this.RemoveHoisting ();
533                 }
534         }
535
536         public abstract class HoistedVariable
537         {
538                 class ExpressionTreeProxy : Expression
539                 {
540                         readonly HoistedVariable hv;
541
542                         public ExpressionTreeProxy (HoistedVariable hv)
543                         {
544                                 this.hv = hv;
545                         }
546
547                         public override Expression CreateExpressionTree (EmitContext ec)
548                         {
549                                 throw new NotSupportedException ("ET");
550                         }
551
552                         public override Expression DoResolve (EmitContext ec)
553                         {
554                                 eclass = ExprClass.Value;
555                                 type = TypeManager.expression_type_expr.Type;
556                                 return this;
557                         }
558
559                         public override void Emit (EmitContext ec)
560                         {
561                                 Expression e = hv.GetFieldExpression (ec).CreateExpressionTree (ec);
562                                 // This should never fail
563                                 e = e.Resolve (ec);
564                                 if (e != null)
565                                         e.Emit (ec);
566                         }
567                 }
568         
569                 protected readonly AnonymousMethodStorey storey;
570                 protected Field field;
571                 Hashtable cached_inner_access; // TODO: Hashtable is too heavyweight
572
573                 protected HoistedVariable (AnonymousMethodStorey storey, string name, Type type)
574                 {
575                         this.storey = storey;
576
577                         this.field = storey.AddCapturedVariable (name, type);
578                 }
579
580                 public void AddressOf (EmitContext ec, AddressOp mode)
581                 {
582                         GetFieldExpression (ec).AddressOf (ec, mode);
583                 }
584
585                 public Expression CreateExpressionTree (EmitContext ec)
586                 {
587                         return new ExpressionTreeProxy (this);
588                 }
589
590                 public void Emit (EmitContext ec)
591                 {
592                         GetFieldExpression (ec).Emit (ec);
593                 }
594
595                 //
596                 // Creates field access expression for hoisted variable
597                 //
598                 protected FieldExpr GetFieldExpression (EmitContext ec)
599                 {
600                         if (ec.CurrentAnonymousMethod == null) {
601                                 //
602                                 // When setting top-level hoisted variable in generic storey
603                                 // change storey generic types to method generic types (VAR -> MVAR)
604                                 //
605                                 FieldExpr outer_access = storey.MemberName.IsGeneric ?
606                                         new FieldExpr (field.FieldBuilder, storey.Instance.Type, field.Location) :
607                                         new FieldExpr (field.FieldBuilder, field.Location);
608
609                                 outer_access.InstanceExpression = storey.GetStoreyInstanceExpression (ec);
610                                 outer_access.Resolve (ec);
611                                 return outer_access;
612                         }
613
614                         FieldExpr inner_access;
615                         if (cached_inner_access != null) {
616                                 inner_access = (FieldExpr) cached_inner_access [ec.CurrentAnonymousMethod];
617                         } else {
618                                 inner_access = null;
619                                 cached_inner_access = new Hashtable (4);
620                         }
621
622                         if (inner_access == null) {
623                                 inner_access = new FieldExpr (field.FieldBuilder, field.Location);
624                                 inner_access.InstanceExpression = storey.GetStoreyInstanceExpression (ec);
625                                 inner_access.Resolve (ec);
626                                 cached_inner_access.Add (ec.CurrentAnonymousMethod, inner_access);
627                         }
628
629                         return inner_access;
630                 }
631
632                 public abstract void EmitSymbolInfo ();
633
634                 public void Emit (EmitContext ec, bool leave_copy)
635                 {
636                         GetFieldExpression (ec).Emit (ec, leave_copy);
637                 }
638
639                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
640                 {
641                         GetFieldExpression (ec).EmitAssign (ec, source, leave_copy, false);
642                 }
643         }
644
645         class HoistedParameter : HoistedVariable
646         {
647                 class HoistedFieldAssign : Assign
648                 {
649                         public HoistedFieldAssign (Expression target, Expression source)
650                                 : base (target, source, source.Location)
651                         {
652                         }
653
654                         protected override Expression ResolveConversions (EmitContext ec)
655                         {
656                                 //
657                                 // Implicit conversion check fails for hoisted type arguments
658                                 // as they are of different types (!!0 x !0)
659                                 //
660                                 return this;
661                         }
662                 }
663
664                 readonly ParameterReference parameter;
665
666                 public HoistedParameter (AnonymousMethodStorey scope, ParameterReference par)
667                         : base (scope, par.Name, par.Type)
668                 {
669                         this.parameter = par;
670                 }
671
672                 public void EmitHoistingAssignment (EmitContext ec)
673                 {
674                         //
675                         // Remove hoisted redirection to emit assignment from original parameter
676                         //
677                         HoistedVariable temp = parameter.Parameter.HoistedVariableReference;
678                         parameter.Parameter.HoistedVariableReference = null;
679
680                         Assign a = new HoistedFieldAssign (GetFieldExpression (ec), parameter);
681                         if (a.Resolve (ec) != null)
682                                 a.EmitStatement (ec);
683
684                         parameter.Parameter.HoistedVariableReference = temp;
685                 }
686
687                 public override void EmitSymbolInfo ()
688                 {
689                         SymbolWriter.DefineCapturedParameter (storey.ID, field.Name, field.Name);
690                 }
691
692                 public Field Field {
693                         get { return field; }
694                 }
695         }
696
697         class HoistedLocalVariable : HoistedVariable
698         {
699                 public HoistedLocalVariable (AnonymousMethodStorey scope, LocalInfo local, string name)
700                         : base (scope, name, local.VariableType)
701                 {
702                 }
703
704                 public override void EmitSymbolInfo ()
705                 {
706                         SymbolWriter.DefineCapturedLocal (storey.ID, field.Name, field.Name);
707                 }
708         }
709
710         public class HoistedThis : HoistedVariable
711         {
712                 readonly This this_reference;
713
714                 public HoistedThis (AnonymousMethodStorey storey, This this_reference)
715                         : base (storey, "<>f__this", this_reference.Type)
716                 {
717                         this.this_reference = this_reference;
718                 }
719
720                 public void EmitHoistingAssignment (EmitContext ec)
721                 {
722                         SimpleAssign a = new SimpleAssign (GetFieldExpression (ec), this_reference);
723                         if (a.Resolve (ec) != null)
724                                 a.EmitStatement (ec);
725                 }
726
727                 public override void EmitSymbolInfo ()
728                 {
729                         SymbolWriter.DefineCapturedThis (storey.ID, field.Name);
730                 }
731
732                 public void RemoveHoisting ()
733                 {
734                         this_reference.RemoveHoisting ();
735                 }
736         }
737
738         //
739         // Anonymous method expression as created by parser
740         //
741         public class AnonymousMethodExpression : Expression
742         {
743                 protected readonly TypeContainer Host;
744                 public readonly Parameters Parameters;
745                 ListDictionary compatibles;
746                 public ToplevelBlock Block;
747
748                 public AnonymousMethodExpression (TypeContainer host, Parameters parameters, Location loc)
749                 {
750                         this.Host = host;
751                         this.Parameters = parameters;
752                         this.loc = loc;
753                         this.compatibles = new ListDictionary ();
754                 }
755
756                 public override string ExprClassName {
757                         get {
758                                 return "anonymous method";
759                         }
760                 }
761
762                 public virtual bool HasExplicitParameters {
763                         get {
764                                 return Parameters != null;
765                         }
766                 }
767
768                 //
769                 // Returns true if the body of lambda expression can be implicitly
770                 // converted to the delegate of type `delegate_type'
771                 //
772                 public bool ImplicitStandardConversionExists (EmitContext ec, Type delegate_type)
773                 {
774                         using (ec.Set (EmitContext.Flags.ProbingMode)) {
775                                 return Compatible (ec, delegate_type) != null;
776                         }
777                 }
778
779                 protected Type CompatibleChecks (EmitContext ec, Type delegate_type)
780                 {
781                         if (TypeManager.IsDelegateType (delegate_type))
782                                 return delegate_type;
783
784 #if GMCS_SOURCE
785                         if (TypeManager.DropGenericTypeArguments (delegate_type) == TypeManager.expression_type) {
786                                 delegate_type = TypeManager.GetTypeArguments (delegate_type) [0];
787                                 if (TypeManager.IsDelegateType (delegate_type))
788                                         return delegate_type;
789
790                                 Report.Error (835, loc, "Cannot convert `{0}' to an expression tree of non-delegate type `{1}'",
791                                         GetSignatureForError (), TypeManager.CSharpName (delegate_type));
792                                 return null;
793                         }
794 #endif
795
796                         Report.Error (1660, loc, "Cannot convert `{0}' to non-delegate type `{1}'",
797                                       GetSignatureForError (), TypeManager.CSharpName (delegate_type));
798                         return null;
799                 }
800
801                 protected bool VerifyExplicitParameters (Type delegate_type, ParameterData parameters, bool ignore_error)
802                 {
803                         if (VerifyParameterCompatibility (delegate_type, parameters, ignore_error))
804                                 return true;
805
806                         if (!ignore_error)
807                                 Report.Error (1661, loc,
808                                         "Cannot convert `{0}' to delegate type `{1}' since there is a parameter mismatch",
809                                         GetSignatureForError (), TypeManager.CSharpName (delegate_type));
810
811                         return false;
812                 }
813
814                 protected bool VerifyParameterCompatibility (Type delegate_type, ParameterData invoke_pd, bool ignore_errors)
815                 {
816                         if (Parameters.Count != invoke_pd.Count) {
817                                 if (ignore_errors)
818                                         return false;
819                                 
820                                 Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
821                                               TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
822                                 return false;
823                         }
824                         
825                         if (!HasExplicitParameters)
826                                 return true;                    
827
828                         bool error = false;
829                         for (int i = 0; i < Parameters.Count; ++i) {
830                                 Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
831                                 if (Parameters.ParameterModifier (i) != p_mod && p_mod != Parameter.Modifier.PARAMS) {
832                                         if (ignore_errors)
833                                                 return false;
834                                         
835                                         if (p_mod == Parameter.Modifier.NONE)
836                                                 Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
837                                                               (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.ParameterModifier (i)));
838                                         else
839                                                 Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
840                                                               (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
841                                         error = true;
842                                         continue;
843                                 }
844
845                                 Type type = invoke_pd.Types [i];
846                                 
847                                 // We assume that generic parameters are always inflated
848                                 if (TypeManager.IsGenericParameter (type))
849                                         continue;
850                                 
851                                 if (TypeManager.HasElementType (type) && TypeManager.IsGenericParameter (TypeManager.GetElementType (type)))
852                                         continue;
853                                 
854                                 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i)) {
855                                         if (ignore_errors)
856                                                 return false;
857                                         
858                                         Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
859                                                       (i+1).ToString (),
860                                                       TypeManager.CSharpName (Parameters.ParameterType (i)),
861                                                       TypeManager.CSharpName (invoke_pd.ParameterType (i)));
862                                         error = true;
863                                 }
864                         }
865
866                         return !error;
867                 }
868
869                 //
870                 // Infers type arguments based on explicit arguments
871                 //
872                 public bool ExplicitTypeInference (TypeInferenceContext type_inference, Type delegate_type)
873                 {
874                         if (!HasExplicitParameters)
875                                 return false;
876
877                         if (!TypeManager.IsDelegateType (delegate_type)) {
878 #if GMCS_SOURCE
879                                 if (TypeManager.DropGenericTypeArguments (delegate_type) != TypeManager.expression_type)
880                                         return false;
881
882                                 delegate_type = delegate_type.GetGenericArguments () [0];
883                                 if (!TypeManager.IsDelegateType (delegate_type))
884                                         return false;
885 #else
886                                 return false;
887 #endif
888                         }
889                         
890                         ParameterData d_params = TypeManager.GetDelegateParameters (delegate_type);
891                         if (d_params.Count != Parameters.Count)
892                                 return false;
893
894                         for (int i = 0; i < Parameters.Count; ++i) {
895                                 Type itype = d_params.Types [i];
896                                 if (!TypeManager.IsGenericParameter (itype)) {
897                                         if (!TypeManager.HasElementType (itype))
898                                                 continue;
899                                         
900                                         if (!TypeManager.IsGenericParameter (itype.GetElementType ()))
901                                             continue;
902                                 }
903                                 type_inference.ExactInference (Parameters.FixedParameters[i].ParameterType, itype);
904                         }
905                         return true;
906                 }
907
908                 public Type InferReturnType (EmitContext ec, TypeInferenceContext tic, Type delegate_type)
909                 {
910                         AnonymousMethodBody am;
911                         using (ec.Set (EmitContext.Flags.ProbingMode | EmitContext.Flags.InferReturnType)) {
912                                 am = CompatibleMethod (ec, tic, GetType (), delegate_type);
913                         }
914                         
915                         if (am == null)
916                                 return null;
917
918                         if (am.ReturnType == TypeManager.null_type)
919                                 am.ReturnType = null;
920
921                         return am.ReturnType;
922                 }
923
924                 //
925                 // Returns AnonymousMethod container if this anonymous method
926                 // expression can be implicitly converted to the delegate type `delegate_type'
927                 //
928                 public Expression Compatible (EmitContext ec, Type type)
929                 {
930                         Expression am = (Expression) compatibles [type];
931                         if (am != null)
932                                 return am;
933
934                         Type delegate_type = CompatibleChecks (ec, type);
935                         if (delegate_type == null)
936                                 return null;
937
938                         //
939                         // At this point its the first time we know the return type that is 
940                         // needed for the anonymous method.  We create the method here.
941                         //
942
943                         MethodInfo invoke_mb = Delegate.GetInvokeMethod (
944                                 ec.ContainerType, delegate_type);
945                         Type return_type = TypeManager.TypeToCoreType (invoke_mb.ReturnType);
946
947 #if MS_COMPATIBLE
948                         Type[] g_args = delegate_type.GetGenericArguments ();
949                         if (return_type.IsGenericParameter)
950                                 return_type = g_args [return_type.GenericParameterPosition];
951 #endif
952
953                         //
954                         // Second: the return type of the delegate must be compatible with 
955                         // the anonymous type.   Instead of doing a pass to examine the block
956                         // we satisfy the rule by setting the return type on the EmitContext
957                         // to be the delegate type return type.
958                         //
959
960                         try {
961                                 int errors = Report.Errors;
962                                 am = CompatibleMethod (ec, null, return_type, delegate_type);
963                                 if (am != null && delegate_type != type && errors == Report.Errors)
964                                         am = CreateExpressionTree (ec, delegate_type);
965
966                                 if (!ec.IsInProbingMode)
967                                         compatibles.Add (type, am);
968
969                                 return am;
970                         } catch (Exception e) {
971                                 throw new InternalErrorException (e, loc);
972                         }
973                 }
974
975                 protected virtual Expression CreateExpressionTree (EmitContext ec, Type delegate_type)
976                 {
977                         return CreateExpressionTree (ec);
978                 }
979
980                 public override Expression CreateExpressionTree (EmitContext ec)
981                 {
982                         Report.Error (1946, loc, "An anonymous method cannot be converted to an expression tree");
983                         return null;
984                 }
985
986                 protected virtual Parameters ResolveParameters (EmitContext ec, TypeInferenceContext tic, Type delegate_type)
987                 {
988                         ParameterData delegate_parameters = TypeManager.GetDelegateParameters (delegate_type);
989
990                         if (Parameters == null) {
991                                 //
992                                 // We provide a set of inaccessible parameters
993                                 //
994                                 Parameter[] fixedpars = new Parameter[delegate_parameters.Count];
995
996                                 for (int i = 0; i < delegate_parameters.Count; i++) {
997                                         Parameter.Modifier i_mod = delegate_parameters.ParameterModifier (i);
998                                         if ((i_mod & Parameter.Modifier.OUTMASK) != 0) {
999                                                 Report.Error (1688, loc, "Cannot convert anonymous " +
1000                                                                   "method block without a parameter list " +
1001                                                                   "to delegate type `{0}' because it has " +
1002                                                                   "one or more `out' parameters.",
1003                                                                   TypeManager.CSharpName (delegate_type));
1004                                                 return null;
1005                                         }
1006                                         fixedpars[i] = new Parameter (
1007                                                 delegate_parameters.ParameterType (i), null,
1008                                                 delegate_parameters.ParameterModifier (i), null, loc);
1009                                 }
1010
1011                                 return Parameters.CreateFullyResolved (fixedpars, delegate_parameters.Types);
1012                         }
1013
1014                         if (!VerifyExplicitParameters (delegate_type, delegate_parameters, ec.IsInProbingMode)) {
1015                                 return null;
1016                         }
1017
1018                         return Parameters;
1019                 }
1020
1021                 public override Expression DoResolve (EmitContext ec)
1022                 {
1023                         if (!ec.IsAnonymousMethodAllowed) {
1024                                 Report.Error (1706, loc, "Anonymous methods and lambda expressions cannot be used in the current context");
1025                                 return null;
1026                         }
1027
1028                         //
1029                         // Set class type, set type
1030                         //
1031
1032                         eclass = ExprClass.Value;
1033
1034                         //
1035                         // This hack means `The type is not accessible
1036                         // anywhere', we depend on special conversion
1037                         // rules.
1038                         // 
1039                         type = TypeManager.anonymous_method_type;
1040
1041                         if ((Parameters != null) && !Parameters.Resolve (ec))
1042                                 return null;
1043
1044                         // FIXME: The emitted code isn't very careful about reachability
1045                         // so, ensure we have a 'ret' at the end
1046                         if (ec.CurrentBranching != null &&
1047                             ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
1048                                 ec.NeedReturnLabel ();
1049
1050                         return this;
1051                 }
1052
1053                 public override void Emit (EmitContext ec)
1054                 {
1055                         // nothing, as we only exist to not do anything.
1056                 }
1057
1058                 public override string GetSignatureForError ()
1059                 {
1060                         return ExprClassName;
1061                 }
1062
1063                 protected AnonymousMethodBody CompatibleMethod (EmitContext ec, TypeInferenceContext tic, Type return_type, Type delegate_type)
1064                 {
1065                         Parameters p = ResolveParameters (ec, tic, delegate_type);
1066                         if (p == null)
1067                                 return null;
1068
1069                         ToplevelBlock b = ec.IsInProbingMode ? (ToplevelBlock) Block.PerformClone () : Block;
1070
1071                         AnonymousMethodBody anonymous = CompatibleMethodFactory (return_type, delegate_type, p, b);
1072                         if (!anonymous.Compatible (ec))
1073                                 return null;
1074
1075                         return anonymous;
1076                 }
1077
1078                 protected virtual AnonymousMethodBody CompatibleMethodFactory (Type return_type, Type delegate_type, Parameters p, ToplevelBlock b)
1079                 {
1080                         return new AnonymousMethodBody (Host,
1081                                 p, b, return_type,
1082                                 delegate_type, loc);
1083                 }
1084
1085                 protected override void CloneTo (CloneContext clonectx, Expression t)
1086                 {
1087                         AnonymousMethodExpression target = (AnonymousMethodExpression) t;
1088
1089                         target.Block = (ToplevelBlock) clonectx.LookupBlock (Block);
1090                 }
1091         }
1092
1093         //
1094         // Abstract expression for any block which requires variables hoisting
1095         //
1096         public abstract class AnonymousExpression : Expression
1097         {
1098                 protected class AnonymousMethodMethod : Method
1099                 {
1100                         public readonly AnonymousExpression AnonymousMethod;
1101                         public readonly AnonymousMethodStorey Storey;
1102                         readonly string RealName;
1103
1104                         public AnonymousMethodMethod (DeclSpace parent, AnonymousExpression am, AnonymousMethodStorey storey,
1105                                                           GenericMethod generic, TypeExpr return_type,
1106                                                           int mod, string real_name, MemberName name,
1107                                                           Parameters parameters)
1108                                 : base (parent, generic, return_type, mod | Modifiers.COMPILER_GENERATED,
1109                                                 false, name, parameters, null)
1110                         {
1111                                 this.AnonymousMethod = am;
1112                                 this.Storey = storey;
1113                                 this.RealName = real_name;
1114
1115                                 Parent.PartialContainer.AddMethod (this);
1116                                 Block = am.Block;
1117                         }
1118
1119                         public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
1120                         {
1121                                 EmitContext aec = AnonymousMethod.aec;
1122                                 aec.ig = ig;
1123                                 aec.IsStatic = (ModFlags & Modifiers.STATIC) != 0;
1124                                 return aec;
1125                         }
1126
1127                         public override bool Define ()
1128                         {
1129                                 if (Storey != null && Storey.IsGeneric && Storey.HasHoistedVariables) {
1130                                         if (!Parameters.Empty) {
1131                                                 Type [] ptypes = Parameters.Types;
1132                                                 for (int i = 0; i < ptypes.Length; ++i)
1133                                                         ptypes [i] = Storey.MutateType (ptypes [i]);
1134                                         }
1135
1136                                         member_type = Storey.MutateType (ReturnType);
1137                                 }
1138
1139                                 return base.Define ();
1140                         }
1141
1142                         public override void Emit ()
1143                         {
1144                                 //
1145                                 // Before emitting any code we have to change all MVAR references to VAR
1146                                 // when the method is of generic type and has hoisted variables
1147                                 //
1148                                 if (Storey == Parent && Storey.IsGeneric) {
1149                                         AnonymousMethod.aec.ReturnType = Storey.MutateType (ReturnType);
1150                                         block.MutateHoistedGenericType (Storey);
1151                                 }
1152
1153                                 if (MethodBuilder == null) {
1154                                         ResolveMembers ();
1155                                         Define ();
1156                                 }
1157
1158                                 base.Emit ();
1159                         }
1160
1161                         public override void EmitExtraSymbolInfo (SourceMethod source)
1162                         {
1163                                 source.SetRealMethodName (RealName);
1164                         }
1165                 }
1166
1167                 //
1168                 // The block that makes up the body for the anonymous method
1169                 //
1170                 protected readonly ToplevelBlock Block;
1171
1172                 public Type ReturnType;
1173                 public readonly TypeContainer Host;
1174
1175                 //
1176                 // The implicit method we create
1177                 //
1178                 protected AnonymousMethodMethod method;
1179                 protected EmitContext aec;
1180
1181                 protected AnonymousExpression (TypeContainer host, ToplevelBlock block, Type return_type, Location loc)
1182                 {
1183                         this.ReturnType = return_type;
1184                         this.Host = host;
1185
1186                         this.Block = block;
1187                         this.loc = loc;
1188                 }
1189
1190                 public abstract void AddStoreyReference (AnonymousMethodStorey storey);
1191                 public abstract string ContainerType { get; }
1192                 public abstract bool IsIterator { get; }
1193                 public abstract AnonymousMethodStorey Storey { get; }
1194
1195                 public bool Compatible (EmitContext ec)
1196                 {
1197                         // TODO: Implement clone
1198                         aec = new EmitContext (
1199                                 ec.ResolveContext, ec.TypeContainer, ec.DeclContainer,
1200                                 Location, null, ReturnType,
1201                                 (ec.InUnsafe ? Modifiers.UNSAFE : 0), /* No constructor */ false);
1202
1203                         aec.CurrentAnonymousMethod = this;
1204                         aec.IsStatic = ec.IsStatic;
1205
1206                         IDisposable aec_dispose = null;
1207                         EmitContext.Flags flags = 0;
1208                         if (ec.InferReturnType)
1209                                 flags |= EmitContext.Flags.InferReturnType;
1210
1211                         if (ec.IsInProbingMode)
1212                                 flags |= EmitContext.Flags.ProbingMode;
1213
1214                         if (ec.IsInFieldInitializer)
1215                                 flags |= EmitContext.Flags.InFieldInitializer;
1216
1217                         if (ec.IsInUnsafeScope)
1218                                 flags |= EmitContext.Flags.InUnsafe;
1219
1220                         // HACK: Flag with 0 cannot be set 
1221                         if (flags != 0)
1222                                 aec_dispose = aec.Set (flags);
1223
1224                         bool unreachable;
1225                         bool res = aec.ResolveTopBlock (ec, Block, Block.Parameters, null, out unreachable);
1226
1227                         if (ec.InferReturnType)
1228                                 ReturnType = aec.ReturnType;
1229
1230                         if (aec_dispose != null) {
1231                                 aec_dispose.Dispose ();
1232                         }
1233
1234                         return res;
1235                 }
1236         }
1237
1238         public class AnonymousMethodBody : AnonymousExpression
1239         {
1240                 ArrayList referenced_storeys;
1241                 protected readonly Parameters parameters;
1242                 static int unique_id;
1243
1244                 public AnonymousMethodBody (TypeContainer host, Parameters parameters,
1245                                         ToplevelBlock block, Type return_type, Type delegate_type,
1246                                         Location loc)
1247                         : base (host, block, return_type, loc)
1248                 {
1249                         this.type = delegate_type;
1250                         this.parameters = parameters;
1251                 }
1252
1253                 public override string ContainerType {
1254                         get { return "anonymous method"; }
1255                 }
1256
1257                 public override AnonymousMethodStorey Storey {
1258                         get { return method.Storey; }
1259                 }
1260
1261                 public override bool IsIterator {
1262                         get { return false; }
1263                 }
1264
1265                 //
1266                 // Adds new storey reference to track out of scope variables
1267                 //
1268                 public override void AddStoreyReference (AnonymousMethodStorey storey)
1269                 {
1270                         if (referenced_storeys == null) {
1271                                 referenced_storeys = new ArrayList (2);
1272                         } else {
1273                                 foreach (AnonymousMethodStorey ams in referenced_storeys) {
1274                                         if (ams == storey)
1275                                                 return;
1276                                 }
1277                         }
1278
1279                         referenced_storeys.Add (storey);
1280                 }
1281
1282                 public override Expression CreateExpressionTree (EmitContext ec)
1283                 {
1284                         Report.Error (1945, loc, "An expression tree cannot contain an anonymous method expression");
1285                         return null;
1286                 }
1287
1288                 bool Define (EmitContext ec)
1289                 {
1290                         if (aec == null && !Compatible (ec))
1291                                 return false;
1292
1293                         //
1294                         // Don't create anonymous expression method when we are in probing
1295                         // mode or unreachable block
1296                         //
1297                         if (ec.IsVariableCapturingRequired)
1298                                 method = DoCreateMethodHost (ec);
1299
1300                         return true;
1301                 }
1302
1303                 //
1304                 // Creates a host for the anonymous method
1305                 //
1306                 AnonymousMethodMethod DoCreateMethodHost (EmitContext ec)
1307                 {
1308                         AnonymousMethodStorey storey = FindBestMethodStorey ();
1309                         
1310                         if (referenced_storeys != null) {
1311                                 foreach (AnonymousMethodStorey s in referenced_storeys) {
1312                                         if (s == storey)
1313                                                 continue;
1314
1315                                         storey.AddParentStoreyReference (s);
1316                                         s.HasHoistedVariables = true;
1317                                         Block.Parent.Explicit.PropagateStoreyReference (s);
1318                                 }
1319                                 referenced_storeys = null;
1320                         } else {
1321                                 //
1322                                 // Ensure we have a reference between this block and a storey
1323                                 // where this anymous method is created
1324                                 //
1325                                 if (Block.Parent != null)
1326                                         Block.Parent.Explicit.PropagateStoreyReference (storey);
1327                         }
1328
1329                         //
1330                         // Anonymous method body can be converted to
1331                         //
1332                         // 1, an instance method in current scope when only `this' is hoisted
1333                         // 2, a static method in current scope when neither `this' nor any variable is hoisted
1334                         // 3, an instance method in compiler generated storey when any hoisted variable exists
1335                         //
1336
1337                         int modifiers;
1338                         if (storey != null) {
1339                                 modifiers = storey.HasHoistedVariables ? Modifiers.INTERNAL : Modifiers.PRIVATE;
1340                         } else {
1341                                 modifiers = Modifiers.STATIC | Modifiers.PRIVATE;
1342                         }
1343
1344                         DeclSpace parent = (modifiers & Modifiers.PRIVATE) != 0 ? Host : storey;
1345
1346                         MemberCore mc = ec.ResolveContext as MemberCore;
1347                         string name = CompilerGeneratedClass.MakeName (parent != storey ? mc.Name : null,
1348                                 "m", null, unique_id++);
1349
1350                         MemberName member_name;
1351                         GenericMethod generic_method;
1352                         if ((modifiers & Modifiers.PRIVATE) != 0 && mc.MemberName.IsGeneric) {
1353                                 member_name = new MemberName (name, mc.MemberName.TypeArguments.Clone (), Location);
1354
1355                                 generic_method = new GenericMethod (
1356                                         Host.NamespaceEntry, storey, member_name,
1357                                         new TypeExpression (ReturnType, Location), parameters);
1358                                 generic_method.SetParameterInfo (null);
1359                         } else {
1360                                 member_name = new MemberName (name, Location);
1361                                 generic_method = null;
1362                         }
1363
1364                         string real_name = String.Format (
1365                                 "{0}~{1}{2}", mc.GetSignatureForError (), GetSignatureForError (),
1366                                 parameters.GetSignatureForError ());
1367
1368                         return new AnonymousMethodMethod (parent,
1369                                 this, storey, generic_method, new TypeExpression (ReturnType, Location), modifiers,
1370                                 real_name, member_name, parameters);
1371                 }
1372
1373                 public override Expression DoResolve (EmitContext ec)
1374                 {
1375                         if (eclass == ExprClass.Invalid) {
1376                                 if (!Define (ec))
1377                                         return null;
1378                         }
1379
1380                         eclass = ExprClass.Value;
1381                         return this;
1382                 }
1383
1384                 public override void Emit (EmitContext ec)
1385                 {
1386                         //
1387                         // It has to be delayed not to polute expression trees
1388                         //
1389                         if (method.MethodBuilder == null) {
1390                                 method.ResolveMembers ();
1391                                 method.Define ();
1392                         }
1393
1394                         //
1395                         // Don't cache generic delegates when contains MVAR argument
1396                         //
1397                         Field am_cache = null;
1398                         if ((method.ModFlags & Modifiers.STATIC) != 0 && !HasGenericParameter (type)) {
1399                                 TypeContainer parent = method.Parent.PartialContainer;
1400                                 int id = parent.Fields == null ? 0 : parent.Fields.Count;
1401                                 am_cache = new Field (Host, new TypeExpression (type, loc),
1402                                         Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
1403                                         CompilerGeneratedClass.MakeName (null, "f", "am$cache", id), null, loc);
1404                                 am_cache.Define ();
1405                                 parent.AddField (am_cache);
1406                         }
1407
1408                         ILGenerator ig = ec.ig;
1409                         Label l_initialized = ig.DefineLabel ();
1410
1411                         if (am_cache != null) {
1412                                 ig.Emit (OpCodes.Ldsfld, am_cache.FieldBuilder);
1413                                 ig.Emit (OpCodes.Brtrue_S, l_initialized);
1414                         }
1415
1416                         //
1417                         // Load method delegate implementation
1418                         //
1419                         if ((method.ModFlags & Modifiers.STATIC) != 0) {
1420                                 ig.Emit (OpCodes.Ldnull);
1421                         } else if (Storey.HasHoistedVariables) {
1422                                 Expression e = Storey.GetStoreyInstanceExpression (ec).Resolve (ec);
1423                                 if (e != null)
1424                                         e.Emit (ec);
1425                         } else {
1426                                 ig.Emit (OpCodes.Ldarg_0);
1427                         }
1428
1429                         MethodInfo delegate_method = method.MethodBuilder;
1430 #if GMCS_SOURCE
1431                         if (Storey != null && Storey.MemberName.IsGeneric && Storey.HasHoistedVariables)
1432                                 delegate_method = TypeBuilder.GetMethod (Storey.Instance.Type, delegate_method);
1433 #endif
1434                         ig.Emit (OpCodes.Ldftn, delegate_method);
1435
1436                         ConstructorInfo constructor_method = Delegate.GetConstructor (ec.ContainerType, type);
1437 #if MS_COMPATIBLE
1438             if (type.IsGenericType && type is TypeBuilder)
1439                 constructor_method = TypeBuilder.GetConstructor (type, constructor_method);
1440 #endif
1441                         ig.Emit (OpCodes.Newobj, constructor_method);
1442
1443                         if (am_cache != null) {
1444                                 ig.Emit (OpCodes.Stsfld, am_cache.FieldBuilder);
1445                                 ig.MarkLabel (l_initialized);
1446                                 ig.Emit (OpCodes.Ldsfld, am_cache.FieldBuilder);
1447                         }
1448                 }
1449
1450                 //
1451                 // Look for the best storey for this anonymous method
1452                 //
1453                 AnonymousMethodStorey FindBestMethodStorey ()
1454                 {
1455                         //
1456                         // Use the nearest parent block which has a storey
1457                         //
1458                         for (Block b = Block.Parent; b != null; b = b.Parent) {
1459                                 AnonymousMethodStorey s = b.Explicit.AnonymousMethodStorey;
1460                                 if (s != null)
1461                                         return s;
1462                         }
1463                                         
1464                         return null;
1465                 }
1466
1467                 public override string GetSignatureForError ()
1468                 {
1469                         return TypeManager.CSharpName (type);
1470                 }
1471
1472                 static bool HasGenericParameter (Type type)
1473                 {
1474 #if GMCS_SOURCE
1475                         if (type.IsGenericParameter)
1476                                 return type.DeclaringMethod != null;
1477                                 
1478                         if (!type.IsGenericType)
1479                                 return false;
1480
1481                         foreach (Type t in type.GetGenericArguments ()) {
1482                                 if (HasGenericParameter (t))
1483                                         return true;
1484                         }
1485 #endif
1486                         return false;
1487                 }
1488                 
1489                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1490                 {
1491                         type = storey.MutateType (type);
1492                 }
1493
1494                 public static void Error_AddressOfCapturedVar (string name, Location loc)
1495                 {
1496                         Report.Error (1686, loc,
1497                                       "Local variable `{0}' or its members cannot have their " +
1498                                       "address taken and be used inside an anonymous method block",
1499                                       name);
1500                 }
1501
1502                 public static void Reset ()
1503                 {
1504                         unique_id = 0;
1505                 }
1506         }
1507
1508         //
1509         // Anonymous type container
1510         //
1511         public class AnonymousTypeClass : CompilerGeneratedClass
1512         {
1513                 static int types_counter;
1514                 public const string ClassNamePrefix = "<>__AnonType";
1515                 public const string SignatureForError = "anonymous type";
1516                 
1517                 readonly ArrayList parameters;
1518
1519                 private AnonymousTypeClass (DeclSpace parent, MemberName name, ArrayList parameters, Location loc)
1520                         : base (parent, name, Modifiers.SEALED)
1521                 {
1522                         this.parameters = parameters;
1523                 }
1524
1525                 public static AnonymousTypeClass Create (TypeContainer parent, ArrayList parameters, Location loc)
1526                 {
1527                         if (RootContext.Version <= LanguageVersion.ISO_2)
1528                                 Report.FeatureIsNotAvailable (loc, "anonymous types");
1529                         
1530                         string name = ClassNamePrefix + types_counter++;
1531
1532                         SimpleName [] t_args = new SimpleName [parameters.Count];
1533                         Parameter [] ctor_params = new Parameter [parameters.Count];
1534                         for (int i = 0; i < parameters.Count; ++i) {
1535                                 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
1536
1537                                 t_args [i] = new SimpleName ("<" + p.Name + ">__T", p.Location);
1538                                 ctor_params [i] = new Parameter (t_args [i], p.Name, 0, null, p.Location);
1539                         }
1540
1541                         //
1542                         // Create generic anonymous type host with generic arguments
1543                         // named upon properties names
1544                         //
1545                         AnonymousTypeClass a_type = new AnonymousTypeClass (parent.NamespaceEntry.SlaveDeclSpace,
1546                                 new MemberName (name, new TypeArguments (loc, t_args), loc), parameters, loc);
1547
1548                         if (parameters.Count > 0)
1549                                 a_type.SetParameterInfo (null);
1550
1551                         Constructor c = new Constructor (a_type, name, Modifiers.PUBLIC | Modifiers.DEBUGGER_HIDDEN,
1552                                 new Parameters (ctor_params), null, loc);
1553                         c.Block = new ToplevelBlock (c.Parameters, loc);
1554
1555                         // 
1556                         // Create fields and contructor body with field initialization
1557                         //
1558                         bool error = false;
1559                         for (int i = 0; i < parameters.Count; ++i) {
1560                                 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
1561
1562                                 Field f = new Field (a_type, t_args [i], Modifiers.PRIVATE | Modifiers.READONLY,
1563                                         "<" + p.Name + ">", null, p.Location);
1564
1565                                 if (!a_type.AddField (f)) {
1566                                         error = true;
1567                                         Report.Error (833, p.Location, "`{0}': An anonymous type cannot have multiple properties with the same name",
1568                                                 p.Name);
1569                                         continue;
1570                                 }
1571
1572                                 c.Block.AddStatement (new StatementExpression (
1573                                         new SimpleAssign (new MemberAccess (new This (p.Location), f.Name),
1574                                                 c.Block.GetParameterReference (p.Name, p.Location))));
1575
1576                                 ToplevelBlock get_block = new ToplevelBlock (p.Location);
1577                                 get_block.AddStatement (new Return (
1578                                         new MemberAccess (new This (p.Location), f.Name), p.Location));
1579                                 Accessor get_accessor = new Accessor (get_block, 0, null, p.Location);
1580                                 Property prop = new Property (a_type, t_args [i], Modifiers.PUBLIC, false,
1581                                         new MemberName (p.Name, p.Location), null, get_accessor, null, false);
1582                                 a_type.AddProperty (prop);
1583                         }
1584
1585                         if (error)
1586                                 return null;
1587
1588                         a_type.AddConstructor (c);
1589                         return a_type;
1590                 }
1591                 
1592                 public static void Reset ()
1593                 {
1594                         types_counter = 0;
1595                 }
1596
1597                 protected override bool AddToContainer (MemberCore symbol, string name)
1598                 {
1599                         MemberCore mc = (MemberCore) defined_names [name];
1600
1601                         if (mc == null) {
1602                                 defined_names.Add (name, symbol);
1603                                 return true;
1604                         }
1605
1606                         Report.SymbolRelatedToPreviousError (mc);
1607                         return false;
1608                 }
1609
1610                 void DefineOverrides ()
1611                 {
1612                         Location loc = Location;
1613
1614                         Method equals = new Method (this, null, TypeManager.system_boolean_expr,
1615                                 Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN, false, new MemberName ("Equals", loc),
1616                                 new Parameters (new Parameter (TypeManager.system_object_expr, "obj", 0, null, loc)), null);
1617
1618                         Method tostring = new Method (this, null, TypeManager.system_string_expr,
1619                                 Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN, false, new MemberName ("ToString", loc),
1620                                 Mono.CSharp.Parameters.EmptyReadOnlyParameters, null);
1621
1622                         ToplevelBlock equals_block = new ToplevelBlock (equals.Parameters, loc);
1623                         TypeExpr current_type;
1624                         if (IsGeneric)
1625                                 current_type = new ConstructedType (TypeBuilder, TypeParameters, loc);
1626                         else
1627                                 current_type = new TypeExpression (TypeBuilder, loc);
1628
1629                         equals_block.AddVariable (current_type, "other", loc);
1630                         LocalVariableReference other_variable = new LocalVariableReference (equals_block, "other", loc);
1631
1632                         MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
1633                                 new QualifiedAliasMember ("global", "System", loc), "Collections", loc), "Generic", loc);
1634
1635                         Expression rs_equals = null;
1636                         Expression string_concat = new StringConstant ("<empty type>", loc);
1637                         Expression rs_hashcode = new IntConstant (-2128831035, loc);
1638                         for (int i = 0; i < parameters.Count; ++i) {
1639                                 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
1640                                 Field f = (Field) Fields [i];
1641
1642                                 MemberAccess equality_comparer = new MemberAccess (new MemberAccess (
1643                                         system_collections_generic, "EqualityComparer",
1644                                                 new TypeArguments (loc, new SimpleName (TypeParameters [i].Name, loc)), loc),
1645                                                 "Default", loc);
1646
1647                                 ArrayList arguments_equal = new ArrayList (2);
1648                                 arguments_equal.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
1649                                 arguments_equal.Add (new Argument (new MemberAccess (other_variable, f.Name)));
1650
1651                                 Expression field_equal = new Invocation (new MemberAccess (equality_comparer,
1652                                         "Equals", loc), arguments_equal);
1653
1654                                 ArrayList arguments_hashcode = new ArrayList (1);
1655                                 arguments_hashcode.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
1656                                 Expression field_hashcode = new Invocation (new MemberAccess (equality_comparer,
1657                                         "GetHashCode", loc), arguments_hashcode);
1658
1659                                 IntConstant FNV_prime = new IntConstant (16777619, loc);                                
1660                                 rs_hashcode = new Binary (Binary.Operator.Multiply,
1661                                         new Binary (Binary.Operator.ExclusiveOr, rs_hashcode, field_hashcode),
1662                                         FNV_prime);
1663
1664                                 Expression field_to_string = new Conditional (new Binary (Binary.Operator.Inequality,
1665                                         new MemberAccess (new This (f.Location), f.Name), new NullLiteral (loc)),
1666                                         new Invocation (new MemberAccess (
1667                                                 new MemberAccess (new This (f.Location), f.Name), "ToString"), null),
1668                                         new StringConstant ("<null>", loc));
1669
1670                                 if (rs_equals == null) {
1671                                         rs_equals = field_equal;
1672                                         string_concat = new Binary (Binary.Operator.Addition,
1673                                                 new StringConstant (p.Name + " = ", loc),
1674                                                 field_to_string);
1675                                         continue;
1676                                 }
1677
1678                                 //
1679                                 // Implementation of ToString () body using string concatenation
1680                                 //                              
1681                                 string_concat = new Binary (Binary.Operator.Addition,
1682                                         new Binary (Binary.Operator.Addition,
1683                                                 string_concat,
1684                                                 new StringConstant (", " + p.Name + " = ", loc)),
1685                                         field_to_string);
1686
1687                                 rs_equals = new Binary (Binary.Operator.LogicalAnd, rs_equals, field_equal);
1688                         }
1689
1690                         //
1691                         // Equals (object obj) override
1692                         //
1693                         equals_block.AddStatement (new StatementExpression (
1694                                 new SimpleAssign (other_variable,
1695                                         new As (equals_block.GetParameterReference ("obj", loc),
1696                                                 current_type, loc), loc)));
1697
1698                         Expression equals_test = new Binary (Binary.Operator.Inequality, other_variable, new NullLiteral (loc));
1699                         if (rs_equals != null)
1700                                 equals_test = new Binary (Binary.Operator.LogicalAnd, equals_test, rs_equals);
1701                         equals_block.AddStatement (new Return (equals_test, loc));
1702
1703                         equals.Block = equals_block;
1704                         equals.ResolveMembers ();
1705                         AddMethod (equals);
1706
1707                         //
1708                         // GetHashCode () override
1709                         //
1710                         Method hashcode = new Method (this, null, TypeManager.system_int32_expr,
1711                                 Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN,
1712                                 false, new MemberName ("GetHashCode", loc),
1713                                 Mono.CSharp.Parameters.EmptyReadOnlyParameters, null);
1714
1715                         //
1716                         // Modified FNV with good avalanche behavior and uniform
1717                         // distribution with larger hash sizes.
1718                         //
1719                         // const int FNV_prime = 16777619;
1720                         // int hash = (int) 2166136261;
1721                         // foreach (int d in data)
1722                         //     hash = (hash ^ d) * FNV_prime;
1723                         // hash += hash << 13;
1724                         // hash ^= hash >> 7;
1725                         // hash += hash << 3;
1726                         // hash ^= hash >> 17;
1727                         // hash += hash << 5;
1728
1729                         ToplevelBlock hashcode_block = new ToplevelBlock (loc);
1730                         hashcode_block.AddVariable (TypeManager.system_int32_expr, "hash", loc);
1731                         LocalVariableReference hash_variable = new LocalVariableReference (hashcode_block, "hash", loc);
1732                         hashcode_block.AddStatement (new StatementExpression (
1733                                 new SimpleAssign (hash_variable, rs_hashcode)));
1734
1735                         hashcode_block.AddStatement (new StatementExpression (
1736                                 new CompoundAssign (Binary.Operator.Addition, hash_variable,
1737                                         new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (13, loc)))));
1738                         hashcode_block.AddStatement (new StatementExpression (
1739                                 new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
1740                                         new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (7, loc)))));
1741                         hashcode_block.AddStatement (new StatementExpression (
1742                                 new CompoundAssign (Binary.Operator.Addition, hash_variable,
1743                                         new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (3, loc)))));
1744                         hashcode_block.AddStatement (new StatementExpression (
1745                                 new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
1746                                         new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (17, loc)))));
1747                         hashcode_block.AddStatement (new StatementExpression (
1748                                 new CompoundAssign (Binary.Operator.Addition, hash_variable,
1749                                         new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (5, loc)))));
1750
1751                         hashcode_block.AddStatement (new Return (hash_variable, loc));
1752                         hashcode.Block = hashcode_block;
1753                         hashcode.ResolveMembers ();
1754                         AddMethod (hashcode);
1755
1756                         //
1757                         // ToString () override
1758                         //
1759
1760                         ToplevelBlock tostring_block = new ToplevelBlock (loc);
1761                         tostring_block.AddStatement (new Return (string_concat, loc));
1762                         tostring.Block = tostring_block;
1763                         tostring.ResolveMembers ();
1764                         AddMethod (tostring);
1765                 }
1766
1767                 public override bool DefineMembers ()
1768                 {
1769                         DefineOverrides ();
1770
1771                         return base.DefineMembers ();
1772                 }
1773
1774                 public override string GetSignatureForError ()
1775                 {
1776                         return SignatureForError;
1777                 }
1778
1779                 public ArrayList Parameters {
1780                         get {
1781                                 return parameters;
1782                         }
1783                 }
1784         }
1785 }