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