Apply Gert's version of the AutoResetEvent, and merge his test
[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 = MakeName (null, "CompilerGenerated");
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                 public static string MakeName (string host, string prefix)
41                 {
42                         return "<" + host + ">c__" + prefix + next_index++;
43                 }
44
45                 protected CompilerGeneratedClass (DeclSpace parent, GenericMethod generic,
46                                                   int mod, Location loc)
47                         : base (parent.NamespaceEntry, parent,
48                                 MakeProxyName (generic, loc), mod | Modifiers.COMPILER_GENERATED, 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.PartialContainer.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 Parameters InflateParameters (Parameters ps)
104                 {
105                         if (generic_method == null)
106                                 return ps;
107
108                         int n = ps.Count;
109                         if (n == 0)
110                                 return ps;
111
112                         Parameter[] inflated_params = new Parameter [n];
113                         Type[] inflated_types = new Type [n];
114
115                         for (int i = 0; i < n; ++i) {
116                                 Parameter p = ps [i];
117                                 Type it = InflateType (p.ExternalType ()).ResolveAsTypeTerminal (this, false).Type;
118                                 inflated_types [i] = it;
119                                 inflated_params [i] = new Parameter (it, p.Name, p.ModFlags, p.OptAttributes, p.Location);
120                         }
121                         return Parameters.CreateFullyResolved (inflated_params, inflated_types);
122                 }
123
124                 public TypeExpr InflateType (Type it)
125                 {
126 #if GMCS_SOURCE
127                         if (generic_method == null)
128                                 return new TypeExpression (it, Location);
129
130                         if (it.IsGenericParameter && (it.DeclaringMethod != null)) {
131                                 int pos = it.GenericParameterPosition;
132                                 it = CurrentTypeParameters [pos].Type;
133                         } else if (it.IsGenericType) {
134                                 Type[] args = it.GetGenericArguments ();
135
136                                 TypeArguments inflated = new TypeArguments (Location);
137                                 foreach (Type t in args)
138                                         inflated.Add (InflateType (t));
139
140                                 return new ConstructedType (it, inflated, Location);
141                         } else if (it.IsArray) {
142                                 TypeExpr et_expr = InflateType (it.GetElementType ());
143                                 int rank = it.GetArrayRank ();
144
145                                 Type et = et_expr.ResolveAsTypeTerminal (this, false).Type;
146                                 it = et.MakeArrayType (rank);
147                         }
148 #endif
149
150                         return new TypeExpression (it, Location);
151                 }
152
153                 public Field CaptureVariable (string name, TypeExpr type)
154                 {
155                         if (members_defined)
156                                 throw new InternalErrorException ("Helper class already defined!");
157                         if (type == null)
158                                 throw new ArgumentNullException ();
159
160                         return new CapturedVariableField (this, name, type);
161                 }
162
163                 bool members_defined;
164
165                 internal void CheckMembersDefined ()
166                 {
167                         if (members_defined)
168                                 throw new InternalErrorException ("Helper class already defined!");
169                 }
170
171                 protected class CapturedVariableField : Field
172                 {
173                         public CapturedVariableField (CompilerGeneratedClass helper, string name,
174                                                       TypeExpr type)
175                                 : base (helper, type, Modifiers.INTERNAL, name, null, helper.Location)
176                         {
177                                 helper.AddField (this);
178                         }
179                 }
180         }
181
182         public class ScopeInfo : CompilerGeneratedClass
183         {
184                 protected readonly RootScopeInfo RootScope;
185                 new public readonly DeclSpace Parent;
186                 public readonly int ID = ++next_id;
187                 public readonly Block ScopeBlock;
188                 protected ScopeInitializer scope_initializer;
189
190                 readonly Hashtable locals = new Hashtable ();
191                 readonly Hashtable captured_scopes = new Hashtable ();
192                 Hashtable captured_params;
193
194                 static int next_id;
195
196                 public static ScopeInfo CreateScope (Block block)
197                 {
198                         ToplevelBlock toplevel = block.Toplevel;
199                         AnonymousContainer ac = toplevel.AnonymousContainer;
200
201                         Report.Debug (128, "CREATE SCOPE", block, block.ScopeInfo, toplevel, ac);
202
203                         if (ac == null)
204                                 return new ScopeInfo (block, toplevel.RootScope.Parent,
205                                                       toplevel.RootScope.GenericMethod);
206
207                         Report.Debug (128, "CREATE SCOPE #1", ac, ac.Host, ac.Scope, ac.Block,
208                                       ac.Container, ac.ContainerAnonymousMethod,
209                                       ac.Location);
210
211                         Block b;
212                         ScopeInfo parent = null;
213
214                         for (b = ac.Block; b != null; b = b.Parent) {
215                                 if (b.ScopeInfo != null) {
216                                         parent = b.ScopeInfo;
217                                         break;
218                                 }
219                         }
220
221                         Report.Debug (128, "CREATE SCOPE #2", parent);
222
223                         ScopeInfo new_scope = new ScopeInfo (block, parent, null);
224
225                         Report.Debug (128, "CREATE SCOPE #3", new_scope);
226
227                         return new_scope;
228                 }
229
230                 private static int default_modflags (DeclSpace parent)
231                 {
232                         return parent is CompilerGeneratedClass ? Modifiers.PUBLIC : Modifiers.PRIVATE;
233                 }
234
235                 protected ScopeInfo (Block block, DeclSpace parent, GenericMethod generic)
236                         : base (parent, generic, default_modflags (parent), block.StartLocation)
237                 {
238                         Parent = parent;
239                         RootScope = block.Toplevel.RootScope;
240                         ScopeBlock = block;
241
242                         Report.Debug (128, "NEW SCOPE", this, block,
243                                       block.Parent, block.Toplevel);
244
245                         RootScope.AddScope (this);
246                 }
247
248                 protected ScopeInfo (ToplevelBlock toplevel, DeclSpace parent,
249                                      GenericMethod generic, Location loc)
250                         : base (parent, generic, default_modflags (parent), loc)
251                 {
252                         Parent = parent;
253                         RootScope = (RootScopeInfo) this;
254                         ScopeBlock = toplevel;
255
256                         Report.Debug (128, "NEW ROOT SCOPE", this, toplevel, loc);
257                 }
258
259                 protected CapturedScope[] CapturedScopes {
260                         get {
261                                 CapturedScope[] list = new CapturedScope [captured_scopes.Count];
262                                 captured_scopes.Values.CopyTo (list, 0);
263                                 return list;
264                         }
265                 }
266
267                 protected CapturedVariable GetCapturedScope (ScopeInfo scope)
268                 {
269                         return (CapturedVariable) captured_scopes [scope];
270                 }
271
272                 protected void EmitScopeInstance (EmitContext ec)
273                 {
274                         if (scope_initializer == null) {
275                                 //
276                                 // This is needed if someone overwrites the Emit method
277                                 // of Statement and manually calls Block.Emit without
278                                 // this snippet first:
279                                 // 
280                                 //   ec.EmitScopeInitFromBlock (The_Block);
281                                 //   The_Block.Emit (ec);
282                                 // 
283                                 throw new InternalErrorException ();
284                         }
285
286                         scope_initializer.Emit (ec);
287                 }
288
289                 public ExpressionStatement GetScopeInitializer (EmitContext ec)
290                 {
291                         Report.Debug (128, "GET SCOPE INITIALIZER",
292                                       this, GetType (), scope_initializer, ScopeBlock);
293
294                         if (scope_initializer == null) {
295                                 scope_initializer = CreateScopeInitializer ();
296                                 if (scope_initializer.Resolve (ec) == null)
297                                         throw new InternalErrorException ();
298                         }
299
300                         return scope_initializer;
301                 }
302
303                 public Type GetScopeType (EmitContext ec)
304                 {
305                         if (!IsGeneric)
306                                 return TypeBuilder;
307
308                         TypeArguments targs = new TypeArguments (Location);
309
310                         if (ec.DeclContainer.Parent.IsGeneric)
311                                 foreach (TypeParameter t in ec.DeclContainer.Parent.TypeParameters)
312                                         targs.Add (new TypeParameterExpr (t, Location));
313                         if (ec.DeclContainer.IsGeneric)
314                                 foreach (TypeParameter t in ec.DeclContainer.CurrentTypeParameters)
315                                         targs.Add (new TypeParameterExpr (t, Location));
316
317                         Report.Debug (128, "GET SCOPE TYPE", this, TypeBuilder, targs,
318                                       ec.DeclContainer, ec.DeclContainer.GetType (),
319                                       ec.DeclContainer.Parent.Name);
320
321                         TypeExpr te = new ConstructedType (TypeBuilder, targs, Location);
322                         te = te.ResolveAsTypeTerminal (ec, false);
323                         if ((te == null) || (te.Type == null))
324                                 return null;
325                         return te.Type;
326                 }
327
328                 protected override bool DoDefineMembers ()
329                 {
330                         Report.Debug (64, "SCOPE INFO DEFINE MEMBERS", this, GetType (), IsGeneric,
331                                       Parent.IsGeneric, GenericMethod);
332
333                         foreach (CapturedScope child in CapturedScopes) {
334                                 if (!child.DefineMembers ())
335                                         return false;
336                         }
337
338                         return base.DoDefineMembers ();
339                 }
340
341                 protected override bool DoResolveMembers ()
342                 {
343                         Report.Debug (64, "SCOPE INFO RESOLVE MEMBERS", this, GetType (), IsGeneric,
344                                       Parent.IsGeneric, GenericMethod);
345
346                         return base.DoResolveMembers ();
347                 }
348
349                 public Variable CaptureScope (ScopeInfo child)
350                 {
351                         CheckMembersDefined ();
352                         Report.Debug (128, "CAPTURE SCOPE", this, GetType (), child, child.GetType ());
353                         if (child == this)
354                                 throw new InternalErrorException ();
355                         CapturedScope captured = (CapturedScope) captured_scopes [child];
356                         if (captured == null) {
357                                 captured = new CapturedScope (this, child);
358                                 captured_scopes.Add (child, captured);
359                         }
360                         return captured;
361                 }
362
363                 public Variable AddLocal (LocalInfo local)
364                 {
365                         Report.Debug (128, "CAPTURE LOCAL", this, local);
366                         Variable var = (Variable) locals [local];
367                         if (var == null) {
368                                 var = new CapturedLocal (this, local);
369                                 locals.Add (local, var);
370                                 local.IsCaptured = true;
371                         }
372                         return var;
373                 }
374
375                 public Variable GetCapturedVariable (LocalInfo local)
376                 {
377                         return (Variable) locals [local];
378                 }
379
380                 public bool HostsParameters {
381                         get { return captured_params != null; }
382                 }
383
384                 public Variable GetCapturedParameter (Parameter par)
385                 {
386                         if (captured_params != null)
387                                 return (Variable) captured_params [par];
388                         else
389                                 return null;
390                 }
391
392                 public Variable AddParameter (Parameter par, int idx)
393                 {
394                         if (captured_params == null)
395                                 captured_params = new Hashtable ();
396
397                         Variable var = (Variable) captured_params [par];
398                         if (var == null) {
399                                 var = new CapturedParameter (this, par, idx);
400                                 captured_params.Add (par, var);
401                                 par.IsCaptured = true;
402                         }
403
404                         return var;
405                 }
406
407                 protected string MakeFieldName (string local_name)
408                 {
409                         return "<" + ID + ":" + local_name + ">";
410                 }
411
412                 protected virtual ScopeInitializer CreateScopeInitializer ()
413                 {
414                         return new ScopeInitializer (this);
415                 }
416
417                 protected abstract class CapturedVariable : Variable
418                 {
419                         public readonly ScopeInfo Scope;
420                         public readonly string Name;
421
422                         public FieldExpr FieldInstance;
423                         protected Field field;
424
425                         protected CapturedVariable (ScopeInfo scope, string name)
426                         {
427                                 this.Scope = scope;
428                                 this.Name = name;
429                         }
430
431                         protected CapturedVariable (ScopeInfo scope, string name, Type type)
432                                 : this (scope, name)
433                         {
434                                 this.field = scope.CaptureVariable (
435                                         scope.MakeFieldName (name), scope.RootScope.InflateType (type));
436                         }
437
438                         public Field Field {
439                                 get { return field; }
440                         }
441
442                         public override Type Type {
443                                 get { return Field.MemberType; }
444                         }
445
446                         public override bool HasInstance {
447                                 get { return true; }
448                         }
449
450                         public override bool NeedsTemporary {
451                                 get { return true; }
452                         }
453
454                         protected FieldInfo GetField (EmitContext ec)
455                         {
456                                 if ((ec.CurrentBlock != null) &&
457                                     (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel))
458                                         return Field.FieldBuilder;
459                                 else
460                                         return FieldInstance.FieldInfo;
461                         }
462
463                         public override void EmitInstance (EmitContext ec)
464                         {
465                                 if ((ec.CurrentAnonymousMethod != null) &&
466                                     (ec.CurrentAnonymousMethod.Scope == Scope)) {
467                                         ec.ig.Emit (OpCodes.Ldarg_0);
468                                         return;
469                                 }
470
471                                 Scope.EmitScopeInstance (ec);
472                         }
473
474                         public override void Emit (EmitContext ec)
475                         {
476                                 ec.ig.Emit (OpCodes.Ldfld, GetField (ec));
477                         }
478
479                         public override void EmitAssign (EmitContext ec)
480                         {
481                                 ec.ig.Emit (OpCodes.Stfld, GetField (ec));
482                         }
483
484                         public override void EmitAddressOf (EmitContext ec)
485                         {
486                                 ec.ig.Emit (OpCodes.Ldflda, GetField (ec));
487                         }
488                 }
489
490                 protected class CapturedParameter : CapturedVariable {
491                         public readonly Parameter Parameter;
492                         public readonly int Idx;
493
494                         public CapturedParameter (ScopeInfo scope, Parameter par, int idx)
495                                 : base (scope, par.Name, par.ParameterType)
496                         {
497                                 this.Parameter = par;
498                                 this.Idx = idx;
499                         }
500
501                         public override string ToString ()
502                         {
503                                 return String.Format ("{0} ({1}:{2}:{3})", GetType (), Field,
504                                                       Parameter.Name, Idx);
505                         }
506                 }
507
508                 protected class CapturedLocal : CapturedVariable {
509                         public readonly LocalInfo Local;
510
511                         public CapturedLocal (ScopeInfo scope, LocalInfo local)
512                                 : base (scope, local.Name, local.VariableType)
513                         {
514                                 this.Local = local;
515                         }
516
517                         public override string ToString ()
518                         {
519                                 return String.Format ("{0} ({1}:{2})", GetType (), Field,
520                                                       Local.Name);
521                         }
522                 }
523
524                 protected class CapturedThis : CapturedVariable {
525                         public CapturedThis (RootScopeInfo host)
526                                 : base (host, "<>THIS", host.ParentType)
527                         { }
528                 }
529
530                 protected class CapturedScope : CapturedVariable {
531                         public readonly ScopeInfo ChildScope;
532
533                         public CapturedScope (ScopeInfo root, ScopeInfo child)
534                                 : base (root, "scope" + child.ID)
535                         {
536                                 this.ChildScope = child;
537                         }
538
539                         public bool DefineMembers ()
540                         {
541                                 Type type = ChildScope.IsGeneric ?
542                                         ChildScope.CurrentType : ChildScope.TypeBuilder;
543                                 Report.Debug (128, "CAPTURED SCOPE DEFINE MEMBERS", this, Scope,
544                                               ChildScope, Name, type);
545                                 if (type == null)
546                                         throw new InternalErrorException ();
547                                 field = Scope.CaptureVariable (
548                                         Scope.MakeFieldName (Name), Scope.InflateType (type));
549                                 return true;
550                         }
551
552                         public override string ToString ()
553                         {
554                                 return String.Format ("CapturedScope ({1} captured in {0})",
555                                                       Scope, ChildScope);
556                         }
557                 }
558
559                 static void DoPath (StringBuilder sb, ScopeInfo start)
560                 {
561                         sb.Append ((start.ID).ToString ());
562                 }
563                 
564                 public override string ToString ()
565                 {
566                         StringBuilder sb = new StringBuilder ();
567                         
568                         sb.Append ("{");
569                         DoPath (sb, this);
570                         sb.Append ("}");
571
572                         return sb.ToString ();
573                 }
574
575                 protected class ScopeInitializer : ExpressionStatement
576                 {
577                         ScopeInfo scope;
578                         CapturedVariable captured_scope;
579                         LocalBuilder scope_instance;
580                         ConstructorInfo scope_ctor;
581
582                         bool initialized;
583
584                         public ScopeInitializer (ScopeInfo scope)
585                         {
586                                 this.scope = scope;
587                                 this.loc = scope.Location;
588                                 eclass = ExprClass.Value;
589                         }
590
591                         public ScopeInfo Scope {
592                                 get { return scope; }
593                         }
594
595                         public override Expression DoResolve (EmitContext ec)
596                         {
597                                 if (scope_ctor != null)
598                                         return this;
599
600                                 Report.Debug (64, "RESOLVE SCOPE INITIALIZER BASE", this, Scope,
601                                               ec, ec.CurrentBlock);
602
603                                 type = Scope.GetScopeType (ec);
604                                 if (type == null)
605                                         throw new InternalErrorException ();
606
607                                 if (!DoResolveInternal (ec))
608                                         throw new InternalErrorException ();
609
610                                 return this;
611                         }
612
613                         protected virtual bool DoResolveInternal (EmitContext ec)
614                         {
615                                 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookupFinal (
616                                         ec, ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
617                                         AllBindingFlags | BindingFlags.DeclaredOnly, loc);
618                                 if (mg == null)
619                                         throw new InternalErrorException ();
620
621                                 scope_ctor = (ConstructorInfo) mg.Methods [0];
622
623                                 Report.Debug (128, "RESOLVE THE INIT", this, Scope, Scope.RootScope,
624                                               Scope.RootScope.GetType ());
625
626                                 ScopeInfo host = Scope.RootScope;
627                                 if ((Scope != host) && (Scope.RootScope is IteratorHost)) {
628                                         captured_scope = host.GetCapturedScope (Scope);
629                                         Type root = host.GetScopeType (ec);
630                                         FieldExpr fe = (FieldExpr) Expression.MemberLookup (
631                                                 type, root, captured_scope.Field.Name, loc);
632                                         if (fe == null)
633                                                 throw new InternalErrorException ();
634
635                                         fe.InstanceExpression = this;
636                                         captured_scope.FieldInstance = fe;
637
638                                         Report.Debug (128, "RESOLVE THE INIT #1", this,
639                                                       captured_scope, fe);
640                                 } else
641                                         scope_instance = ec.ig.DeclareLocal (type);
642
643                                 foreach (CapturedLocal local in Scope.locals.Values) {
644                                         FieldExpr fe = (FieldExpr) Expression.MemberLookup (
645                                                 ec.ContainerType, type, local.Field.Name, loc);
646                                         Report.Debug (64, "RESOLVE SCOPE INITIALIZER #2", this, Scope,
647                                                       Scope, ec, ec.ContainerType, type,
648                                                       local.Field, local.Field.Name, loc, fe);
649                                         if (fe == null)
650                                                 throw new InternalErrorException ();
651
652                                         fe.InstanceExpression = this;
653                                         local.FieldInstance = fe;
654                                 }
655
656                                 if (Scope.HostsParameters) {
657                                         foreach (CapturedParameter cp in Scope.captured_params.Values) {
658                                                 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
659                                                         ec.ContainerType, type, cp.Field.Name, loc);
660                                                 if (fe == null)
661                                                         throw new InternalErrorException ();
662
663                                                 fe.InstanceExpression = this;
664                                                 cp.FieldInstance = fe;
665                                         }
666                                 }
667
668                                 foreach (CapturedScope scope in Scope.CapturedScopes) {
669                                         FieldExpr fe = (FieldExpr) Expression.MemberLookup (
670                                                 ec.ContainerType, type, scope.Field.Name, loc);
671                                         Report.Debug (64, "RESOLVE SCOPE INITIALIZER #3", this, Scope,
672                                                       scope, ec, ec.ContainerType, type,
673                                                       scope.Field, scope.Field.Name, loc, fe);
674                                         if (fe == null)
675                                                 throw new InternalErrorException ();
676
677                                         fe.InstanceExpression = this;
678                                         scope.FieldInstance = fe;
679                                 }
680
681                                 return true;
682                         }
683
684                         protected virtual void EmitParameterReference (EmitContext ec,
685                                                                        CapturedParameter cp)
686                         {
687                                 int extra = ec.MethodIsStatic ? 0 : 1;
688                                 ParameterReference.EmitLdArg (ec.ig, cp.Idx + extra);
689                         }
690
691                         static int next_id;
692                         int id = ++next_id;
693
694                         protected virtual void DoEmit (EmitContext ec)
695                         {
696                                 if ((ec.CurrentBlock != null) &&
697                                     (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel)) {
698                                         ec.ig.Emit (OpCodes.Ldarg_0);
699
700                                         if (ec.CurrentAnonymousMethod != null) {
701                                                 ScopeInfo host = ec.CurrentAnonymousMethod.Scope;
702                                                 Variable captured = host.GetCapturedScope (scope);
703                                                 Report.Debug (128, "EMIT SCOPE INSTANCE #2",
704                                                               ec.CurrentAnonymousMethod, host,
705                                                               scope, captured);
706                                                 if (captured != null)
707                                                         captured.Emit (ec);
708                                         }
709                                 } else if (scope_instance != null)
710                                         ec.ig.Emit (OpCodes.Ldloc, scope_instance);
711                                 else {
712                                         Report.Debug (128, "DO EMIT", this, Scope, ec,
713                                                       scope_instance, captured_scope);
714                                         captured_scope.EmitInstance (ec);
715                                         captured_scope.Emit (ec);
716                                 }
717                         }
718
719                         protected void DoEmitInstance (EmitContext ec)
720                         {
721                                 Report.Debug (128, "DO EMIT INSTANCE", this, Scope, ec,
722                                               scope_instance, captured_scope);
723
724                                 if (scope_instance != null)
725                                         ec.ig.Emit (OpCodes.Ldloc, scope_instance);
726                                 else
727                                         captured_scope.EmitInstance (ec);
728                         }
729
730                         protected virtual void EmitScopeConstructor (EmitContext ec)
731                         {
732                                 ec.ig.Emit (OpCodes.Newobj, scope_ctor);
733                         }
734
735                         public override void Emit (EmitContext ec)
736                         {
737                                 if (!initialized)
738                                         throw new InternalErrorException (
739                                                 "Scope {0} not initialized yet", scope);
740
741                                 DoEmit (ec);
742                         }
743
744                         public override void EmitStatement (EmitContext ec)
745                         {
746                                 if (initialized)
747                                         return;
748
749                                 DoEmitStatement (ec);
750                                 initialized = true;
751                         }
752
753                         protected virtual void DoEmitStatement (EmitContext ec)
754                         {
755                                 Report.Debug (128, "EMIT SCOPE INITIALIZER STATEMENT", this, id,
756                                               Scope, scope_instance, ec);
757
758                                 ec.ig.Emit (OpCodes.Nop);
759                                 ec.ig.Emit (OpCodes.Ldc_I4, id);
760                                 ec.ig.Emit (OpCodes.Pop);
761                                 ec.ig.Emit (OpCodes.Nop);
762
763                                 if (scope_instance == null)
764                                         ec.ig.Emit (OpCodes.Ldarg_0);
765                                 EmitScopeConstructor (ec);
766                                 if (scope_instance != null)
767                                         ec.ig.Emit (OpCodes.Stloc, scope_instance);
768                                 else
769                                         captured_scope.EmitAssign (ec);
770
771                                 if (Scope.HostsParameters) {
772                                         foreach (CapturedParameter cp in Scope.captured_params.Values) {
773                                                 Report.Debug (128, "EMIT SCOPE INIT #6", this,
774                                                               ec, ec.IsStatic, Scope, cp, cp.Field.Name);
775                                                 DoEmitInstance (ec);
776                                                 EmitParameterReference (ec, cp);
777                                                 ec.ig.Emit (OpCodes.Stfld, cp.FieldInstance.FieldInfo);
778                                         }
779                                 }
780
781                                 if (Scope is IteratorHost)
782                                         return;
783
784                                 foreach (CapturedScope scope in Scope.CapturedScopes) {
785                                         ScopeInfo child = scope.ChildScope;
786
787                                         Report.Debug (128, "EMIT SCOPE INIT #5", this, Scope,
788                                                       scope.Scope, scope.ChildScope);
789
790                                         ExpressionStatement init = child.GetScopeInitializer (ec);
791                                         init.EmitStatement (ec);
792
793                                         DoEmit (ec);
794                                         scope.ChildScope.EmitScopeInstance (ec);
795                                         scope.EmitAssign (ec);
796                                 }
797                         }
798                 }
799         }
800
801         public class RootScopeInfo : ScopeInfo
802         {
803                 public RootScopeInfo (ToplevelBlock toplevel, DeclSpace parent,
804                                       GenericMethod generic, Location loc)
805                         : base (toplevel, parent, generic, loc)
806                 {
807                         scopes = new ArrayList ();
808                 }
809
810                 TypeExpr parent_type;
811                 CapturedVariableField parent_link;
812                 CapturedThis this_variable;
813                 protected ArrayList scopes;
814
815                 public virtual bool IsIterator {
816                         get { return false; }
817                 }
818
819                 public RootScopeInfo ParentHost {
820                         get { return Parent.PartialContainer as RootScopeInfo; }
821                 }
822
823                 public Type ParentType {
824                         get { return parent_type.Type; }
825                 }
826
827                 public Field ParentLink {
828                         get { return parent_link; }
829                 }
830
831                 protected CapturedThis THIS {
832                         get { return this_variable; }
833                 }
834
835                 public Variable CaptureThis ()
836                 {
837                         if (ParentHost != null)
838                                 return ParentHost.CaptureThis ();
839
840                         CheckMembersDefined ();
841                         if (this_variable == null)
842                                 this_variable = new CapturedThis (this);
843                         return this_variable;
844                 }
845
846                 public void AddScope (ScopeInfo scope)
847                 {
848                         scopes.Add (scope);
849                 }
850
851                 bool linked;
852                 public void LinkScopes ()
853                 {
854                         Report.Debug (128, "LINK SCOPES", this, linked, scopes);
855
856                         if (linked)
857                                 return;
858
859                         linked = true;
860                         if (ParentHost != null)
861                                 ParentHost.LinkScopes ();
862
863                         foreach (ScopeInfo si in scopes) {
864                                 if (!si.Define ())
865                                         throw new InternalErrorException ();
866                                 if (si.DefineType () == null)
867                                         throw new InternalErrorException ();
868                                 if (!si.ResolveType ())
869                                         throw new InternalErrorException ();
870                         }
871
872                         foreach (ScopeInfo si in scopes) {
873                                 if (!si.ResolveMembers ())
874                                         throw new InternalErrorException ();
875                                 if (!si.DefineMembers ())
876                                         throw new InternalErrorException ();
877                         }
878                 }
879
880                 protected override ScopeInitializer CreateScopeInitializer ()
881                 {
882                         return new RootScopeInitializer (this);
883                 }
884
885                 protected override bool DefineNestedTypes ()
886                 {
887                         if (Parent.IsGeneric) {
888                                 parent_type = new ConstructedType (
889                                         Parent.TypeBuilder, Parent.TypeParameters, Location);
890                                 parent_type = parent_type.ResolveAsTypeTerminal (this, false);
891                                 if ((parent_type == null) || (parent_type.Type == null))
892                                         return false;
893                         } else {
894                                 parent_type = new TypeExpression (Parent.TypeBuilder, Location);
895                         }
896
897                         CompilerGeneratedClass parent = Parent.PartialContainer as CompilerGeneratedClass;
898                         if (parent != null)
899                                 parent_link = new CapturedVariableField (this, "<>parent", parent_type);
900
901                         return base.DefineNestedTypes ();
902                 }
903
904                 protected override bool DoDefineMembers ()
905                 {
906                         ArrayList args = new ArrayList ();
907                         if (this is IteratorHost)
908                                 args.Add (new Parameter (
909                                         TypeManager.int32_type, "$PC", Parameter.Modifier.NONE,
910                                         null, Location));
911
912                         Field pfield;
913                         if (Parent is CompilerGeneratedClass)
914                                 pfield = parent_link;
915                         else
916                                 pfield = this_variable !=  null ? this_variable.Field : null;
917                         if (pfield != null)
918                                 args.Add (new Parameter (
919                                         pfield.MemberType, "parent", Parameter.Modifier.NONE,
920                                         null, Location));
921
922                         Parameter[] ctor_params = new Parameter [args.Count];
923                         args.CopyTo (ctor_params, 0);
924                         Constructor ctor = new Constructor (
925                                 this, MemberName.Name, Modifiers.PUBLIC,
926                                 new Parameters (ctor_params),
927                                 new GeneratedBaseInitializer (Location),
928                                 Location);
929                         AddConstructor (ctor);
930
931                         ctor.Block = new ToplevelBlock (null, Location);
932                         ctor.Block.AddStatement (new TheCtor (this));
933
934                         return base.DoDefineMembers ();
935                 }
936
937                 protected virtual void EmitScopeConstructor (EmitContext ec)
938                 {
939                         int pos = (this is IteratorHost) ? 2 : 1;
940
941                         Field pfield;
942                         if (Parent is CompilerGeneratedClass)
943                                 pfield = parent_link;
944                         else
945                                 pfield = this_variable !=  null ? this_variable.Field : null;
946
947                         if (pfield != null) {
948                                 ec.ig.Emit (OpCodes.Ldarg_0);
949                                 ec.ig.Emit (OpCodes.Ldarg, pos);
950                                 ec.ig.Emit (OpCodes.Stfld, pfield.FieldBuilder);
951                                 pos++;
952                         }
953                 }
954
955                 protected class TheCtor : Statement
956                 {
957                         RootScopeInfo host;
958
959                         public TheCtor (RootScopeInfo host)
960                         {
961                                 this.host = host;
962                         }
963
964                         public override bool Resolve (EmitContext ec)
965                         {
966                                 return true;
967                         }
968
969                         protected override void DoEmit (EmitContext ec)
970                         {
971                                 host.EmitScopeConstructor (ec);
972                         }
973                 }
974
975                 protected class RootScopeInitializer : ScopeInitializer
976                 {
977                         RootScopeInfo host;
978
979                         public RootScopeInitializer (RootScopeInfo host)
980                                 : base (host)
981                         {
982                                 this.host = host;
983                         }
984
985                         public RootScopeInfo Host {
986                                 get { return host; }
987                         }
988
989                         protected override bool DoResolveInternal (EmitContext ec)
990                         {
991                                 Report.Debug (64, "RESOLVE ANONYMOUS METHOD HOST INITIALIZER",
992                                               this, Host, Host.ParentType, loc);
993
994                                 if (Host.THIS != null) {
995                                         FieldExpr fe = (FieldExpr) Expression.MemberLookup (
996                                                 ec.ContainerType, type, Host.THIS.Field.Name, loc);
997                                         if (fe == null)
998                                                 throw new InternalErrorException ();
999
1000                                         fe.InstanceExpression = this;
1001                                         Host.THIS.FieldInstance = fe;
1002                                 }
1003
1004                                 return base.DoResolveInternal (ec);
1005                         }
1006
1007                         protected virtual bool IsGetEnumerator {
1008                                 get { return false; }
1009                         }
1010
1011                         protected override void EmitScopeConstructor (EmitContext ec)
1012                         {
1013                                 if (host.THIS != null) {
1014                                         ec.ig.Emit (OpCodes.Ldarg_0);
1015                                         if (IsGetEnumerator)
1016                                                 ec.ig.Emit (OpCodes.Ldfld, host.THIS.Field.FieldBuilder);
1017                                         else if (host.THIS.Type.IsValueType)
1018                                                 Expression.LoadFromPtr (ec.ig, host.THIS.Type);
1019                                 } else if (host.ParentLink != null)
1020                                         ec.ig.Emit (OpCodes.Ldarg_0);
1021
1022                                 base.EmitScopeConstructor (ec);
1023                         }
1024                 }
1025
1026         }
1027
1028         public interface IAnonymousContainer
1029         {
1030                 Block Container {
1031                         get;
1032                 }
1033
1034                 GenericMethod GenericMethod {
1035                         get;
1036                 }
1037
1038                 RootScopeInfo RootScope {
1039                         get;
1040                 }
1041
1042                 bool IsIterator {
1043                         get;
1044                 }
1045         }
1046
1047         public interface IAnonymousHost
1048         {
1049                 //
1050                 // Invoked if a yield statement is found in the body
1051                 //
1052                 void SetYields ();
1053
1054                 //
1055                 // Invoked if an anonymous method is found in the body
1056                 //
1057                 void AddAnonymousMethod (AnonymousMethodExpression anonymous);
1058         }
1059
1060         public class AnonymousMethodExpression : Expression, IAnonymousContainer, IAnonymousHost
1061         {
1062                 public readonly AnonymousMethodExpression Parent;
1063                 public readonly TypeContainer Host;
1064                 public readonly Parameters Parameters;
1065
1066                 public ToplevelBlock Block;
1067                 protected AnonymousMethod anonymous;
1068
1069                 protected Block container;
1070                 protected readonly GenericMethod generic;
1071
1072                 public Block Container {
1073                         get { return container; }
1074                 }
1075
1076                 public GenericMethod GenericMethod {
1077                         get { return generic; }
1078                 }
1079
1080                 public AnonymousMethod AnonymousMethod {
1081                         get { return anonymous; }
1082                 }
1083
1084                 public RootScopeInfo RootScope {
1085                         get { return root_scope; }
1086                 }
1087
1088                 public AnonymousMethodExpression (AnonymousMethodExpression parent,
1089                                                   GenericMethod generic, TypeContainer host,
1090                                                   Parameters parameters, Block container,
1091                                                   Location loc)
1092                 {
1093                         this.Parent = parent;
1094                         this.generic = parent != null ? null : generic;
1095                         this.Host = host;
1096                         this.Parameters = parameters;
1097                         this.container = container;
1098                         this.loc = loc;
1099
1100                         Report.Debug (64, "NEW ANONYMOUS METHOD EXPRESSION", this, parent, host,
1101                                       container, loc);
1102
1103                         if (parent != null)
1104                                 parent.AddAnonymousMethod (this);
1105                 }
1106
1107                 ArrayList children;
1108                 RootScopeInfo root_scope;
1109
1110                 static int next_index;
1111
1112                 void IAnonymousHost.SetYields ()
1113                 {
1114                         throw new InvalidOperationException ();
1115                 }
1116
1117                 public void AddAnonymousMethod (AnonymousMethodExpression anonymous)
1118                 {
1119                         if (children == null)
1120                                 children = new ArrayList ();
1121                         children.Add (anonymous);
1122                 }
1123
1124                 public bool CreateAnonymousHelpers ()
1125                 {
1126                         Report.Debug (64, "ANONYMOUS METHOD EXPRESSION CREATE ROOT SCOPE",
1127                                       this, Host, container, loc);
1128
1129                         if (container != null)
1130                                 root_scope = container.Toplevel.CreateRootScope (Host);
1131
1132                         if (children != null) {
1133                                 foreach (AnonymousMethodExpression child in children) {
1134                                         if (!child.CreateAnonymousHelpers ())
1135                                                 return false;
1136                                 }
1137                         }
1138
1139                         return true;
1140                 }
1141
1142                 public override string ExprClassName {
1143                         get {
1144                                 return "anonymous method";
1145                         }
1146                 }
1147
1148                 public virtual bool HasExplicitParameters {
1149                         get {
1150                                 return true;
1151                         }
1152                 }
1153
1154                 public virtual bool ImplicitStandardConversionExists (Type delegate_type)
1155                 {
1156                         if (Parameters == null)
1157                                 return true;
1158
1159                         MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
1160                                 Host.TypeBuilder, delegate_type, loc);
1161                         MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
1162                         ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
1163
1164                         if (Parameters.Count != invoke_pd.Count)
1165                                 return false;
1166
1167                         for (int i = 0; i < Parameters.Count; ++i) {
1168                                 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i))
1169                                         return false;
1170                         }
1171                         return true;
1172                 }
1173
1174                 protected Expression CompatibleChecks (EmitContext ec, Type delegate_type)
1175                 {
1176                         if (!ec.IsAnonymousMethodAllowed) {
1177                                 Report.Error (1706, loc,
1178                                               "Anonymous methods are not allowed in the " +
1179                                               "attribute declaration");
1180                                 return null;
1181                         }
1182                         
1183                         if (!TypeManager.IsDelegateType (delegate_type)){
1184                                 Report.Error (1660, loc,
1185                                               "Cannot convert anonymous method block to type " +
1186                                               "`{0}' because it is not a delegate type",
1187                                               TypeManager.CSharpName (delegate_type));
1188                                 return null;
1189                         }
1190                         return this;
1191                 }
1192
1193                 protected bool VerifyParameterCompatibility (Type delegate_type, ParameterData invoke_pd, bool showErrors)
1194                 {
1195                         if (Parameters.Count != invoke_pd.Count) {
1196                                 if (!showErrors)
1197                                         return false;
1198                                 
1199                                 Report.SymbolRelatedToPreviousError (delegate_type);
1200                                 Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
1201                                               TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
1202                                 return false;
1203                         }
1204
1205                         if (!HasExplicitParameters)
1206                                 return true;
1207
1208                         bool error = false;
1209                         for (int i = 0; i < Parameters.Count; ++i) {
1210                                 Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
1211                                 if (Parameters.ParameterModifier (i) != p_mod && p_mod != Parameter.Modifier.PARAMS) {
1212                                         if (!showErrors)
1213                                                 return false;
1214                                         
1215                                         if (p_mod == Parameter.Modifier.NONE)
1216                                                 Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
1217                                                               (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.ParameterModifier (i)));
1218                                         else
1219                                                 Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
1220                                                               (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
1221                                         error = true;
1222                                         continue;
1223                                 }
1224
1225                                 // We assume that generic parameters are always inflated
1226                                 if (TypeManager.IsGenericParameter (invoke_pd.Types[i]))
1227                                         continue;
1228                                 
1229                                 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i)) {
1230                                         if (!showErrors)
1231                                                 return false;
1232                                         
1233                                         Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
1234                                                       (i+1).ToString (),
1235                                                       TypeManager.CSharpName (Parameters.ParameterType (i)),
1236                                                       TypeManager.CSharpName (invoke_pd.ParameterType (i)));
1237                                         error = true;
1238                                 }
1239                         }
1240
1241                         return !error;
1242                 }
1243
1244 #if GMCS_SOURCE         
1245                 // TODO: Merge with lambda DoCompatibleTest
1246                 // TODO: Need to sort out error reporting
1247                 public Expression InferTypeArguments (EmitContext ec, Type delegateType)
1248                 {
1249                         if (anonymous != null)
1250                                 return anonymous.AnonymousDelegate;
1251
1252                         if (!delegateType.ContainsGenericParameters)
1253                                 throw new InternalErrorException ("No inference required");
1254
1255                         // It looks like we cannot generate arguments during type inference
1256                         if (Parameters == null)
1257                                 return null;
1258
1259                         delegateType = delegateType.GetGenericTypeDefinition ();
1260                         
1261                         MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
1262                                 ec.ContainerType, delegateType, loc);
1263                         MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
1264                         ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);                     
1265
1266                         if (!VerifyParameterCompatibility (delegateType, invoke_pd, false))
1267                                 return null;
1268
1269                         Type[] g_arguments = delegateType.GetGenericArguments ();
1270                         Type[] inferred_arguments = new Type [g_arguments.Length];
1271                         g_arguments.CopyTo (inferred_arguments, 0);
1272
1273                         for (int i = 0; i < invoke_pd.Count; ++i) {
1274                                 if (!invoke_pd.Types[i].IsGenericParameter)
1275                                         continue;
1276
1277                                 inferred_arguments [invoke_pd.Types[i].GenericParameterPosition] = Parameters.Types[i];
1278                         }
1279
1280                         int return_type_pos = -1;
1281                         if (TypeManager.IsGenericParameter (invoke_mb.ReturnType)) {
1282                                         ec.InferReturnType = true;
1283                                 return_type_pos = invoke_mb.ReturnType.GenericParameterPosition;
1284                         }
1285
1286                         anonymous = new AnonymousMethod (
1287                                 Parent != null ? Parent.AnonymousMethod : null, RootScope, Host,
1288                                 GenericMethod, Parameters, Container, Block, invoke_mb.ReturnType,
1289                                 delegateType, loc);
1290
1291                         if (!anonymous.Resolve (ec))
1292                                 return null;
1293
1294                         if (return_type_pos != -1) {
1295                                 inferred_arguments [return_type_pos] = anonymous.ReturnType;
1296                         }
1297
1298                         anonymous.AnonymousDelegate.Type = delegateType.GetGenericTypeDefinition ().MakeGenericType (inferred_arguments);
1299                         anonymous.DelegateType = anonymous.AnonymousDelegate.Type;
1300                         
1301                         return anonymous.AnonymousDelegate;
1302                 }
1303 #endif
1304                 
1305                 //
1306                 // Returns true if this anonymous method can be implicitly
1307                 // converted to the delegate type `delegate_type'
1308                 //
1309                 public virtual Expression Compatible (EmitContext ec, Type delegate_type)
1310                 {
1311                         if (anonymous != null)
1312                                 return anonymous.AnonymousDelegate;
1313                         
1314                         if (CompatibleChecks (ec, delegate_type) == null)
1315                                 return null;
1316
1317                         //
1318                         // At this point its the first time we know the return type that is 
1319                         // needed for the anonymous method.  We create the method here.
1320                         //
1321
1322                         MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
1323                                 ec.ContainerType, delegate_type, loc);
1324                         MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
1325                         ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
1326
1327                         Parameters parameters = CreateParameters (ec, delegate_type, invoke_pd);
1328                         if (parameters == null)
1329                                 return null;
1330
1331                         //
1332                         // Second: the return type of the delegate must be compatible with 
1333                         // the anonymous type.   Instead of doing a pass to examine the block
1334                         // we satisfy the rule by setting the return type on the EmitContext
1335                         // to be the delegate type return type.
1336                         //
1337
1338                         //MethodBuilder builder = method_data.MethodBuilder;
1339                         //ILGenerator ig = builder.GetILGenerator ();
1340
1341                         Report.Debug (64, "COMPATIBLE", this, Parent, GenericMethod, Host,
1342                                       Container, Block, invoke_mb.ReturnType, delegate_type,
1343                                       TypeManager.IsGenericType (delegate_type), loc);
1344
1345                         return ResolveMethod (ec, parameters, invoke_mb.ReturnType, delegate_type);
1346                 }
1347
1348                 protected virtual Parameters CreateParameters (EmitContext ec, Type delegateType, ParameterData delegateParameters)
1349                 {
1350                         if (Parameters == null) {
1351                                 //
1352                                 // We provide a set of inaccessible parameters
1353                                 //
1354                                 Parameter[] fixedpars = new Parameter[delegateParameters.Count];
1355
1356                                 for (int i = 0; i < delegateParameters.Count; i++) {
1357                                         Parameter.Modifier i_mod = delegateParameters.ParameterModifier (i);
1358                                         if ((i_mod & Parameter.Modifier.OUTMASK) != 0) {
1359                                                 Report.Error (1688, loc, "Cannot convert anonymous " +
1360                                                                   "method block without a parameter list " +
1361                                                                   "to delegate type `{0}' because it has " +
1362                                                                   "one or more `out' parameters.",
1363                                                                   TypeManager.CSharpName (delegateType));
1364                                                 return null;
1365                                         }
1366                                         fixedpars[i] = new Parameter (
1367                                                 delegateParameters.ParameterType (i), "+" + (++next_index),
1368                                                 delegateParameters.ParameterModifier (i), null, loc);
1369                                 }
1370
1371                                 Parameters parameters = new Parameters (fixedpars);
1372                                 if (!parameters.Resolve (ec))
1373                                         return null;
1374                                 return parameters;
1375                         }
1376
1377                         if (!VerifyParameterCompatibility (delegateType, delegateParameters, true)) {
1378                                 Report.Error (1661, loc,
1379                                         "Cannot convert `{0}' to delegate type `{1}' since there is a parameter mismatch",
1380                                         GetSignatureForError (), TypeManager.CSharpName (delegateType));
1381                                 return null;
1382                         }
1383
1384                         return Parameters;
1385                 }
1386
1387                 public override Expression DoResolve (EmitContext ec)
1388                 {
1389                         //
1390                         // Set class type, set type
1391                         //
1392
1393                         eclass = ExprClass.Value;
1394
1395                         //
1396                         // This hack means `The type is not accessible
1397                         // anywhere', we depend on special conversion
1398                         // rules.
1399                         // 
1400                         type = TypeManager.anonymous_method_type;
1401
1402                         if ((Parameters != null) && !Parameters.Resolve (ec))
1403                                 return null;
1404
1405                         return this;
1406                 }
1407
1408                 public override void Emit (EmitContext ec)
1409                 {
1410                         // nothing, as we only exist to not do anything.
1411                 }
1412
1413                 public override string GetSignatureForError ()
1414                 {
1415                         return ExprClassName;
1416                 }
1417
1418                 public bool IsIterator {
1419                         get { return false; }
1420                 }
1421
1422                 protected virtual Expression ResolveMethod (EmitContext ec, Parameters parameters, Type returnType, Type delegateType)
1423                 {
1424                         anonymous = new AnonymousMethod (
1425                                 Parent != null ? Parent.AnonymousMethod : null, RootScope, Host,
1426                                 GenericMethod, parameters, Container, Block, returnType,
1427                                 delegateType, loc);
1428
1429                         if (!anonymous.Resolve (ec))
1430                                 return null;
1431
1432                         return anonymous.AnonymousDelegate;
1433                 }
1434
1435                 protected override void CloneTo (CloneContext clonectx, Expression t)
1436                 {
1437                         AnonymousMethodExpression target = (AnonymousMethodExpression) t;
1438
1439                         target.Block = (ToplevelBlock) clonectx.LookupBlock (Block);
1440                         target.container = clonectx.LookupBlock (Block);
1441                 }
1442         }
1443
1444         public abstract class AnonymousContainer : IAnonymousContainer
1445         {
1446                 public readonly Location Location;
1447
1448                 public Parameters Parameters;
1449
1450                 //
1451                 // The block that makes up the body for the anonymous mehtod
1452                 //
1453                 public readonly ToplevelBlock Block;
1454
1455                 public readonly int ModFlags;
1456                 public Type ReturnType;
1457                 public readonly DeclSpace Host;
1458
1459                 //
1460                 // The implicit method we create
1461                 //
1462                 protected Method method;
1463                 protected EmitContext aec;
1464
1465                 // The emit context for the anonymous method
1466                 protected bool unreachable;
1467                 protected readonly Block container;
1468                 protected readonly GenericMethod generic;
1469
1470                 //
1471                 // Points to our container anonymous method if its present
1472                 //
1473                 public readonly AnonymousContainer ContainerAnonymousMethod;
1474
1475                 protected AnonymousContainer (AnonymousContainer parent, DeclSpace host,
1476                                               GenericMethod generic, Parameters parameters,
1477                                               Block container, ToplevelBlock block,
1478                                               Type return_type, int mod, Location loc)
1479                 {
1480                         this.ContainerAnonymousMethod = parent;
1481                         this.ReturnType = return_type;
1482                         this.ModFlags = mod | Modifiers.COMPILER_GENERATED;
1483                         this.Host = host;
1484
1485                         this.container = container;
1486                         this.generic = parent != null ? null : generic;
1487                         this.Parameters = parameters;
1488                         this.Block = block;
1489                         this.Location = loc;
1490
1491                         block.AnonymousContainer = this;
1492                 }
1493
1494                 public Method Method {
1495                         get { return method; }
1496                 }
1497
1498                 public abstract string ContainerType {
1499                         get; 
1500                 }
1501
1502                 public abstract RootScopeInfo RootScope {
1503                         get;
1504                 }
1505
1506                 public abstract ScopeInfo Scope {
1507                         get;
1508                 }
1509
1510                 public abstract string GetSignatureForError ();
1511
1512                 public virtual bool ResolveNoDefine (EmitContext ec)
1513                 {
1514                         Report.Debug (64, "RESOLVE ANONYMOUS METHOD", this, Location, ec,
1515                                       RootScope, Parameters, ec.IsStatic);
1516
1517                         if (ReturnType != null) {
1518                                 TypeExpr return_type_expr;
1519                                 if (RootScope != null)
1520                                         return_type_expr = RootScope.InflateType (ReturnType);
1521                                 else
1522                                         return_type_expr = new TypeExpression (ReturnType, Location);
1523                                 return_type_expr = return_type_expr.ResolveAsTypeTerminal (ec, false);
1524                                 if ((return_type_expr == null) || (return_type_expr.Type == null))
1525                                         return false;
1526                                 ReturnType = return_type_expr.Type;
1527                         }
1528
1529                         if (RootScope != null)
1530                                 Parameters = RootScope.InflateParameters (Parameters);
1531
1532                         aec = new EmitContext (
1533                                 ec.ResolveContext, ec.TypeContainer,
1534                                 RootScope != null ? RootScope : Host, Location, null, ReturnType,
1535                                 /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) |
1536                                 (ec.InUnsafe ? Modifiers.UNSAFE : 0), /* No constructor */ false);
1537
1538                         aec.CurrentAnonymousMethod = this;
1539                         aec.IsFieldInitializer = ec.IsFieldInitializer;
1540                         aec.IsStatic = ec.IsStatic;
1541                         aec.InferReturnType = ec.InferReturnType;
1542
1543                         IDisposable aec_dispose = null;
1544                         if (ec.IsInProbingMode)
1545                                 aec_dispose = aec.Set (EmitContext.Flags.ProbingMode);
1546
1547                         Report.Debug (64, "RESOLVE ANONYMOUS METHOD #1", this, Location, ec, aec,
1548                                       RootScope, Parameters, Block);
1549
1550                         bool unreachable;
1551                         bool res = aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable);
1552
1553                         if (aec_dispose != null)
1554                                 aec_dispose.Dispose ();
1555
1556                         return res;
1557                 }
1558
1559                 public virtual bool Resolve (EmitContext ec)
1560                 {
1561                         if (!ResolveNoDefine (ec))
1562                                 return false;
1563                         
1564                         Report.Debug (64, "RESOLVE ANONYMOUS METHOD #3", this, ec, aec, Block);
1565
1566                         if (aec.InferReturnType)
1567                                 ReturnType = aec.ReturnType;
1568
1569                         method = DoCreateMethodHost (ec);
1570
1571                         if (Scope != null)
1572                                 return true;
1573
1574                         if (!method.ResolveMembers ())
1575                                 return false;
1576                         return method.Define ();
1577                 }
1578
1579                 protected abstract Method DoCreateMethodHost (EmitContext ec);
1580
1581                 public Block Container {
1582                         get { return container; }
1583                 }
1584
1585                 public GenericMethod GenericMethod {
1586                         get { return generic; }
1587                 }
1588
1589                 public abstract bool IsIterator {
1590                         get;
1591                 }
1592
1593                 protected class AnonymousMethodMethod : Method
1594                 {
1595                         public readonly AnonymousContainer AnonymousMethod;
1596                         public readonly ScopeInfo Scope;
1597
1598                         public AnonymousMethodMethod (AnonymousContainer am, ScopeInfo scope,
1599                                                       GenericMethod generic, TypeExpr return_type,
1600                                                       int mod, MemberName name, Parameters parameters)
1601                                 : base (scope != null ? scope : am.Host,
1602                                         generic, return_type, mod | Modifiers.COMPILER_GENERATED, false, name, parameters, null)
1603                         {
1604                                 this.AnonymousMethod = am;
1605                                 this.Scope = scope;
1606
1607                                 if (scope != null) {
1608                                         scope.CheckMembersDefined ();
1609                                         scope.AddMethod (this);
1610                                 } else {
1611                                         ModFlags |= Modifiers.STATIC;
1612                                         am.Host.PartialContainer.AddMethod (this);
1613                                 }
1614                                 Block = am.Block;
1615                         }
1616
1617                         public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
1618                         {
1619                                 EmitContext aec = AnonymousMethod.aec;
1620                                 aec.ig = ig;
1621                                 aec.MethodIsStatic = Scope == null;
1622                                 return aec;
1623                         }
1624                 }
1625         }
1626
1627         public class LambdaMethod : AnonymousMethod
1628         {
1629                 public LambdaMethod (AnonymousMethod parent, RootScopeInfo root_scope,
1630                                         DeclSpace host, GenericMethod generic,
1631                                         Parameters parameters, Block container,
1632                                         ToplevelBlock block, Type return_type, Type delegate_type,
1633                                         Location loc)
1634                         : base (parent, root_scope, host, generic, parameters, container, block,
1635                                 return_type, delegate_type, loc)
1636                 {
1637                 }
1638
1639                 public override string ContainerType {
1640                         get {
1641                                 return "lambda expression";
1642                         }
1643                 }
1644         }
1645
1646         public class AnonymousMethod : AnonymousContainer
1647         {
1648                 public Type DelegateType;
1649
1650                 //
1651                 // The value return by the Compatible call, this ensure that
1652                 // the code works even if invoked more than once (Resolve called
1653                 // more than once, due to the way Convert.ImplicitConversion works
1654                 //
1655                 Expression anonymous_delegate;
1656                 RootScopeInfo root_scope;
1657                 ScopeInfo scope;
1658
1659                 public AnonymousMethod (AnonymousMethod parent, RootScopeInfo root_scope,
1660                                         DeclSpace host, GenericMethod generic,
1661                                         Parameters parameters, Block container,
1662                                         ToplevelBlock block, Type return_type, Type delegate_type,
1663                                         Location loc)
1664                         : base (parent, host, generic, parameters, container, block,
1665                                 return_type, 0, loc)
1666                 {
1667                         this.DelegateType = delegate_type;
1668                         this.root_scope = root_scope;
1669                 }
1670
1671                 public override string ContainerType {
1672                         get { return "anonymous method"; }
1673                 }
1674
1675                 public override RootScopeInfo RootScope {
1676                         get { return root_scope; }
1677                 }
1678
1679                 public override ScopeInfo Scope {
1680                         get { return scope; }
1681                 }
1682
1683                 public override bool IsIterator {
1684                         get { return false; }
1685                 }
1686
1687                 public Expression AnonymousDelegate {
1688                         get { return anonymous_delegate; }
1689                 }
1690
1691                 public override string GetSignatureForError ()
1692                 {
1693                         return TypeManager.CSharpName (DelegateType);
1694                 }
1695
1696                 //
1697                 // Creates the host for the anonymous method
1698                 //
1699                 protected override Method DoCreateMethodHost (EmitContext ec)
1700                 {
1701                         MemberCore mc = ec.ResolveContext as MemberCore;
1702                         string name = CompilerGeneratedClass.MakeName (mc.Name, null);
1703                         MemberName member_name;
1704
1705                         Report.Debug (128, "CREATE METHOD HOST #0", RootScope);
1706
1707                         Block b;
1708                         scope = RootScope;
1709
1710                         Report.Debug (128, "CREATE METHOD HOST #1", this, Block, Block.ScopeInfo,
1711                                       RootScope, Location);
1712
1713                         for (b = Block.Parent; b != null; b = b.Parent) {
1714                                 Report.Debug (128, "CREATE METHOD HOST #2", this, Block,
1715                                               b, b.ScopeInfo);
1716                                 if (b.ScopeInfo != null) {
1717                                         scope = b.ScopeInfo;
1718                                         break;
1719                                 }
1720                         }
1721
1722                         if (scope != null)
1723                                 scope.CheckMembersDefined ();
1724
1725                         ArrayList scopes = new ArrayList ();
1726                         if (b != null) {
1727                                 for (b = b.Parent; b != null; b = b.Parent) {
1728                                         if (b.ScopeInfo != null)
1729                                                 scopes.Add (b.ScopeInfo);
1730                                 }
1731                         }
1732
1733                         Report.Debug (128, "CREATE METHOD HOST #1", this, scope, scopes);
1734
1735                         foreach (ScopeInfo si in scopes)
1736                                 scope.CaptureScope (si);
1737
1738                         Report.Debug (128, "CREATE METHOD HOST", this, Block, container,
1739                                       RootScope, scope, scopes, Location,
1740                                       ContainerAnonymousMethod);
1741
1742                         GenericMethod generic_method = null;
1743 #if GMCS_SOURCE
1744                         if (TypeManager.IsGenericType (DelegateType)) {
1745                                 TypeArguments args = new TypeArguments (Location);
1746
1747                                 Type dt = DelegateType.GetGenericTypeDefinition ();
1748
1749                                 Type[] tparam = TypeManager.GetTypeArguments (dt);
1750                                 for (int i = 0; i < tparam.Length; i++)
1751                                         args.Add (new SimpleName (tparam [i].Name, Location));
1752
1753                                 member_name = new MemberName (name, args, Location);
1754
1755                                 Report.Debug (128, "CREATE METHOD HOST #5", this, DelegateType,
1756                                               TypeManager.GetTypeArguments (DelegateType),
1757                                               dt, tparam, args);
1758
1759                                 generic_method = new GenericMethod (
1760                                         Host.NamespaceEntry, scope, member_name,
1761                                         new TypeExpression (ReturnType, Location), Parameters);
1762
1763                                 generic_method.SetParameterInfo (null);
1764                         } else
1765 #endif
1766                                 member_name = new MemberName (name, Location);
1767
1768                         return new AnonymousMethodMethod (
1769                                 this, scope, generic_method, new TypeExpression (ReturnType, Location),
1770                                 Modifiers.INTERNAL, member_name, Parameters);
1771                 }
1772
1773                 bool ResolveAnonymousDelegate (EmitContext ec)
1774                 {
1775                         // If we are inferring the return type, set it to the discovered value.
1776                         if (DelegateType == null){
1777                                 DelegateType = aec.ReturnType;
1778                                 
1779                                 // The special value pointing to our internal type means it failed.
1780                                 if (DelegateType == typeof (AnonymousDelegate))
1781                                         return false;
1782                         }
1783
1784                         anonymous_delegate = new AnonymousDelegate (
1785                                 this, DelegateType, Location).Resolve (ec);
1786                         if (anonymous_delegate == null)
1787                                 return false;
1788                         return true;
1789                 }
1790
1791                 public override bool Resolve (EmitContext ec)
1792                 {
1793                         if (!base.Resolve (ec))
1794                                 return false;
1795
1796                         return ResolveAnonymousDelegate (ec);
1797                 }
1798
1799                 public override bool ResolveNoDefine (EmitContext ec)
1800                 {
1801                         if (!base.ResolveNoDefine (ec))
1802                                 return false;
1803
1804                         return ResolveAnonymousDelegate (ec);
1805                 }
1806
1807                 public MethodInfo GetMethodBuilder (EmitContext ec)
1808                 {
1809                         MethodInfo builder = method.MethodBuilder;
1810                         if ((Scope != null) && Scope.IsGeneric) {
1811                                 Type scope_type = Scope.GetScopeType (ec);
1812                                 if (scope_type == null)
1813                                         throw new InternalErrorException ();
1814
1815                                 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup (
1816                                         ec.ContainerType, scope_type, builder.Name, Location);
1817
1818                                 if (mg == null)
1819                                         throw new InternalErrorException ();
1820                                 builder = (MethodInfo) mg.Methods [0];
1821                         }
1822
1823 #if GMCS_SOURCE
1824                         if (!DelegateType.IsGenericType)
1825                                 return builder;
1826
1827                         Type[] targs = TypeManager.GetTypeArguments (DelegateType);
1828                         return builder.MakeGenericMethod (targs);
1829 #else
1830                         return builder;
1831 #endif
1832                 }
1833
1834                 public static void Error_AddressOfCapturedVar (string name, Location loc)
1835                 {
1836                         Report.Error (1686, loc,
1837                                       "Local variable `{0}' or its members cannot have their " +
1838                                       "address taken and be used inside an anonymous method block",
1839                                       name);
1840                 }
1841         }
1842
1843         //
1844         // This will emit the code for the delegate, as well delegate creation on the host
1845         //
1846         public class AnonymousDelegate : DelegateCreation {
1847                 AnonymousMethod am;
1848
1849                 //
1850                 // if target_type is null, this means that we do not know the type
1851                 // for this delegate, and we want to infer it from the various 
1852                 // returns (implicit and explicit) from the body of this anonymous
1853                 // method.
1854                 //
1855                 // for example, the lambda: x => 1
1856                 //
1857                 public AnonymousDelegate (AnonymousMethod am, Type target_type, Location l)
1858                 {
1859                         type = target_type;
1860                         loc = l;
1861                         this.am = am;
1862                 }
1863
1864                 public override Expression DoResolve (EmitContext ec)
1865                 {
1866                         eclass = ExprClass.Value;
1867
1868                         //
1869                         // If we are inferencing
1870                         //
1871                         if (type == null){
1872                                 type = ec.ReturnType;
1873
1874                                 // No type was infered
1875                                 if (type == null)
1876                                         return null;
1877                         }
1878
1879                         return this;
1880                 }
1881                 
1882                 public override void Emit (EmitContext ec)
1883                 {
1884                         //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE");
1885                         //ec.ig.Emit (OpCodes.Pop);
1886
1887                         //
1888                         // Now emit the delegate creation.
1889                         //
1890                         if ((am.Method.ModFlags & Modifiers.STATIC) == 0) {
1891                                 Report.Debug (128, "EMIT ANONYMOUS DELEGATE", this, am, am.Scope, loc);
1892                                 delegate_instance_expression = am.Scope.GetScopeInitializer (ec);
1893
1894                                 if (delegate_instance_expression == null)
1895                                         throw new InternalErrorException ();
1896                         }
1897
1898                         Expression ml = Expression.MemberLookup (
1899                                 ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
1900                                 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
1901                                 loc);
1902
1903                         constructor_method = ((MethodGroupExpr) ml).Methods [0];
1904 #if MS_COMPATIBLE
1905                         if (type.IsGenericType && type is TypeBuilder)
1906                                 constructor_method = TypeBuilder.GetConstructor (type, (ConstructorInfo)constructor_method);
1907 #endif
1908                         
1909                         delegate_method = am.GetMethodBuilder (ec);
1910                         base.Emit (ec);
1911
1912                         //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE DONE");
1913                         //ec.ig.Emit (OpCodes.Pop);
1914
1915                         Report.Debug (128, "EMIT ANONYMOUS DELEGATE DONE", this, am, am.Scope, loc);
1916                 }
1917         }
1918         
1919         public class AnonymousClass : CompilerGeneratedClass
1920         {
1921                 public AnonymousClass (TypeContainer parent, Location loc)
1922                         : base (parent, null, 0, loc)
1923                 {
1924                 }
1925         }
1926 }