2006-10-08 Marek Safar <marek.safar@seznam.cz>
[mono.git] / mcs / mcs / anonymous.cs
1 //
2 // anonymous.cs: Support for anonymous methods
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximain.com)
6 //
7 // (C) 2003, 2004 Novell, Inc.
8 //
9 // TODO: Ideally, we should have the helper classes emited as a hierarchy to map
10 // their nesting, and have the visibility set to private, instead of NestedAssembly
11 //
12 //
13 //
14
15 using System;
16 using System.Text;
17 using System.Collections;
18 using System.Reflection;
19 using System.Reflection.Emit;
20
21 namespace Mono.CSharp {
22
23         public abstract class CompilerGeneratedClass : Class
24         {
25                 GenericMethod generic_method;
26                 static int next_index = 0;
27
28                 private static MemberName MakeProxyName (GenericMethod generic, Location loc)
29                 {
30                         string name = String.Format ("<>c__CompilerGenerated{0}", ++next_index);
31                         if (generic != null) {
32                                 TypeArguments args = new TypeArguments (loc);
33                                 foreach (TypeParameter tparam in generic.CurrentTypeParameters)
34                                         args.Add (new SimpleName (tparam.Name, loc));
35                                 return new MemberName (name, args, loc);
36                         } else
37                                 return new MemberName (name, loc);
38                 }
39
40                 protected string MakeName (string prefix)
41                 {
42                         return String.Format ("<>c__{0}{1}", prefix, ++next_index);
43                 }
44
45                 protected CompilerGeneratedClass (TypeContainer parent, GenericMethod generic,
46                                                   int mod, Location loc)
47                         : base (parent.NamespaceEntry, parent,
48                                 MakeProxyName (generic, loc), mod, null)
49                 {
50                         this.generic_method = generic;
51
52                         if (generic != null) {
53                                 ArrayList list = new ArrayList ();
54                                 foreach (TypeParameter tparam in generic.TypeParameters) {
55                                         if (tparam.Constraints != null)
56                                                 list.Add (tparam.Constraints.Clone ());
57                                 }
58                                 SetParameterInfo (list);
59                         }
60
61                         parent.AddCompilerGeneratedClass (this);
62                 }
63
64                 protected override bool DefineNestedTypes ()
65                 {
66                         RootContext.RegisterCompilerGeneratedType (TypeBuilder);
67                         return base.DefineNestedTypes ();
68                 }
69
70                 protected override bool DoDefineMembers ()
71                 {
72                         members_defined = true;
73
74                         if (!base.DoDefineMembers ())
75                                 return false;
76
77                         if (CompilerGenerated != null) {
78                                 foreach (CompilerGeneratedClass c in CompilerGenerated) {
79                                         if (!c.DefineMembers ())
80                                                 throw new InternalErrorException ();
81                                 }
82                         }
83
84                         return true;
85                 }
86
87                 protected override bool DoResolveMembers ()
88                 {
89                         if (CompilerGenerated != null) {
90                                 foreach (CompilerGeneratedClass c in CompilerGenerated) {
91                                         if (!c.ResolveMembers ())
92                                                 return false;
93                                 }
94                         }
95
96                         return base.DoResolveMembers ();
97                 }
98
99                 public GenericMethod GenericMethod {
100                         get { return generic_method; }
101                 }
102
103                 public TypeExpr InflateType (Type it)
104                 {
105 #if GMCS_SOURCE
106                         if (generic_method == null)
107                                 return new TypeExpression (it, Location);
108
109                         if (it.IsGenericParameter && (it.DeclaringMethod != null)) {
110                                 int pos = it.GenericParameterPosition;
111                                 it = CurrentTypeParameters [pos].Type;
112                         } else if (it.IsGenericType) {
113                                 Type[] args = it.GetGenericArguments ();
114
115                                 TypeArguments inflated = new TypeArguments (Location);
116                                 foreach (Type t in args)
117                                         inflated.Add (InflateType (t));
118
119                                 return new ConstructedType (it, inflated, Location);
120                         } else if (it.IsArray) {
121                                 TypeExpr et_expr = InflateType (it.GetElementType ());
122                                 int rank = it.GetArrayRank ();
123
124                                 Type et = et_expr.ResolveAsTypeTerminal (this, false).Type;
125                                 it = et.MakeArrayType (rank);
126                         }
127 #endif
128
129                         return new TypeExpression (it, Location);
130                 }
131
132                 public Field CaptureVariable (string name, TypeExpr type)
133                 {
134                         if (members_defined)
135                                 throw new InternalErrorException ("Helper class already defined!");
136                         if (type == null)
137                                 throw new ArgumentNullException ();
138
139                         return new CapturedVariableField (this, name, type);
140                 }
141
142                 bool members_defined;
143
144                 internal void CheckMembersDefined ()
145                 {
146                         if (members_defined)
147                                 throw new InternalErrorException ("Helper class already defined!");
148                 }
149
150                 protected class CapturedVariableField : Field
151                 {
152                         public CapturedVariableField (CompilerGeneratedClass helper, string name,
153                                                       TypeExpr type)
154                                 : base (helper, type, Modifiers.INTERNAL, name, null, helper.Location)
155                         {
156                                 helper.AddField (this);
157                         }
158                 }
159         }
160
161         public class ScopeInfo : CompilerGeneratedClass
162         {
163                 public readonly AnonymousMethodHost RootScope;
164                 public readonly int ID = ++next_id;
165                 public Block ScopeBlock;
166
167                 static int next_id;
168
169                 public ScopeInfo (AnonymousMethodHost root, Block block)
170                         : base (root, null, Modifiers.PUBLIC, block.StartLocation)
171                 {
172                         this.RootScope = root;
173                         ScopeBlock = block;
174
175                         Report.Debug (64, "NEW SCOPE", this, root, block);
176
177                         root.AddScope (this);
178                 }
179
180                 public ScopeInfo (ToplevelBlock toplevel, TypeContainer parent,
181                                   GenericMethod generic, Location loc)
182                         : base (parent, generic, 0, loc)
183                 {
184                         RootScope = (AnonymousMethodHost) this;
185                         ScopeBlock = toplevel;
186
187                         Report.Debug (64, "NEW ROOT SCOPE", this);
188                 }
189
190                 protected CapturedScope scope_instance;
191                 protected ScopeInitializer scope_initializer;
192
193                 Hashtable locals = new Hashtable ();
194
195                 public virtual AnonymousMethodHost Host {
196                         get { return RootScope; }
197                 }
198
199                 public Variable ScopeInstance {
200                         get { return scope_instance; }
201                 }
202
203                 public void EmitScopeInstance (EmitContext ec)
204                 {
205                         if (scope_initializer == null) {
206                                 //
207                                 // This is needed if someone overwrites the Emit method
208                                 // of Statement and manually calls Block.Emit without
209                                 // this snippet first:
210                                 // 
211                                 //   ec.EmitScopeInitFromBlock (The_Block);
212                                 //   The_Block.Emit (ec);
213                                 // 
214                                 throw new InternalErrorException ();
215                         }
216
217                         scope_initializer.Emit (ec);
218                 }
219
220                 public ExpressionStatement GetScopeInitializer (EmitContext ec)
221                 {
222                         Report.Debug (64, "GET SCOPE INITIALIZER",
223                                       this, GetType (), scope_initializer, ScopeBlock);
224
225                         if (scope_initializer == null) {
226                                 scope_initializer = CreateScopeInitializer ();
227                                 if (scope_initializer.Resolve (ec) == null)
228                                         throw new InternalErrorException ();
229                         }
230
231                         return scope_initializer;
232                 }
233
234                 public Type GetScopeType (EmitContext ec)
235                 {
236                         if (!IsGeneric)
237                                 return TypeBuilder;
238
239                         TypeArguments targs = new TypeArguments (Location);
240
241                         if (ec.DeclContainer.Parent.IsGeneric)
242                                 foreach (TypeParameter t in ec.DeclContainer.Parent.TypeParameters)
243                                         targs.Add (new TypeParameterExpr (t, Location));
244                         if (ec.DeclContainer.IsGeneric)
245                                 foreach (TypeParameter t in ec.DeclContainer.CurrentTypeParameters)
246                                         targs.Add (new TypeParameterExpr (t, Location));
247
248                         TypeExpr te = new ConstructedType (TypeBuilder, targs, Location);
249                         te = te.ResolveAsTypeTerminal (ec, false);
250                         if ((te == null) || (te.Type == null))
251                                 return null;
252                         return te.Type;
253                 }
254
255                 protected override bool DoResolveMembers ()
256                 {
257                         Report.Debug (64, "SCOPE INFO RESOLVE MEMBERS", this, GetType (), IsGeneric,
258                                       Parent.IsGeneric, GenericMethod);
259
260                         if (Host != this)
261                                 scope_instance = new CapturedScope (Host, this);
262
263                         return base.DoResolveMembers ();
264                 }
265
266                 public Variable AddLocal (LocalInfo local)
267                 {
268                         Variable var = (Variable) locals [local];
269                         if (var == null) {
270                                 var = new CapturedLocal (this, local);
271                                 locals.Add (local, var);
272                                 local.IsCaptured = true;
273                         }
274                         return var;
275                 }
276
277                 public Variable GetCapturedVariable (LocalInfo local)
278                 {
279                         return (Variable) locals [local];
280                 }
281
282                 protected string MakeFieldName (string local_name)
283                 {
284                         return "<" + ID + ":" + local_name + ">";
285                 }
286
287                 protected virtual ScopeInitializer CreateScopeInitializer ()
288                 {
289                         return new ScopeInitializer (this);
290                 }
291
292                 protected abstract class CapturedVariable : Variable
293                 {
294                         public readonly ScopeInfo Scope;
295                         public readonly Field Field;
296
297                         public FieldExpr FieldInstance;
298
299                         protected CapturedVariable (ScopeInfo scope, string name, Type type)
300                         {
301                                 this.Scope = scope;
302                                 this.Field = scope.CaptureVariable (
303                                         scope.MakeFieldName (name), scope.RootScope.InflateType (type));
304                         }
305
306                         public override Type Type {
307                                 get { return Field.MemberType; }
308                         }
309
310                         public override bool HasInstance {
311                                 get { return true; }
312                         }
313
314                         public override bool NeedsTemporary {
315                                 get { return true; }
316                         }
317
318                         protected FieldInfo GetField (EmitContext ec)
319                         {
320                                 if (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel)
321                                         return Field.FieldBuilder;
322                                 else
323                                         return FieldInstance.FieldInfo;
324                         }
325
326                         public override void EmitInstance (EmitContext ec)
327                         {
328                                 ec.CurrentBlock.Toplevel.EmitScopeInstance (ec, Scope);
329                         }
330
331                         public override void Emit (EmitContext ec)
332                         {
333                                 ec.ig.Emit (OpCodes.Ldfld, GetField (ec));
334                         }
335
336                         public override void EmitAssign (EmitContext ec)
337                         {
338                                 ec.ig.Emit (OpCodes.Stfld, GetField (ec));
339                         }
340
341                         public override void EmitAddressOf (EmitContext ec)
342                         {
343                                 ec.ig.Emit (OpCodes.Ldflda, GetField (ec));
344                         }
345                 }
346
347                 protected class CapturedParameter : CapturedVariable {
348                         public readonly Parameter Parameter;
349                         public readonly int Idx;
350
351                         public CapturedParameter (ScopeInfo scope, Parameter par, int idx)
352                                 : base (scope, par.Name, par.ParameterType)
353                         {
354                                 this.Parameter = par;
355                                 this.Idx = idx;
356                         }
357
358                         public override string ToString ()
359                         {
360                                 return String.Format ("{0} ({1}:{2}:{3})", GetType (), Field,
361                                                       Parameter.Name, Idx);
362                         }
363                 }
364
365                 protected class CapturedLocal : CapturedVariable {
366                         public readonly LocalInfo Local;
367
368                         public CapturedLocal (ScopeInfo scope, LocalInfo local)
369                                 : base (scope, local.Name, local.VariableType)
370                         {
371                                 this.Local = local;
372                         }
373
374                         public override string ToString ()
375                         {
376                                 return String.Format ("{0} ({1}:{2})", GetType (), Field,
377                                                       Local.Name);
378                         }
379                 }
380
381                 protected class CapturedThis : CapturedVariable {
382                         public CapturedThis (AnonymousMethodHost host)
383                                 : base (host, "<>THIS", host.ParentType)
384                         { }
385                 }
386
387                 protected class CapturedScope : CapturedVariable {
388                         public readonly ScopeInfo ChildScope;
389
390                         public CapturedScope (ScopeInfo root, ScopeInfo child)
391                                 : base (root, child.ID + "_scope", child.TypeBuilder)
392                         {
393                                 this.ChildScope = child;
394                         }
395                 }
396
397                 static void DoPath (StringBuilder sb, ScopeInfo start)
398                 {
399                         sb.Append ((start.ID).ToString ());
400                 }
401                 
402                 public override string ToString ()
403                 {
404                         StringBuilder sb = new StringBuilder ();
405                         
406                         sb.Append ("{");
407                         DoPath (sb, this);
408                         sb.Append ("}");
409
410                         return sb.ToString ();
411                 }
412
413                 protected class ScopeInitializer : ExpressionStatement
414                 {
415                         ScopeInfo scope;
416                         LocalBuilder scope_instance;
417                         ConstructorInfo scope_ctor;
418
419                         bool initialized;
420
421                         public ScopeInitializer (ScopeInfo scope)
422                         {
423                                 this.scope = scope;
424                                 this.loc = scope.Location;
425                                 eclass = ExprClass.Value;
426                         }
427
428                         public ScopeInfo Scope {
429                                 get { return scope; }
430                         }
431
432                         public override Expression DoResolve (EmitContext ec)
433                         {
434                                 if (scope_ctor != null)
435                                         return this;
436
437                                 Report.Debug (64, "RESOLVE SCOPE INITIALIZER BASE", this, Scope,
438                                               ec, ec.CurrentBlock);
439
440                                 type = Scope.GetScopeType (ec);
441                                 if (type == null)
442                                         throw new InternalErrorException ();
443
444                                 if (!DoResolveInternal (ec))
445                                         throw new InternalErrorException ();
446
447                                 return this;
448                         }
449
450                         protected virtual bool DoResolveInternal (EmitContext ec)
451                         {
452                                 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookupFinal (
453                                         ec, ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
454                                         AllBindingFlags | BindingFlags.DeclaredOnly, loc);
455                                 if (mg == null)
456                                         throw new InternalErrorException ();
457
458                                 scope_ctor = (ConstructorInfo) mg.Methods [0];
459
460                                 if (Scope.ScopeInstance == null)
461                                         scope_instance = ec.ig.DeclareLocal (type);
462                                 else {
463                                         Type root = Scope.Host.GetScopeType (ec);
464                                         FieldExpr fe = (FieldExpr) Expression.MemberLookup (
465                                                 type, root, Scope.scope_instance.Field.Name, loc);
466                                         if (fe == null)
467                                                 throw new InternalErrorException ();
468
469                                         fe.InstanceExpression = this;
470                                         Scope.scope_instance.FieldInstance = fe;
471                                 }
472
473                                 foreach (CapturedLocal local in Scope.locals.Values) {
474                                         FieldExpr fe = (FieldExpr) Expression.MemberLookup (
475                                                 ec.ContainerType, type, local.Field.Name, loc);
476                                         Report.Debug (64, "RESOLVE SCOPE INITIALIZER #2", this, Scope,
477                                                       Scope, ec, ec.ContainerType, type,
478                                                       local.Field, local.Field.Name, loc, fe);
479                                         if (fe == null)
480                                                 throw new InternalErrorException ();
481
482                                         fe.InstanceExpression = this;
483                                         local.FieldInstance = fe;
484                                 }
485
486                                 return true;
487                         }
488
489                         protected virtual void EmitParameterReference (EmitContext ec,
490                                                                        CapturedParameter cp)
491                         {
492                                 int extra = ec.IsStatic ? 0 : 1;
493                                 ParameterReference.EmitLdArg (ec.ig, cp.Idx + extra);
494                         }
495
496                         static int next_id;
497                         int id = ++next_id;
498
499                         protected virtual void DoEmit (EmitContext ec)
500                         {
501                                 if (ec.CurrentBlock.Toplevel == Scope.ScopeBlock.Toplevel)
502                                         DoEmitInstance (ec);
503                                 else
504                                         ec.ig.Emit (OpCodes.Ldarg_0);
505                         }
506
507                         protected void DoEmitInstance (EmitContext ec)
508                         {
509                                 ec.ig.Emit (OpCodes.Ldloc, scope_instance);
510                         }
511
512                         protected virtual void EmitScopeConstructor (EmitContext ec)
513                         {
514                                 ec.ig.Emit (OpCodes.Newobj, scope_ctor);
515                         }
516
517                         public override void Emit (EmitContext ec)
518                         {
519                                 if (!initialized)
520                                         throw new InternalErrorException (
521                                                 "Scope {0} not initialized yet", scope);
522
523                                 DoEmit (ec);
524                         }
525
526                         public override void EmitStatement (EmitContext ec)
527                         {
528                                 if (initialized)
529                                         return;
530
531                                 DoEmitStatement (ec);
532                                 initialized = true;
533                         }
534
535                         protected virtual void DoEmitStatement (EmitContext ec)
536                         {
537                                 Report.Debug (64, "EMIT SCOPE INIT", this, id,
538                                               Scope, scope_instance, ec);
539
540                                 ec.ig.Emit (OpCodes.Nop);
541                                 ec.ig.Emit (OpCodes.Ldc_I4, id);
542                                 ec.ig.Emit (OpCodes.Pop);
543                                 ec.ig.Emit (OpCodes.Nop);
544
545                                 if (Scope != Scope.Host)
546                                         Scope.Host.EmitScopeInstance (ec);
547                                 else if (Scope.ScopeInstance != null)
548                                         ec.ig.Emit (OpCodes.Ldarg_0);
549                                 EmitScopeConstructor (ec);
550                                 if (Scope.ScopeInstance != null)
551                                         Scope.ScopeInstance.EmitAssign (ec);
552                                 else
553                                         ec.ig.Emit (OpCodes.Stloc, scope_instance);
554                         }
555                 }
556         }
557
558         public class AnonymousMethodHost : ScopeInfo
559         {
560                 public AnonymousMethodHost (ToplevelBlock toplevel, TypeContainer parent,
561                                             GenericMethod generic, Location loc)
562                         : base (toplevel, parent, generic, loc)
563                 {
564                         scopes = new ArrayList ();
565                 }
566
567                 ArrayList scopes;
568                 TypeExpr parent_type;
569                 CapturedVariableField parent_link;
570                 CapturedThis this_variable;
571                 Hashtable captured_params;
572
573                 public override AnonymousMethodHost Host {
574                         get { return this; }
575                 }
576
577                 public virtual bool IsIterator {
578                         get { return false; }
579                 }
580
581                 public AnonymousMethodHost ParentHost {
582                         get { return Parent as AnonymousMethodHost; }
583                 }
584
585                 public Type ParentType {
586                         get { return parent_type.Type; }
587                 }
588
589                 public Field ParentLink {
590                         get { return parent_link; }
591                 }
592
593                 protected CapturedThis THIS {
594                         get { return this_variable; }
595                 }
596
597                 public bool HostsParameters {
598                         get { return captured_params != null; }
599                 }
600
601                 public Variable CaptureThis ()
602                 {
603                         if (ParentHost != null)
604                                 return ParentHost.CaptureThis ();
605
606                         CheckMembersDefined ();
607                         if (this_variable == null)
608                                 this_variable = new CapturedThis (this);
609                         return this_variable;
610                 }
611
612                 public Variable GetCapturedParameter (Parameter par)
613                 {
614                         if (captured_params != null)
615                                 return (Variable) captured_params [par];
616                         else
617                                 return null;
618                 }
619
620                 public bool IsParameterCaptured (string name)
621                 {                       
622                         if (captured_params != null)
623                                 return captured_params [name] != null;
624                         return false;
625                 }
626
627                 public Variable AddParameter (Parameter par, int idx)
628                 {
629                         if (captured_params == null)
630                                 captured_params = new Hashtable ();
631
632                         Variable var = (Variable) captured_params [par];
633                         if (var == null) {
634                                 var = new CapturedParameter (this, par, idx);
635                                 captured_params.Add (par, var);
636                                 par.IsCaptured = true;
637                         }
638
639                         return var;
640                 }
641
642                 public void AddScope (ScopeInfo scope)
643                 {
644                         scopes.Add (scope);
645                 }
646
647                 bool linked;
648                 public void LinkScopes ()
649                 {
650                         if (linked)
651                                 return;
652
653                         linked = true;
654                         if (ParentHost != null)
655                                 ParentHost.LinkScopes ();
656
657                         foreach (ScopeInfo si in scopes) {
658                                 if (!si.Define ())
659                                         throw new InternalErrorException ();
660                                 if (si.DefineType () == null)
661                                         throw new InternalErrorException ();
662                         }
663                 }
664
665                 protected override ScopeInitializer CreateScopeInitializer ()
666                 {
667                         return new AnonymousMethodHostInitializer (this);
668                 }
669
670                 protected override bool DefineNestedTypes ()
671                 {
672                         if (Parent.IsGeneric) {
673                                 parent_type = new ConstructedType (
674                                         Parent.TypeBuilder, Parent.TypeParameters, Location);
675                                 parent_type = parent_type.ResolveAsTypeTerminal (this, false);
676                                 if ((parent_type == null) || (parent_type.Type == null))
677                                         return false;
678                         } else {
679                                 parent_type = new TypeExpression (Parent.TypeBuilder, Location);
680                         }
681
682                         CompilerGeneratedClass parent = Parent as CompilerGeneratedClass;
683                         if (parent != null)
684                                 parent_link = new CapturedVariableField (this, "<>parent", parent_type);
685
686                         return base.DefineNestedTypes ();
687                 }
688
689                 protected override bool DoDefineMembers ()
690                 {
691                         ArrayList args = new ArrayList ();
692                         if (this is IteratorHost)
693                                 args.Add (new Parameter (
694                                         TypeManager.int32_type, "$PC", Parameter.Modifier.NONE,
695                                         null, Location));
696
697                         Field pfield;
698                         if (Parent is CompilerGeneratedClass)
699                                 pfield = parent_link;
700                         else
701                                 pfield = this_variable !=  null ? this_variable.Field : null;
702                         if (pfield != null)
703                                 args.Add (new Parameter (
704                                         pfield.MemberType, "parent", Parameter.Modifier.NONE,
705                                         null, Location));
706
707                         if (HostsParameters) {
708                                 foreach (CapturedParameter cp in captured_params.Values) {
709                                         args.Add (new Parameter (
710                                                           cp.Field.MemberType, cp.Field.Name,
711                                                           Parameter.Modifier.NONE, null, Location));
712                                 }
713                         }
714
715                         Parameter[] ctor_params = new Parameter [args.Count];
716                         args.CopyTo (ctor_params, 0);
717                         Constructor ctor = new Constructor (
718                                 this, MemberName.Name, Modifiers.PUBLIC,
719                                 new Parameters (ctor_params),
720                                 new GeneratedBaseInitializer (Location),
721                                 Location);
722                         AddConstructor (ctor);
723
724                         ctor.Block = new ToplevelBlock (null, Location);
725                         ctor.Block.AddStatement (new TheCtor (this));
726
727                         return base.DoDefineMembers ();
728                 }
729
730                 protected virtual void EmitScopeConstructor (EmitContext ec)
731                 {
732                         int pos = (this is IteratorHost) ? 2 : 1;
733
734                         Field pfield;
735                         if (Parent is CompilerGeneratedClass)
736                                 pfield = parent_link;
737                         else
738                                 pfield = this_variable !=  null ? this_variable.Field : null;
739
740                         if (pfield != null) {
741                                 ec.ig.Emit (OpCodes.Ldarg_0);
742                                 ec.ig.Emit (OpCodes.Ldarg, pos);
743                                 ec.ig.Emit (OpCodes.Stfld, pfield.FieldBuilder);
744                                 pos++;
745                         }
746
747                         if (HostsParameters) {
748                                 foreach (CapturedParameter cp in captured_params.Values) {
749                                         ec.ig.Emit (OpCodes.Ldarg_0);
750                                         ParameterReference.EmitLdArg (ec.ig, pos++);
751                                         ec.ig.Emit (OpCodes.Stfld, cp.Field.FieldBuilder);
752                                 }
753                         }
754                 }
755
756                 protected class TheCtor : Statement
757                 {
758                         AnonymousMethodHost host;
759
760                         public TheCtor (AnonymousMethodHost host)
761                         {
762                                 this.host = host;
763                         }
764
765                         public override bool Resolve (EmitContext ec)
766                         {
767                                 return true;
768                         }
769
770                         protected override void DoEmit (EmitContext ec)
771                         {
772                                 host.EmitScopeConstructor (ec);
773                         }
774                 }
775
776                 protected class AnonymousMethodHostInitializer : ScopeInitializer
777                 {
778                         AnonymousMethodHost host;
779
780                         public AnonymousMethodHostInitializer (AnonymousMethodHost host)
781                                 : base (host)
782                         {
783                                 this.host = host;
784                         }
785
786                         public AnonymousMethodHost Host {
787                                 get { return host; }
788                         }
789
790                         protected override bool DoResolveInternal (EmitContext ec)
791                         {
792                                 Report.Debug (64, "RESOLVE ANONYMOUS METHOD HOST INITIALIZER",
793                                               this, Host, Host.ParentType, loc);
794
795                                 if (Host.THIS != null) {
796                                         FieldExpr fe = (FieldExpr) Expression.MemberLookup (
797                                                 ec.ContainerType, type, Host.THIS.Field.Name, loc);
798                                         if (fe == null)
799                                                 throw new InternalErrorException ();
800
801                                         fe.InstanceExpression = this;
802                                         Host.THIS.FieldInstance = fe;
803                                 }
804
805                                 //
806                                 // Copy the parameter values, if any
807                                 //
808                                 if (Host.HostsParameters) {
809                                         foreach (CapturedParameter cp in Host.captured_params.Values) {
810                                                 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
811                                                         ec.ContainerType, type, cp.Field.Name, loc);
812                                                 if (fe == null)
813                                                         throw new InternalErrorException ();
814
815                                                 fe.InstanceExpression = this;
816                                                 cp.FieldInstance = fe;
817                                         }
818                                 }
819
820                                 return base.DoResolveInternal (ec);
821                         }
822
823                         protected virtual bool IsGetEnumerator {
824                                 get { return false; }
825                         }
826
827                         protected override void EmitScopeConstructor (EmitContext ec)
828                         {
829                                 if (host.THIS != null) {
830                                         ec.ig.Emit (OpCodes.Ldarg_0);
831                                         if (IsGetEnumerator)
832                                                 ec.ig.Emit (OpCodes.Ldfld, host.THIS.Field.FieldBuilder);
833                                         else if (host.THIS.Type.IsValueType)
834                                                 Expression.LoadFromPtr (ec.ig, host.THIS.Type);
835                                 } else if (host.ParentLink != null)
836                                         ec.ig.Emit (OpCodes.Ldarg_0);
837
838                                 if (Host.HostsParameters) {
839                                         foreach (CapturedParameter cp in Host.captured_params.Values) {
840                                                 EmitParameterReference (ec, cp);
841                                         }
842                                 }
843
844                                 base.EmitScopeConstructor (ec);
845                         }
846                 }
847
848         }
849
850         public interface IAnonymousContainer
851         {
852                 Block Container {
853                         get;
854                 }
855
856                 GenericMethod GenericMethod {
857                         get;
858                 }
859
860                 AnonymousMethodHost RootScope {
861                         get;
862                 }
863
864                 bool IsIterator {
865                         get;
866                 }
867         }
868
869         public interface IAnonymousHost
870         {
871                 //
872                 // Invoked if a yield statement is found in the body
873                 //
874                 void SetYields ();
875
876                 //
877                 // Invoked if an anonymous method is found in the body
878                 //
879                 void AddAnonymousMethod (AnonymousMethodExpression anonymous);
880         }
881
882         public class AnonymousMethodExpression : Expression, IAnonymousContainer, IAnonymousHost
883         {
884                 public readonly AnonymousMethodExpression Parent;
885                 public readonly TypeContainer Host;
886                 public readonly Parameters Parameters;
887
888                 public ToplevelBlock Block;
889                 protected AnonymousMethod anonymous;
890
891                 protected readonly Block container;
892                 protected readonly GenericMethod generic;
893
894                 public Block Container {
895                         get { return container; }
896                 }
897
898                 public GenericMethod GenericMethod {
899                         get { return generic; }
900                 }
901
902                 public AnonymousMethod AnonymousMethod {
903                         get { return anonymous; }
904                 }
905
906                 public AnonymousMethodHost RootScope {
907                         get { return root_scope; }
908                 }
909
910                 public AnonymousMethodExpression (AnonymousMethodExpression parent,
911                                                   GenericMethod generic, TypeContainer host,
912                                                   Parameters parameters, Block container,
913                                                   Location loc)
914                 {
915                         this.Parent = parent;
916                         this.generic = parent != null ? null : generic;
917                         this.Host = host;
918                         this.Parameters = parameters;
919                         this.container = container;
920                         this.loc = loc;
921
922                         Report.Debug (64, "NEW ANONYMOUS METHOD EXPRESSION", this, parent, host,
923                                       container, loc);
924
925                         if (parent != null)
926                                 parent.AddAnonymousMethod (this);
927                 }
928
929                 ArrayList children;
930                 AnonymousMethodHost root_scope;
931
932                 static int next_index;
933
934                 void IAnonymousHost.SetYields ()
935                 {
936                         throw new InvalidOperationException ();
937                 }
938
939                 public void AddAnonymousMethod (AnonymousMethodExpression anonymous)
940                 {
941                         if (children == null)
942                                 children = new ArrayList ();
943                         children.Add (anonymous);
944                 }
945
946                 public bool CreateAnonymousHelpers ()
947                 {
948                         Report.Debug (64, "ANONYMOUS METHOD EXPRESSION CREATE ROOT SCOPE",
949                                       this, Host, container, loc);
950
951                         if (container != null)
952                                 root_scope = container.Toplevel.CreateAnonymousMethodHost (Host);
953
954                         if (children != null) {
955                                 foreach (AnonymousMethodExpression child in children) {
956                                         if (!child.CreateAnonymousHelpers ())
957                                                 return false;
958                                 }
959                         }
960
961                         return true;
962                 }
963
964                 public override string ExprClassName {
965                         get {
966                                 return "anonymous method";
967                         }
968                 }
969
970                 void Error_ParameterMismatch (Type t)
971                 {
972                         Report.Error (1661, loc, "Anonymous method could not be converted to delegate `" +
973                                       "{0}' since there is a parameter mismatch",
974                                       TypeManager.CSharpName (t));
975                 }
976
977                 public bool ImplicitStandardConversionExists (Type delegate_type)
978                 {
979                         if (Parameters == null)
980                                 return true;
981
982                         MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
983                                 Host.TypeBuilder, delegate_type, loc);
984                         MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
985                         ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
986
987                         if (Parameters.Count != invoke_pd.Count)
988                                 return false;
989
990                         for (int i = 0; i < Parameters.Count; ++i) {
991                                 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i))
992                                         return false;
993                         }
994                         return true;
995                 }
996
997                 //
998                 // Returns true if this anonymous method can be implicitly
999                 // converted to the delegate type `delegate_type'
1000                 //
1001                 public Expression Compatible (EmitContext ec, Type delegate_type)
1002                 {
1003                         if (anonymous != null)
1004                                 return anonymous.AnonymousDelegate;
1005
1006                         if (!ec.IsAnonymousMethodAllowed) {
1007                                 Report.Error (1706, loc,
1008                                               "Anonymous methods are not allowed in the " +
1009                                               "attribute declaration");
1010                                 return null;
1011                         }
1012
1013                         if (!TypeManager.IsDelegateType (delegate_type)){
1014                                 Report.Error (1660, loc,
1015                                               "Cannot convert anonymous method block to type " +
1016                                               "`{0}' because it is not a delegate type",
1017                                               TypeManager.CSharpName (delegate_type));
1018                                 return null;
1019                         }
1020
1021                         //
1022                         // At this point its the first time we know the return type that is 
1023                         // needed for the anonymous method.  We create the method here.
1024                         //
1025
1026                         MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
1027                                 ec.ContainerType, delegate_type, loc);
1028                         MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
1029                         ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
1030
1031                         Parameters parameters;
1032                         if (Parameters == null) {
1033                                 //
1034                                 // We provide a set of inaccessible parameters
1035                                 //
1036                                 Parameter [] fixedpars = new Parameter [invoke_pd.Count];
1037                                                                 
1038                                 for (int i = 0; i < invoke_pd.Count; i++) {
1039                                         Parameter.Modifier i_mod = invoke_pd.ParameterModifier (i);
1040                                         if ((i_mod & Parameter.Modifier.OUTMASK) != 0) {
1041                                                 Report.Error (1688, loc, "Cannot convert anonymous " +
1042                                                               "method block without a parameter list " +
1043                                                               "to delegate type `{0}' because it has " +
1044                                                               "one or more `out' parameters.",
1045                                                               TypeManager.CSharpName (delegate_type));
1046                                                 return null;
1047                                         }
1048                                         fixedpars [i] = new Parameter (
1049                                                 invoke_pd.ParameterType (i), "+" + (++next_index),
1050                                                 invoke_pd.ParameterModifier (i), null, loc);
1051                                 }
1052                                                                 
1053                                 parameters = new Parameters (fixedpars);
1054                                 if (!parameters.Resolve (ec))
1055                                         return null;
1056                         } else {
1057                                 if (Parameters.Count != invoke_pd.Count) {
1058                                         Report.SymbolRelatedToPreviousError (delegate_type);
1059                                         Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
1060                                                 TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
1061                                         Error_ParameterMismatch (delegate_type);
1062                                         return null;
1063                                 }
1064
1065                                 for (int i = 0; i < Parameters.Count; ++i) {
1066                                         Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
1067                                         if (Parameters.ParameterModifier (i) != p_mod && p_mod != Parameter.Modifier.PARAMS) {
1068                                                 if (p_mod == Parameter.Modifier.NONE)
1069                                                         Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
1070                                                                 (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.ParameterModifier (i)));
1071                                                 else
1072                                                         Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
1073                                                                 (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
1074                                                 Error_ParameterMismatch (delegate_type);
1075                                                 return null;
1076                                         }
1077
1078                                         if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i)) {
1079                                                 Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
1080                                                         (i+1).ToString (),
1081                                                         TypeManager.CSharpName (Parameters.ParameterType (i)),
1082                                                         TypeManager.CSharpName (invoke_pd.ParameterType (i)));
1083                                                 Error_ParameterMismatch (delegate_type);
1084                                                 return null;
1085                                         }
1086                                 }
1087
1088                                 parameters = Parameters;
1089                         }
1090
1091                         //
1092                         // Second: the return type of the delegate must be compatible with 
1093                         // the anonymous type.   Instead of doing a pass to examine the block
1094                         // we satisfy the rule by setting the return type on the EmitContext
1095                         // to be the delegate type return type.
1096                         //
1097
1098                         //MethodBuilder builder = method_data.MethodBuilder;
1099                         //ILGenerator ig = builder.GetILGenerator ();
1100
1101                         Report.Debug (64, "COMPATIBLE", this, Parent, GenericMethod, Host,
1102                                       Container, Block, invoke_mb.ReturnType, delegate_type,
1103                                       TypeManager.IsGenericType (delegate_type), loc);
1104
1105                         anonymous = new AnonymousMethod (
1106                                 Parent != null ? Parent.AnonymousMethod : null, RootScope, Host,
1107                                 GenericMethod, parameters, Container, Block, invoke_mb.ReturnType,
1108                                 delegate_type, loc);
1109
1110                         if (!anonymous.Resolve (ec))
1111                                 return null;
1112
1113                         return anonymous.AnonymousDelegate;
1114                 }
1115
1116                 public override Expression DoResolve (EmitContext ec)
1117                 {
1118                         //
1119                         // Set class type, set type
1120                         //
1121
1122                         eclass = ExprClass.Value;
1123
1124                         //
1125                         // This hack means `The type is not accessible
1126                         // anywhere', we depend on special conversion
1127                         // rules.
1128                         // 
1129                         type = TypeManager.anonymous_method_type;
1130
1131                         if ((Parameters != null) && !Parameters.Resolve (ec))
1132                                 return null;
1133
1134                         return this;
1135                 }
1136
1137                 public override void Emit (EmitContext ec)
1138                 {
1139                         // nothing, as we only exist to not do anything.
1140                 }
1141
1142                 public bool IsIterator {
1143                         get { return false; }
1144                 }
1145         }
1146
1147         public abstract class AnonymousContainer : IAnonymousContainer
1148         {
1149                 // Used to generate unique method names.
1150                 protected static int anonymous_method_count;
1151
1152                 public readonly Location Location;
1153
1154                 // An array list of AnonymousMethodParameter or null
1155                 public readonly Parameters Parameters;
1156
1157                 //
1158                 // The block that makes up the body for the anonymous mehtod
1159                 //
1160                 public readonly ToplevelBlock Block;
1161
1162                 public readonly int ModFlags;
1163                 public readonly Type ReturnType;
1164                 public readonly TypeContainer Host;
1165
1166                 //
1167                 // The implicit method we create
1168                 //
1169                 protected Method method;
1170                 protected EmitContext aec;
1171
1172                 // The emit context for the anonymous method
1173                 protected bool unreachable;
1174                 protected readonly Block container;
1175                 protected readonly GenericMethod generic;
1176
1177                 //
1178                 // Points to our container anonymous method if its present
1179                 //
1180                 public readonly AnonymousContainer ContainerAnonymousMethod;
1181
1182                 protected AnonymousContainer (AnonymousContainer parent, TypeContainer host,
1183                                               GenericMethod generic, Parameters parameters,
1184                                               Block container, ToplevelBlock block,
1185                                               Type return_type, int mod, Location loc)
1186                 {
1187                         this.ContainerAnonymousMethod = parent;
1188                         this.ReturnType = return_type;
1189                         this.ModFlags = mod;
1190                         this.Host = host;
1191
1192                         this.container = container;
1193                         this.generic = parent != null ? null : generic;
1194                         this.Parameters = parameters;
1195                         this.Block = block;
1196                         this.Location = loc;
1197                 }
1198
1199                 public Method Method {
1200                         get { return method; }
1201                 }
1202
1203                 public abstract AnonymousMethodHost RootScope {
1204                         get;
1205                 }
1206
1207                 public abstract string GetSignatureForError ();
1208
1209                 public virtual bool Resolve (EmitContext ec)
1210                 {
1211                         Report.Debug (64, "RESOLVE ANONYMOUS METHOD", this, Location, ec,
1212                                       RootScope, Parameters, ec.IsStatic);
1213
1214                         aec = new EmitContext (
1215                                 ec.ResolveContext, ec.TypeContainer,
1216                                 RootScope != null ? RootScope : Host, Location, null, ReturnType,
1217                                 /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) |
1218                                 (ec.InUnsafe ? Modifiers.UNSAFE : 0), /* No constructor */ false);
1219
1220                         aec.CurrentAnonymousMethod = this;
1221                         aec.IsFieldInitializer = ec.IsFieldInitializer;
1222
1223                         Report.Debug (64, "RESOLVE ANONYMOUS METHOD #1", this, Location, ec, aec,
1224                                       RootScope, Parameters, Block);
1225
1226                         bool unreachable;
1227                         if (!aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable))
1228                                 return false;
1229
1230                         Report.Debug (64, "RESOLVE ANONYMOUS METHOD #3", this, ec, aec, Block);
1231
1232                         method = DoCreateMethodHost (ec);
1233
1234                         if (RootScope != null)
1235                                 return true;
1236
1237                         if (!method.ResolveMembers ())
1238                                 return false;
1239                         return method.Define ();
1240                 }
1241
1242                 protected abstract Method DoCreateMethodHost (EmitContext ec);
1243
1244                 public Block Container {
1245                         get { return container; }
1246                 }
1247
1248                 public GenericMethod GenericMethod {
1249                         get { return generic; }
1250                 }
1251
1252                 public abstract bool IsIterator {
1253                         get;
1254                 }
1255
1256                 protected class AnonymousMethodMethod : Method
1257                 {
1258                         public AnonymousContainer AnonymousMethod;
1259
1260                         public AnonymousMethodMethod (AnonymousContainer am, GenericMethod generic,
1261                                                       TypeExpr return_type, int mod, MemberName name,
1262                                                       Parameters parameters)
1263                                 : base (am.RootScope != null ? am.RootScope : am.Host,
1264                                         generic, return_type, mod, false, name, parameters, null)
1265                         {
1266                                 this.AnonymousMethod = am;
1267
1268                                 if (am.RootScope != null) {
1269                                         am.RootScope.CheckMembersDefined ();
1270                                         am.RootScope.AddMethod (this);
1271                                 } else {
1272                                         ModFlags |= Modifiers.STATIC;
1273                                         am.Host.AddMethod (this);
1274                                 }
1275                                 Block = am.Block;
1276                         }
1277
1278                         public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
1279                         {
1280                                 EmitContext aec = AnonymousMethod.aec;
1281                                 aec.ig = ig;
1282                                 return aec;
1283                         }
1284                 }
1285         }
1286
1287         public class AnonymousMethod : AnonymousContainer
1288         {
1289                 public readonly Type DelegateType;
1290
1291                 //
1292                 // The value return by the Compatible call, this ensure that
1293                 // the code works even if invoked more than once (Resolve called
1294                 // more than once, due to the way Convert.ImplicitConversion works
1295                 //
1296                 Expression anonymous_delegate;
1297                 AnonymousMethodHost root_scope;
1298
1299                 public AnonymousMethod (AnonymousMethod parent, AnonymousMethodHost root_scope,
1300                                         TypeContainer host, GenericMethod generic,
1301                                         Parameters parameters, Block container,
1302                                         ToplevelBlock block, Type return_type, Type delegate_type,
1303                                         Location loc)
1304                         : base (parent, host, generic, parameters, container, block,
1305                                 return_type, 0, loc)
1306                 {
1307                         this.DelegateType = delegate_type;
1308                         this.root_scope = root_scope;
1309                 }
1310
1311                 public override AnonymousMethodHost RootScope {
1312                         get { return root_scope; }
1313                 }
1314
1315                 public override bool IsIterator {
1316                         get { return false; }
1317                 }
1318
1319                 public Expression AnonymousDelegate {
1320                         get { return anonymous_delegate; }
1321                 }
1322
1323                 public override string GetSignatureForError ()
1324                 {
1325                         return TypeManager.CSharpName (DelegateType);
1326                 }
1327
1328                 //
1329                 // Creates the host for the anonymous method
1330                 //
1331                 protected override Method DoCreateMethodHost (EmitContext ec)
1332                 {
1333                         string name = "<>c__AnonymousMethod" + anonymous_method_count++;
1334                         MemberName member_name;
1335
1336                         GenericMethod generic_method = null;
1337                         if (TypeManager.IsGenericType (DelegateType)) {
1338                                 TypeArguments args = new TypeArguments (Location);
1339
1340                                 Type[] tparam = TypeManager.GetTypeArguments (DelegateType);
1341                                 for (int i = 0; i < tparam.Length; i++)
1342                                         args.Add (new SimpleName (tparam [i].Name, Location));
1343
1344                                 member_name = new MemberName (name, args, Location);
1345
1346                                 generic_method = new GenericMethod (
1347                                         RootScope.NamespaceEntry, RootScope, member_name,
1348                                         new TypeExpression (ReturnType, Location), Parameters);
1349
1350                                 generic_method.SetParameterInfo (null);
1351                         } else
1352                                 member_name = new MemberName (name, Location);
1353
1354                         return new AnonymousMethodMethod (
1355                                 this, generic_method, new TypeExpression (ReturnType, Location),
1356                                 Modifiers.INTERNAL, member_name, Parameters);
1357                 }
1358
1359                 public override bool Resolve (EmitContext ec)
1360                 {
1361                         if (!base.Resolve (ec))
1362                                 return false;
1363
1364                         anonymous_delegate = new AnonymousDelegate (
1365                                 this, DelegateType, Location).Resolve (ec);
1366                         if (anonymous_delegate == null)
1367                                 return false;
1368
1369                         return true;
1370                 }
1371
1372                 public MethodInfo GetMethodBuilder (EmitContext ec)
1373                 {
1374                         MethodInfo builder = method.MethodBuilder;
1375                         if ((RootScope != null) && RootScope.IsGeneric) {
1376                                 Type scope_type = RootScope.GetScopeType (ec);
1377                                 if (scope_type == null)
1378                                         throw new InternalErrorException ();
1379
1380                                 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup (
1381                                         ec.ContainerType, scope_type, builder.Name, Location);
1382
1383                                 if (mg == null)
1384                                         throw new InternalErrorException ();
1385                                 builder = (MethodInfo) mg.Methods [0];
1386                         }
1387
1388 #if GMCS_SOURCE
1389                         if (!DelegateType.IsGenericType)
1390                                 return builder;
1391
1392                         Type[] targs = TypeManager.GetTypeArguments (DelegateType);
1393                         return builder.MakeGenericMethod (targs);
1394 #else
1395                         return builder;
1396 #endif
1397                 }
1398
1399                 public static void Error_AddressOfCapturedVar (string name, Location loc)
1400                 {
1401                         Report.Error (1686, loc,
1402                                       "Local variable `{0}' or its members cannot have their " +
1403                                       "address taken and be used inside an anonymous method block",
1404                                       name);
1405                 }
1406         }
1407
1408         //
1409         // This will emit the code for the delegate, as well delegate creation on the host
1410         //
1411         public class AnonymousDelegate : DelegateCreation {
1412                 AnonymousMethod am;
1413
1414                 public AnonymousDelegate (AnonymousMethod am, Type target_type, Location l)
1415                 {
1416                         type = target_type;
1417                         loc = l;
1418                         this.am = am;
1419                 }
1420
1421                 public override Expression DoResolve (EmitContext ec)
1422                 {
1423                         eclass = ExprClass.Value;
1424
1425                         return this;
1426                 }
1427                 
1428                 public override void Emit (EmitContext ec)
1429                 {
1430                         //
1431                         // Now emit the delegate creation.
1432                         //
1433                         if ((am.Method.ModFlags & Modifiers.STATIC) == 0) {
1434                                 delegate_instance_expression = am.RootScope.GetScopeInitializer (ec);
1435
1436                                 if (delegate_instance_expression == null)
1437                                         throw new InternalErrorException ();
1438                         }
1439
1440                         Expression ml = Expression.MemberLookup (
1441                                 ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
1442                                 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
1443                                 loc);
1444
1445                         constructor_method = ((MethodGroupExpr) ml).Methods [0];
1446                         delegate_method = am.GetMethodBuilder (ec);
1447                         base.Emit (ec);
1448                 }
1449         }
1450 }