2006-09-28 Marek Safar <marek.safar@seznam.cz>
[mono.git] / mcs / mcs / anonymous.cs
1 //
2 // anonymous.cs: Support for anonymous methods
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximain.com)
6 //
7 // (C) 2003, 2004 Novell, Inc.
8 //
9 // TODO: Ideally, we should have the helper classes emited as a hierarchy to map
10 // their nesting, and have the visibility set to private, instead of NestedAssembly
11 //
12 //
13 //
14
15 using System;
16 using System.Text;
17 using System.Collections;
18 using System.Reflection;
19 using System.Reflection.Emit;
20
21 namespace Mono.CSharp {
22
23         public abstract class AnonymousContainer : Expression
24         {
25                 // Used to generate unique method names.
26                 protected static int anonymous_method_count;
27                     
28                 // An array list of AnonymousMethodParameter or null
29                 public Parameters Parameters;
30
31                 //
32                 // The block that makes up the body for the anonymous mehtod
33                 //
34                 public ToplevelBlock Block;
35
36                 //
37                 // The container block for this anonymous method.
38                 //
39                 public Block ContainingBlock;
40
41                 //
42                 // The implicit method we create
43                 //
44                 public Method method;
45
46                 protected MethodInfo invoke_mb;
47                 
48                 // The emit context for the anonymous method
49                 public EmitContext aec;
50                 protected bool unreachable;
51
52                 // The method scope
53                 ScopeInfo method_scope;
54                 bool computed_method_scope = false;
55                 
56                 //
57                 // The modifiers applied to the method, we aggregate them
58                 //
59                 protected int method_modifiers = Modifiers.PRIVATE;
60                 
61                 //
62                 // Track the scopes that this method has used.  At the
63                 // end this is used to determine the ScopeInfo that will
64                 // host the method
65                 //
66                 ArrayList scopes_used = new ArrayList ();
67                 
68                 //
69                 // Points to our container anonymous method if its present
70                 //
71                 public AnonymousContainer ContainerAnonymousMethod;     
72
73                 protected AnonymousContainer (Parameters parameters, ToplevelBlock container,
74                                               ToplevelBlock block, Location l)
75                 {
76                         Parameters = parameters;
77                         Block = block;
78                         loc = l;
79
80                         //
81                         // The order is important: this setups the CaptureContext tree hierarchy.
82                         //
83                         if (container == null) {
84                                 return;
85                         }
86                         container.SetHaveAnonymousMethods (l, this);
87                         block.SetHaveAnonymousMethods (l, this);
88                 }
89
90                 protected AnonymousContainer (Parameters parameters, ToplevelBlock container,
91                                               Location l):
92                         this (parameters, container, new ToplevelBlock (container, parameters, l), l)
93                 {
94                 }
95
96                 public override Expression DoResolve (EmitContext ec)
97                 {
98                         //
99                         // Set class type, set type
100                         //
101
102                         eclass = ExprClass.Value;
103                         
104                         //
105                         // This hack means `The type is not accessible
106                         // anywhere', we depend on special conversion
107                         // rules.
108                         // 
109                         type = TypeManager.anonymous_method_type;
110
111                         return this;
112                 }
113
114                 public void RegisterScope (ScopeInfo scope)
115                 {
116                         if (scopes_used.Contains (scope))
117                                 return;
118                         scopes_used.Add (scope);
119                 }
120
121                 // Returns the deepest of two scopes
122                 ScopeInfo Deepest (ScopeInfo a, ScopeInfo b)
123                 {
124                         ScopeInfo p;
125
126                         if (a == null)
127                                 return b;
128                         if (b == null)
129                                 return a;
130                         if (a == b)
131                                 return a;
132
133                         //
134                         // If they Scopes are on the same CaptureContext, we do the double
135                         // checks just so if there is an invariant change in the future,
136                         // we get the exception at the end
137                         //
138                         for (p = a; p != null; p = p.ParentScope)
139                                 if (p == b)
140                                         return a;
141                         
142                         for (p = b; p != null; p = p.ParentScope)
143                                 if (p == a)
144                                         return b;
145
146                         CaptureContext ca = a.CaptureContext;
147                         CaptureContext cb = b.CaptureContext;
148
149                         for (CaptureContext c = ca; c != null; c = c.ParentCaptureContext)
150                                 if (c == cb)
151                                         return a;
152
153                         for (CaptureContext c = cb; c != null; c = c.ParentCaptureContext)
154                                 if (c == ca)
155                                         return b;
156                         throw new Exception ("Should never be reached");
157                 }
158
159                 //
160                 // Determines the proper host for a method considering the
161                 // scopes it references
162                 //
163                 public void ComputeMethodHost ()
164                 {
165                         if (computed_method_scope)
166                                 return;
167                         
168                         method_scope = null;
169                         int top = scopes_used.Count;
170                         computed_method_scope = true;
171
172                         if (top == 0)
173                                 return;
174                         
175                         method_scope = (ScopeInfo) scopes_used [0];
176                         if (top == 1)
177                                 return;
178                         
179                         for (int i = 1; i < top; i++)
180                                 method_scope = Deepest (method_scope, (ScopeInfo) scopes_used [i]);
181                 }
182
183                 public ScopeInfo Scope {
184                         get {
185                                 if (computed_method_scope)
186                                         return method_scope;
187
188                                 //
189                                 // This means that ComputeMethodHost is not being called, most
190                                 // likely by someone who overwrote the CreateMethodHost method
191                                 //
192                                 throw new Exception ("Internal error, AnonymousContainer.Scope is being used before its container is computed");
193                         }
194                 }
195                 
196                 
197                 protected abstract bool CreateMethodHost (EmitContext ec);
198
199                 public abstract void CreateScopeType (EmitContext ec, ScopeInfo scope);
200
201                 public abstract bool IsIterator {
202                         get;
203                 }
204         }
205
206         public class AnonymousMethod : AnonymousContainer
207         {
208                 TypeContainer host;
209
210                 //
211                 // The value return by the Compatible call, this ensure that
212                 // the code works even if invoked more than once (Resolve called
213                 // more than once, due to the way Convert.ImplicitConversion works
214                 //
215                 Expression anonymous_delegate;
216
217                 public AnonymousMethod (TypeContainer host, Parameters parameters, ToplevelBlock container,
218                                         ToplevelBlock block, Location l)
219                         : base (parameters, container, block, l)
220                 {
221                         this.host = host;
222                 }
223
224                 public override bool IsIterator {
225                         get { return false; }
226                 }
227
228                 public override void Emit (EmitContext ec)
229                 {
230                         // nothing, as we only exist to not do anything.
231                 }
232
233                 //
234                 // Creates the host for the anonymous method
235                 //
236                 protected override bool CreateMethodHost (EmitContext ec)
237                 {
238                         ComputeMethodHost ();
239
240                         //
241                         // Crude hack follows: we replace the TypeBuilder during the
242                         // definition to get the method hosted in the right class
243                         //
244                         TypeBuilder current_type = ec.TypeContainer.TypeBuilder;
245                         TypeBuilder type_host = (Scope == null ) ? current_type : Scope.ScopeTypeBuilder;
246
247                         if (current_type == null)
248                                 throw new Exception ("The current_type is null");
249                         
250                         if (type_host == null)
251                                 throw new Exception (String.Format ("Type host is null, method_host is {0}", Scope == null ? "null" : "Not null"));
252
253                         if (current_type != type_host)
254                                 method_modifiers = Modifiers.INTERNAL;
255
256                         if (current_type == type_host && ec.IsStatic){
257                                 method_modifiers |= Modifiers.STATIC;
258                                 current_type = null;
259                         } 
260
261                         method = new Method (
262                                 (TypeContainer) ec.TypeContainer, null,
263                                 new TypeExpression (invoke_mb.ReturnType, loc),
264                                 method_modifiers, false, new MemberName ("<#AnonymousMethod>" + anonymous_method_count++, loc),
265                                 Parameters, null);
266                         method.Block = Block;
267                         
268                         //
269                         // Swap the TypeBuilder while we define the method, then restore
270                         //
271                         if (current_type != null)
272                                 ec.TypeContainer.TypeBuilder = type_host;
273                         bool res = method.Define ();
274                         if (current_type != null)
275                                 ec.TypeContainer.TypeBuilder = current_type;
276                         return res;
277                 }
278
279                 void Error_ParameterMismatch (Type t)
280                 {
281                         Report.Error (1661, loc, "Anonymous method could not be converted to delegate `" +
282                                       "{0}' since there is a parameter mismatch", TypeManager.CSharpName (t));
283                 }
284
285                 public bool ImplicitStandardConversionExists (Type delegate_type)
286                 {
287                         if (Parameters == null)
288                                 return true;
289
290                         MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (host.TypeBuilder, delegate_type, loc);
291                         invoke_mb = (MethodInfo) invoke_mg.Methods [0];
292                         ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
293
294                         if (Parameters.Count != invoke_pd.Count)
295                                 return false;
296
297                         for (int i = 0; i < Parameters.Count; ++i) {
298                                 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i))
299                                         return false;
300                         }
301                         return true;
302                 }
303
304                 //
305                 // Returns true if this anonymous method can be implicitly
306                 // converted to the delegate type `delegate_type'
307                 //
308                 public Expression Compatible (EmitContext ec, Type delegate_type)
309                 {
310                         if (anonymous_delegate != null)
311                                 return anonymous_delegate;
312                         
313                         //
314                         // At this point its the first time we know the return type that is 
315                         // needed for the anonymous method.  We create the method here.
316                         //
317
318                         MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (ec.ContainerType, delegate_type, loc);
319                         invoke_mb = (MethodInfo) invoke_mg.Methods [0];
320                         ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
321
322                         if (Parameters == null) {
323                                 //
324                                 // We provide a set of inaccessible parameters
325                                 //
326                                 Parameter [] fixedpars = new Parameter [invoke_pd.Count];
327                                                                 
328                                 for (int i = 0; i < invoke_pd.Count; i++) {
329                                         Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
330                                         if ((p_mod & Parameter.Modifier.OUT) != 0) {
331                                                 Report.SymbolRelatedToPreviousError (delegate_type);
332                                                 Report.Error (1688, loc, "Cannot convert anonymous method block without a parameter list " +
333                                                         "to delegate type `{0}' because it has one or more `out' parameters",
334                                                         TypeManager.CSharpName (delegate_type));
335                                                 return null;
336                                         }
337
338                                         fixedpars [i] = new Parameter (invoke_pd.ParameterType (i),
339                                                 "+" + i, p_mod, null, loc);
340                                 }
341                                                                 
342                                 Parameters = new Parameters (fixedpars);
343                         } else {
344                                 if (Parameters.Count != invoke_pd.Count) {
345                                         Report.SymbolRelatedToPreviousError (delegate_type);
346                                         Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
347                                                 TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
348                                         Error_ParameterMismatch (delegate_type);
349                                         return null;
350                                 }
351
352                                 for (int i = 0; i < Parameters.Count; ++i) {
353                                         Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
354                                         if (Parameters.ParameterModifier (i) != p_mod && p_mod != Parameter.Modifier.PARAMS) {
355                                                 if (p_mod == Parameter.Modifier.NONE)
356                                                         Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
357                                                                 (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.ParameterModifier (i)));
358                                                 else
359                                                         Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
360                                                                 (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
361                                                 Error_ParameterMismatch (delegate_type);
362                                                 return null;
363                                         }
364
365                                         if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i)) {
366                                                 Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
367                                                         (i+1).ToString (),
368                                                         TypeManager.CSharpName (Parameters.ParameterType (i)),
369                                                         TypeManager.CSharpName (invoke_pd.ParameterType (i)));
370                                                 Error_ParameterMismatch (delegate_type);
371                                                 return null;
372                                         }
373                                 }
374                         }
375                         
376                         //
377                         // Second: the return type of the delegate must be compatible with 
378                         // the anonymous type.   Instead of doing a pass to examine the block
379                         // we satisfy the rule by setting the return type on the EmitContext
380                         // to be the delegate type return type.
381                         //
382
383                         //MethodBuilder builder = method_data.MethodBuilder;
384                         //ILGenerator ig = builder.GetILGenerator ();
385
386                         aec = new EmitContext (ec.ResolveContext,
387                                 ec.TypeContainer, ec.DeclContainer, loc, null,
388                                 invoke_mb.ReturnType,
389                                 /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) |
390                                 (ec.InUnsafe ? Modifiers.UNSAFE : 0) |
391                                 (ec.IsStatic ? Modifiers.STATIC : 0),
392                                 /* No constructor */ false);
393
394                         aec.CurrentAnonymousMethod = this;
395                         ContainerAnonymousMethod = ec.CurrentAnonymousMethod;
396                         ContainingBlock = ec.CurrentBlock;
397
398                         if (aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable)){
399                                 anonymous_delegate = new AnonymousDelegate (
400                                         this, delegate_type, loc).Resolve (ec);
401                                 return anonymous_delegate;
402                         }
403                         return null;
404                 }
405
406                 public override Expression DoResolve (EmitContext ec)
407                 {
408                         if (!ec.IsAnonymousMethodAllowed) {
409                                 Report.Error (1706, loc, "Anonymous methods are not allowed in the attribute declaration");
410                                 return null;
411                         }
412
413                         if (Parameters != null && !Parameters.Resolve (ec)) {
414                                 return null;
415                         }
416
417                         return base.DoResolve (ec);
418                 }
419
420
421                 public override string ExprClassName {
422                         get {
423                                 return "anonymous method";
424                         }
425                 }
426
427                 public MethodBuilder GetMethodBuilder ()
428                 {
429                         return method.MethodBuilder;
430                 }
431
432                 public override string GetSignatureForError ()
433                 {
434                         string s = TypeManager.CSharpSignature (invoke_mb);
435                         return s.Substring (0, s.IndexOf (".Invoke("));
436                 }
437                 
438                 public bool EmitMethod (EmitContext ec)
439                 {
440                         if (!CreateMethodHost (ec))
441                                 return false;
442
443                         MethodBuilder builder = GetMethodBuilder ();
444                         ILGenerator ig = builder.GetILGenerator ();
445                         aec.ig = ig;
446                         
447                         Parameters.ApplyAttributes (builder);
448
449                         //
450                         // Adjust based on the computed state of the
451                         // method from CreateMethodHost
452                         
453                         aec.MethodIsStatic = (method_modifiers & Modifiers.STATIC) != 0;
454                         
455                         aec.EmitMeta (Block);
456                         aec.EmitResolvedTopBlock (Block, unreachable);
457                         return true;
458                 }
459
460                 public override void CreateScopeType (EmitContext ec, ScopeInfo scope)
461                 {
462                         TypeBuilder container = ec.TypeContainer.TypeBuilder;
463                         string name = String.Format ("<>AnonHelp<{0}>", scope.id);
464
465                         scope.ScopeTypeBuilder = container.DefineNestedType (name,
466                                 TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit | TypeAttributes.NestedPrivate,
467                                          TypeManager.object_type);
468
469                         Type [] constructor_types = Type.EmptyTypes;
470                         scope.ScopeConstructor = scope.ScopeTypeBuilder.DefineConstructor (
471                                 MethodAttributes.Public | MethodAttributes.HideBySig |
472                                 MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
473                                 CallingConventions.HasThis, constructor_types);
474
475                         TypeManager.RegisterMethod (scope.ScopeConstructor, Parameters.EmptyReadOnlyParameters);
476
477                         ILGenerator cig = scope.ScopeConstructor.GetILGenerator ();
478                         cig.Emit (OpCodes.Ldarg_0);
479                         cig.Emit (OpCodes.Call, TypeManager.object_ctor);
480                         cig.Emit (OpCodes.Ret);
481                 }
482
483                 public static void Error_AddressOfCapturedVar (string name, Location loc)
484                 {
485                         Report.Error (1686, loc,
486                                 "Local variable `{0}' or its members cannot have their address taken and be used inside an anonymous method block",
487                                 name);
488                 }
489         }
490
491         //
492         // This will emit the code for the delegate, as well delegate creation on the host
493         //
494         public class AnonymousDelegate : DelegateCreation {
495                 AnonymousMethod am;
496
497                 public AnonymousDelegate (AnonymousMethod am, Type target_type, Location l)
498                 {
499                         type = target_type;
500                         loc = l;
501                         this.am = am;
502                 }
503
504                 public override Expression DoResolve (EmitContext ec)
505                 {
506                         eclass = ExprClass.Value;
507
508                         return this;
509                 }
510                 
511                 public override void Emit (EmitContext ec)
512                 {
513                         if (!am.EmitMethod (ec))
514                                 return;
515
516                         //
517                         // Now emit the delegate creation.
518                         //
519                         if ((am.method.ModFlags & Modifiers.STATIC) == 0)
520                                 delegate_instance_expression = new AnonymousInstance (am);
521                         
522                         Expression ml = Expression.MemberLookup (ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
523                                 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, loc);
524                         constructor_method = ((MethodGroupExpr) ml).Methods [0];
525                         delegate_method = am.GetMethodBuilder ();
526                         base.Emit (ec);
527                 }
528
529                 class AnonymousInstance : Expression {
530                         AnonymousMethod am;
531                         
532                         public AnonymousInstance (AnonymousMethod am)
533                         {
534                                 this.am = am;
535                                 eclass = ExprClass.Value;
536                         }
537
538                         public override Expression DoResolve (EmitContext ec)
539                         {
540                                 return this;
541                         }
542                         
543                         public override void Emit (EmitContext ec)
544                         {
545                                 am.aec.EmitMethodHostInstance (ec, am);
546                         }
547                 }
548         }
549
550         class CapturedParameter {
551                 public Type Type;
552                 public FieldBuilder FieldBuilder;
553                 public int Idx;
554
555                 public CapturedParameter (Type type, int idx)
556                 {
557                         Type = type;
558                         Idx = idx;
559                 }
560         }
561
562         //
563         // Here we cluster all the variables captured on a given scope, we also
564         // keep some extra information that might be required on each scope.
565         //
566         public class ScopeInfo {
567                 public CaptureContext CaptureContext;
568                 public ScopeInfo ParentScope;
569                 public Block ScopeBlock;
570                 public bool NeedThis = false;
571                 public bool HostsParameters = false;
572                 
573                 // For tracking the number of scopes created.
574                 public int id;
575                 static int count;
576                 bool inited = false;
577                 
578                 ArrayList locals = new ArrayList ();
579                 ArrayList children = new ArrayList ();
580
581                 //
582                 // The types and fields generated
583                 //
584                 public TypeBuilder ScopeTypeBuilder;
585                 public ConstructorBuilder ScopeConstructor;
586                 public FieldBuilder THIS;
587                 public FieldBuilder ParentLink;
588
589                 //
590                 // Points to the object of type `ScopeTypeBuilder' that
591                 // holds the data for the scope
592                 //
593                 LocalBuilder scope_instance;
594                 
595                 public ScopeInfo (CaptureContext cc, Block b)
596                 {
597                         CaptureContext = cc;
598                         ScopeBlock = b;
599                         id = count++;
600
601                         cc.RegisterCaptureContext ();
602                 }
603
604                 public void AddLocal (LocalInfo li)
605                 {
606                         if (locals.Contains (li))
607                                 return;
608
609                         locals.Add (li);
610                 }
611
612                 public bool IsCaptured (LocalInfo li)
613                 {
614                         return locals.Contains (li);
615                 }
616                 
617                 internal void AddChild (ScopeInfo si)
618                 {
619                         if (children.Contains (si))
620                                 return;
621
622                         //
623                         // If any of the current children should be a children of `si', move them there
624                         //
625                         ArrayList move_queue = null;
626                         foreach (ScopeInfo child in children){
627                                 if (child.ScopeBlock.IsChildOf (si.ScopeBlock)){
628                                         if (move_queue == null)
629                                                 move_queue = new ArrayList ();
630                                         move_queue.Add (child);
631                                         child.ParentScope = si;
632                                         si.AddChild (child);
633                                 }
634                         }
635                         
636                         children.Add (si);
637
638                         if (move_queue != null){
639                                 foreach (ScopeInfo child in move_queue){
640                                         children.Remove (child);
641                                 }
642                         }
643                 } 
644
645                 static int indent = 0;
646
647                 void Pad ()
648                 {
649                         for (int i = 0; i < indent; i++)
650                                 Console.Write ("    ");
651                 }
652
653                 void EmitDebug ()
654                 {
655                         //Console.WriteLine (Environment.StackTrace);
656                         Pad ();
657                         Console.WriteLine ("START");
658                         indent++;
659                         Pad ();
660                         Console.WriteLine ("NeedThis=" + NeedThis);
661                         foreach (LocalInfo li in locals){
662                                 Pad ();
663                                 Console.WriteLine ("var {0}", MakeFieldName (li.Name));
664                         }
665                         
666                         foreach (ScopeInfo si in children)
667                                 si.EmitDebug ();
668                         indent--;
669                         Pad ();
670                         Console.WriteLine ("END");
671                 }
672
673                 private string MakeFieldName (string local_name)
674                 {
675                         return "<" + id + ":" + local_name + ">";
676                 }
677
678                 public void EmitScopeType (EmitContext ec)
679                 {
680                         // EmitDebug ();
681
682                         if (ScopeTypeBuilder != null)
683                                 return;
684                         
685                         TypeBuilder container = ec.TypeContainer.TypeBuilder;
686
687                         CaptureContext.Host.CreateScopeType (ec, this);
688                         
689                         if (NeedThis)
690                                 THIS = ScopeTypeBuilder.DefineField ("<>THIS", container, FieldAttributes.Assembly);
691
692                         if (ParentScope != null){
693                                 if (ParentScope.ScopeTypeBuilder == null){
694                                         throw new Exception (String.Format ("My parent has not been initialized {0} and {1}", ParentScope, this));
695                                 }
696
697                                 if (ParentScope.ScopeTypeBuilder != ScopeTypeBuilder)
698                                         ParentLink = ScopeTypeBuilder.DefineField ("<>parent", ParentScope.ScopeTypeBuilder,
699                                                                                    FieldAttributes.Assembly);
700                         }
701                         
702                         if (NeedThis && ParentScope != null)
703                                 throw new Exception ("I was not expecting THIS && having a parent");
704
705                         foreach (LocalInfo info in locals)
706                                 info.FieldBuilder = ScopeTypeBuilder.DefineField (
707                                         MakeFieldName (info.Name), info.VariableType, FieldAttributes.Assembly);
708
709                         if (HostsParameters){
710                                 Hashtable captured_parameters = CaptureContext.captured_parameters;
711                                 
712                                 foreach (DictionaryEntry de in captured_parameters){
713                                         string name = (string) de.Key;
714                                         CapturedParameter cp = (CapturedParameter) de.Value;
715                                         FieldBuilder fb;
716                                         
717                                         fb = ScopeTypeBuilder.DefineField ("<p:" + name + ">", cp.Type, FieldAttributes.Assembly);
718                                         cp.FieldBuilder = fb;
719                                 }
720                         }
721
722                         foreach (ScopeInfo si in children){
723                                 si.EmitScopeType (ec);
724                         }
725                 }
726
727                 public void CloseTypes ()
728                 {
729                         RootContext.RegisterCompilerGeneratedType (ScopeTypeBuilder);
730                         foreach (ScopeInfo si in children)
731                                 si.CloseTypes ();
732                 }
733
734                 //
735                 // Emits the initialization code for the scope
736                 //
737                 public void EmitInitScope (EmitContext ec)
738                 {
739                         ILGenerator ig = ec.ig;
740
741                         if (inited)
742                                 return;
743
744                         if (ScopeConstructor == null)
745                                 throw new Exception ("ScopeConstructor is null for" + this.ToString ());
746                         
747                         if (!CaptureContext.Host.IsIterator) {
748                                 scope_instance = ig.DeclareLocal (ScopeTypeBuilder);
749                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) ScopeConstructor);
750                                 ig.Emit (OpCodes.Stloc, scope_instance);
751                         }
752
753                         if (THIS != null){
754                                 if (CaptureContext.Host.IsIterator) {
755                                         ig.Emit (OpCodes.Ldarg_0);
756                                         ig.Emit (OpCodes.Ldarg_1);
757                                 } else {
758                                         ig.Emit (OpCodes.Ldloc, scope_instance);
759                                         ig.Emit (OpCodes.Ldarg_0);
760                                 }
761                                 ig.Emit (OpCodes.Stfld, THIS);
762                         }
763
764                         //
765                         // Copy the parameter values, if any
766                         //
767                         int extra = ec.IsStatic ? 0 : 1;
768                         if (CaptureContext.Host.IsIterator)
769                                 extra++;
770                         if (HostsParameters){
771                                 Hashtable captured_parameters = CaptureContext.captured_parameters;
772                                 
773                                 foreach (DictionaryEntry de in captured_parameters){
774                                         CapturedParameter cp = (CapturedParameter) de.Value;
775
776                                         EmitScopeInstance (ig);
777                                         ParameterReference.EmitLdArg (ig, cp.Idx + extra);
778                                         ig.Emit (OpCodes.Stfld, cp.FieldBuilder);
779                                 }
780                         }
781
782                         if (ParentScope != null){
783                                 if (!ParentScope.inited)
784                                         ParentScope.EmitInitScope (ec);
785
786                                 if (ParentScope.ScopeTypeBuilder != ScopeTypeBuilder) {
787                                         //
788                                         // Only emit initialization in our capturecontext world
789                                         //
790                                         if (ParentScope.CaptureContext == CaptureContext){
791                                                 EmitScopeInstance (ig);
792                                                 ParentScope.EmitScopeInstance (ig);
793                                                 ig.Emit (OpCodes.Stfld, ParentLink);
794                                         } else {
795                                                 EmitScopeInstance (ig);
796                                                 ig.Emit (OpCodes.Ldarg_0);
797                                                 ig.Emit (OpCodes.Stfld, ParentLink);
798                                         }
799                                 }
800                         }
801                         inited = true;
802                 }
803
804                 public void EmitScopeInstance (ILGenerator ig)
805                 {
806                         if (CaptureContext.Host.IsIterator)
807                                 ig.Emit (OpCodes.Ldarg_0);
808                         else {
809                                 if (scope_instance == null){
810                                         //
811                                         // This is needed if someone overwrites the Emit method
812                                         // of Statement and manually calls Block.Emit without
813                                         // this snippet first:
814                                         // 
815                                         //   ec.EmitScopeInitFromBlock (The_Block);
816                                         //   The_Block.Emit (ec);
817                                         // 
818
819                                         Console.WriteLine (
820                                                 "The scope_instance has not been emitted, this typically means\n" +
821                                                 "that inside the compiler someone is calling Block.Emit without\n" +
822                                                 "first calling EmitScopeInitFromBlock for the block.  See compiler" +
823                                                 "source code for an explanation");
824                                         throw new Exception ("Internal compiler error");
825                                         
826                                 }
827                                 ig.Emit (OpCodes.Ldloc, scope_instance);
828                         }
829                 }
830
831                 public static void CheckCycles (string msg, ScopeInfo s)
832                 {
833                         ArrayList l = new ArrayList ();
834                         int n = 0;
835                         
836                         for (ScopeInfo p = s; p != null; p = p.ParentScope,n++){
837                                 if (l.Contains (p)){
838                                         Console.WriteLine ("Loop detected {0} in {1}", n, msg);
839                                         throw new Exception ();
840                                 }
841                                 l.Add (p);
842                         }
843                 }
844                 
845                 static void DoPath (StringBuilder sb, ScopeInfo start)
846                 {
847                         CheckCycles ("print", start);
848                         
849                         if (start.ParentScope != null){
850                                 DoPath (sb, start.ParentScope);
851                                 sb.Append (", ");
852                         }
853                         sb.Append ((start.id).ToString ());
854                 }
855                 
856                 public override string ToString ()
857                 {
858                         StringBuilder sb = new StringBuilder ();
859                         
860                         sb.Append ("{");
861                         if (CaptureContext != null){
862                                 sb.Append (CaptureContext.ToString ());
863                                 sb.Append (":");
864                         }
865
866                         DoPath (sb, this);
867                         sb.Append ("}");
868
869                         return sb.ToString ();
870                 }
871         }
872
873         //
874         // CaptureContext objects are created on demand if a method has
875         // anonymous methods and kept on the ToplevelBlock.
876         //
877         // If they exist, all ToplevelBlocks in the containing block are
878         // linked together (children pointing to their parents).
879         //
880         public class CaptureContext {
881                 public static int count;
882                 public int cc_id;
883                 public Location loc;
884                 
885                 //
886                 // Points to the toplevel block that owns this CaptureContext
887                 //
888                 ToplevelBlock toplevel_owner;
889
890                 //
891                 // All the scopes we capture
892                 //
893                 Hashtable scopes = new Hashtable ();
894
895                 //
896                 // All the root scopes
897                 //
898                 ArrayList roots = new ArrayList ();
899                 
900                 bool have_captured_vars = false;
901                 bool referenced_this = false;
902
903                 //
904                 // Captured fields
905                 //
906                 Hashtable captured_fields = new Hashtable ();
907                 Hashtable captured_variables = new Hashtable ();
908                 public Hashtable captured_parameters = new Hashtable ();
909                 public AnonymousContainer Host;
910                 
911                 public CaptureContext (ToplevelBlock toplevel_owner, Location loc,
912                                        AnonymousContainer host)
913                 {
914                         cc_id = count++;
915                         this.toplevel_owner = toplevel_owner;
916                         this.loc = loc;
917
918                         if (host != null)
919                                 Host = host;
920                 }
921
922                 void DoPath (StringBuilder sb, CaptureContext cc)
923                 {
924                         if (cc.ParentCaptureContext != null){
925                                 DoPath (sb, cc.ParentCaptureContext);
926                                 sb.Append (".");
927                         }
928                         sb.Append (cc.cc_id.ToString ());
929                 }
930
931                 public void ReParent (ToplevelBlock new_toplevel, AnonymousContainer new_host)
932                 {
933                         toplevel_owner = new_toplevel;
934                         Host = new_host;
935
936                         for (CaptureContext cc = ParentCaptureContext; cc != null;
937                              cc = cc.ParentCaptureContext) {
938                                 cc.Host = new_host;
939                         }
940                 }
941                 
942                 public override string ToString ()
943                 {
944                         StringBuilder sb = new StringBuilder ();
945                         sb.Append ("[");
946                         DoPath (sb, this);
947                         sb.Append ("]");
948                         return sb.ToString ();
949                 }
950
951                 public ToplevelBlock ParentToplevel {
952                         get {
953                                 return toplevel_owner.Container;
954                         }
955                 }
956
957                 public CaptureContext ParentCaptureContext {
958                         get {
959                                 ToplevelBlock parent = ParentToplevel;
960                                 
961                                 return (parent == null) ? null : parent.CaptureContext;
962                         }
963                 }
964
965                 ScopeInfo GetScopeForBlock (Block block)
966                 {
967                         ScopeInfo si = (ScopeInfo) scopes [block.ID];
968                         if (si != null)
969                                 return si;
970                         si = new ScopeInfo (this, block);
971                         scopes [block.ID] = si;
972                         return si;
973                 }
974                 
975                 public void AddLocal (AnonymousContainer am, LocalInfo li)
976                 {
977                         if (li.Block.Toplevel != toplevel_owner){
978                                 ParentCaptureContext.AddLocal (am, li);
979                                 return;
980                         }
981                         ScopeInfo scope = GetScopeForBlock (li.Block);
982
983                         //
984                         // Adjust the owner
985                         //
986                         if (Host != null)
987                                 Host.RegisterScope (scope);
988
989                         //
990                         // Adjust the user
991                         //
992                         am.RegisterScope (scope);
993                         
994                         if (captured_variables [li] != null)
995                                 return;
996                         
997                         have_captured_vars = true;
998                         captured_variables [li] = li;
999                         scope.AddLocal (li);
1000                 }
1001
1002                 //
1003                 // Retursn the CaptureContext for the block that defines the parameter `name'
1004                 //
1005                 static CaptureContext _ContextForParameter (ToplevelBlock current, string name)
1006                 {
1007                         ToplevelBlock container = current.Container;
1008                         if (container != null){
1009                                 CaptureContext cc = _ContextForParameter (container, name);
1010                                 if (cc != null)
1011                                         return cc;
1012                         }
1013                         if (current.IsParameterReference (name))
1014                                 return current.ToplevelBlockCaptureContext;
1015                         return null;
1016                 }
1017
1018                 static CaptureContext ContextForParameter (ToplevelBlock current, string name)
1019                 {
1020                         CaptureContext cc = _ContextForParameter (current, name);
1021                         if (cc == null)
1022                                 throw new Exception (String.Format ("request for parameteter {0} failed: not found", name));
1023                         return cc;
1024                 }
1025                 
1026                 //
1027                 // Records the captured parameter at the appropriate CaptureContext
1028                 //
1029                 public void AddParameter (EmitContext ec, AnonymousContainer am,
1030                                           string name, Type t, int idx)
1031                 {
1032                         CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name);
1033
1034                         cc.AddParameterToContext (am, name, t, idx);
1035                 }
1036
1037                 //
1038                 // Records the parameters in the context
1039                 //
1040                 public void AddParameterToContext (AnonymousContainer am, string name, Type t, int idx)
1041                 {
1042                         if (captured_parameters == null)
1043                                 captured_parameters = new Hashtable ();
1044                         if (captured_parameters [name] == null)
1045                                 captured_parameters [name] = new CapturedParameter (t, idx);
1046
1047                         ScopeInfo scope = GetScopeForBlock (toplevel_owner);
1048                         scope.HostsParameters = true;
1049                         am.RegisterScope (scope);
1050                 }
1051
1052                 //
1053                 // Captured fields are only recorded on the topmost CaptureContext, because that
1054                 // one is the one linked to the owner of instance fields
1055                 //
1056                 public void AddField (EmitContext ec, AnonymousContainer am, FieldExpr fe)
1057                 {
1058                         if (fe.FieldInfo.IsStatic)
1059                                 throw new Exception ("Attempt to register a static field as a captured field");
1060                         CaptureContext parent = ParentCaptureContext;
1061                         if (parent != null) {
1062                                 parent.AddField (ec, am, fe);
1063                                 return;
1064                         }
1065
1066                         ScopeInfo scope = GetScopeForBlock (toplevel_owner);
1067                         am.RegisterScope (scope);
1068                 }
1069
1070                 public void CaptureThis (AnonymousContainer am)
1071                 {
1072                         if (am == null)
1073                                 throw new Exception ("Internal Compiler error: Capturethis called with a null method");
1074                         CaptureContext parent = ParentCaptureContext;
1075                         if (parent != null) {
1076                                 parent.CaptureThis (am);
1077                                 return;
1078                         }
1079                         referenced_this = true;
1080
1081                         ScopeInfo scope = GetScopeForBlock (toplevel_owner);
1082                         am.RegisterScope (scope);
1083                 }
1084
1085                 public bool HaveCapturedVariables {
1086                         get {
1087                                 return have_captured_vars;
1088                         }
1089                 }
1090                 
1091                 public bool HaveCapturedFields {
1092                         get {
1093                                 CaptureContext parent = ParentCaptureContext;
1094                                 if (parent != null)
1095                                         return parent.HaveCapturedFields;
1096                                 return captured_fields.Count > 0;
1097                         }
1098                 }
1099
1100                 public bool IsCaptured (LocalInfo local)
1101                 {
1102                         foreach (ScopeInfo si in scopes.Values){
1103                                 if (si.IsCaptured (local))
1104                                         return true;
1105                         }
1106                         return false;
1107                 }
1108
1109                 //
1110                 // Returns whether the parameter is captured
1111                 //
1112                 public bool IsParameterCaptured (string name)
1113                 {
1114                         if (ParentCaptureContext != null && ParentCaptureContext.IsParameterCaptured (name))
1115                                 return true;
1116                         
1117                         if (captured_parameters != null)
1118                                 return captured_parameters [name] != null;
1119                         return false;
1120                 }
1121
1122                 public void EmitAnonymousHelperClasses (EmitContext ec)
1123                 {
1124                         if (roots.Count != 0){
1125                                 foreach (ScopeInfo root in roots){
1126                                         //
1127                                         // FIXME: We really should do this in a per-ScopeInfo
1128                                         // basis, instead of having the NeedThis applied to
1129                                         // all of the roots.
1130                                         //
1131                                         root.NeedThis = HaveCapturedFields || referenced_this;
1132                                         
1133                                         root.EmitScopeType (ec);
1134                                 }
1135                         } 
1136                 }
1137
1138                 public void CloseAnonymousHelperClasses ()
1139                 {
1140                         if (roots.Count != 0)
1141                                 foreach (ScopeInfo root in roots)
1142                                         root.CloseTypes ();
1143                 }
1144
1145                 public void EmitInitScope (EmitContext ec)
1146                 {
1147                         EmitAnonymousHelperClasses (ec);
1148                         if (roots.Count != 0)
1149                                 foreach (ScopeInfo root in roots)
1150                                         root.EmitInitScope (ec);                }
1151
1152                 //
1153                 // This is called externally when we start emitting code for a block
1154                 // if the block has a ScopeInfo associated, emit the init code
1155                 //
1156                 public void EmitScopeInitFromBlock (EmitContext ec, Block b)
1157                 {
1158                         ScopeInfo si = (ScopeInfo) scopes [b.ID];
1159                         if (si == null)
1160                                 return;
1161
1162                         si.EmitInitScope (ec);
1163                 }
1164                 
1165                 //
1166                 // Emits the opcodes necessary to load the instance of the captured
1167                 // variable in `li'
1168                 //
1169                 public void EmitCapturedVariableInstance (EmitContext ec, LocalInfo li,
1170                                                           AnonymousContainer am)
1171                 {
1172                         ILGenerator ig = ec.ig;
1173                         ScopeInfo si;
1174
1175                         if (li.Block.Toplevel == toplevel_owner){
1176                                 si = (ScopeInfo) scopes [li.Block.ID];
1177                                 si.EmitScopeInstance (ig);
1178                                 return;
1179                         }
1180
1181                         si = am.Scope;
1182                         ig.Emit (OpCodes.Ldarg_0);
1183                         if (si != null){
1184                                 if (am.IsIterator && (si.ScopeBlock.Toplevel == li.Block.Toplevel)) {
1185                                         return;
1186                                 }
1187
1188                                 while (si.ScopeBlock.ID != li.Block.ID){
1189                                         if (si.ParentLink != null)
1190                                                 ig.Emit (OpCodes.Ldfld, si.ParentLink);
1191                                         si = si.ParentScope;
1192                                         if (si == null) {
1193                                                 si = am.Scope;
1194                                                 Console.WriteLine ("Target: {0} {1}", li.Block.ID, li.Name);
1195                                                 while (si.ScopeBlock.ID != li.Block.ID){
1196                                                         Console.WriteLine ("Trying: {0}", si.ScopeBlock.ID);
1197                                                         si = si.ParentScope;
1198                                                 }
1199
1200                                                 throw new Exception (
1201                                                              String.Format ("Never found block {0} starting at {1} while looking up {2}",
1202                                                                             li.Block.ID, am.Scope.ScopeBlock.ID, li.Name));
1203                                         }
1204                                 }
1205                         }
1206                 }
1207
1208                 //
1209                 // Internal routine that loads the instance to reach parameter `name'
1210                 //
1211                 void EmitParameterInstance (EmitContext ec, string name)
1212                 {
1213                         CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name);
1214                         if (cc != this){
1215                                 cc.EmitParameterInstance (ec, name);
1216                                 return;
1217                         }
1218
1219                         CapturedParameter par_info = (CapturedParameter) captured_parameters [name];
1220                         if (par_info != null){
1221                                 // 
1222                                 // FIXME: implementing this.
1223                                 //
1224                         }
1225                         ILGenerator ig = ec.ig;
1226
1227                         ScopeInfo si;
1228
1229                         if (ec.CurrentBlock.Toplevel == toplevel_owner) {
1230                                 si = (ScopeInfo) scopes [toplevel_owner.ID];
1231                                 si.EmitScopeInstance (ig);
1232                         } else {
1233                                 si = ec.CurrentAnonymousMethod.Scope;
1234                                 ig.Emit (OpCodes.Ldarg_0);
1235                         }
1236
1237                         if (si != null){
1238                                 while (si.ParentLink != null) {
1239                                         ig.Emit (OpCodes.Ldfld, si.ParentLink);
1240                                         si = si.ParentScope;
1241                                 } 
1242                         }
1243                 }
1244
1245                 //
1246                 // Emits the code necessary to load the parameter named `name' within
1247                 // an anonymous method.
1248                 //
1249                 public void EmitParameter (EmitContext ec, string name, bool leave_copy, bool prepared, ref LocalTemporary temp)
1250                 {
1251                         CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name);
1252                         if (cc != this){
1253                                 cc.EmitParameter (ec, name, leave_copy, prepared, ref temp);
1254                                 return;
1255                         }
1256                         if (!prepared)
1257                                 EmitParameterInstance (ec, name);
1258                         CapturedParameter par_info = (CapturedParameter) captured_parameters [name];
1259                         if (par_info != null){
1260                                 // 
1261                                 // FIXME: implementing this.
1262                                 //
1263                         }
1264                         ec.ig.Emit (OpCodes.Ldfld, par_info.FieldBuilder);
1265
1266                         if (leave_copy){
1267                                 ec.ig.Emit (OpCodes.Dup);
1268                                 temp = new LocalTemporary (par_info.FieldBuilder.FieldType);
1269                                 temp.Store (ec);
1270                         }
1271                 }
1272
1273                 //
1274                 // Implements the assignment of `source' to the paramenter named `name' within
1275                 // an anonymous method.
1276                 //
1277                 public void EmitAssignParameter (EmitContext ec, string name, Expression source, bool leave_copy, bool prepare_for_load, ref LocalTemporary temp)
1278                 {
1279                         CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name);
1280                         if (cc != this){
1281                                 cc.EmitAssignParameter (ec, name, source, leave_copy, prepare_for_load, ref temp);
1282                                 return;
1283                         }
1284                         ILGenerator ig = ec.ig;
1285                         CapturedParameter par_info = (CapturedParameter) captured_parameters [name];
1286
1287                         EmitParameterInstance (ec, name);
1288                         if (prepare_for_load)
1289                                 ig.Emit (OpCodes.Dup);
1290                         source.Emit (ec);
1291                         if (leave_copy){
1292                                 ig.Emit (OpCodes.Dup);
1293                                 temp = new LocalTemporary (par_info.FieldBuilder.FieldType);
1294                                 temp.Store (ec);
1295                         }
1296                         ig.Emit (OpCodes.Stfld, par_info.FieldBuilder);
1297                         if (temp != null)
1298                                 temp.Emit (ec);
1299                 }
1300
1301                 //
1302                 // Emits the address for the parameter named `name' within
1303                 // an anonymous method.
1304                 //
1305                 public void EmitAddressOfParameter (EmitContext ec, string name)
1306                 {
1307                         CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name);
1308                         if (cc != this){
1309                                 cc.EmitAddressOfParameter (ec, name);
1310                                 return;
1311                         }
1312                         EmitParameterInstance (ec, name);
1313                         CapturedParameter par_info = (CapturedParameter) captured_parameters [name];
1314                         ec.ig.Emit (OpCodes.Ldflda, par_info.FieldBuilder);
1315                 }
1316
1317                 //
1318                 // The following methods are only invoked on the host for the
1319                 // anonymous method.
1320                 //
1321                 public void EmitMethodHostInstance (EmitContext target, AnonymousContainer am)
1322                 {
1323                         ILGenerator ig = target.ig;
1324                         ScopeInfo si = am.Scope;
1325
1326                         AnonymousContainer container = am.ContainerAnonymousMethod;
1327
1328                         if ((si == null) || ((container != null) && (si == container.Scope))) {
1329                                 ig.Emit (OpCodes.Ldarg_0);
1330                                 return;
1331                         }
1332
1333                         si.EmitInitScope (target);
1334                         si.EmitScopeInstance (ig);
1335                 }
1336
1337                 public void RegisterCaptureContext ()
1338                 {
1339                         toplevel_owner.RegisterCaptureContext (this);
1340                 }
1341
1342                 //
1343                 // Returs true if `probe' is an ancestor of `scope' in the 
1344                 // scope chain
1345                 //
1346                 bool IsAncestor (ScopeInfo probe, ScopeInfo scope)
1347                 {
1348                         for (Block b = scope.ScopeBlock.Parent; b != null; b = b.Parent){
1349                                 if (probe.ScopeBlock == b)
1350                                         return true;
1351                         }
1352                         return false;
1353                 }
1354
1355                 //
1356                 // Returns an ArrayList of ScopeInfos that enumerates all the ancestors
1357                 // of `scope' found in `scope_list'.
1358                 //
1359                 // The value returned is either a ScopeInfo or an Arraylist of ScopeInfos
1360                 //
1361                 object GetAncestorScopes (ScopeInfo scope, ScopeInfo [] scope_list)
1362                 {
1363                         object ancestors = null;
1364                         
1365                         for (int i = 0; i < scope_list.Length; i++){
1366                                 // Ignore the same scope
1367                                 if (scope_list [i] == scope)
1368                                         continue;
1369                                 
1370                                 if (IsAncestor (scope_list [i], scope)){
1371                                         if (ancestors == null){
1372                                                 ancestors = scope_list [i];
1373                                                 continue;
1374                                         }
1375                                         
1376                                         if (ancestors is ScopeInfo){
1377                                                 object old = ancestors;
1378                                                 ancestors = new ArrayList (4);
1379                                                 ((ArrayList)ancestors).Add (old);
1380                                         } 
1381                                         
1382                                         ((ArrayList)ancestors).Add (scope_list [i]);
1383                                 }
1384                         }
1385                         return ancestors;
1386                 }
1387
1388                 //
1389                 // Returns the immediate parent of `scope' from all the captured
1390                 // scopes found in `scope_list', or null if this is a toplevel scope.
1391                 //
1392                 ScopeInfo GetParentScope (ScopeInfo scope, ScopeInfo [] scope_list)
1393                 {
1394                         object ancestors = GetAncestorScopes (scope, scope_list);
1395                         if (ancestors == null)
1396                                 return null;
1397
1398                         // Single match, thats the parent.
1399                         if (ancestors is ScopeInfo)
1400                                 return (ScopeInfo) ancestors;
1401
1402                         ArrayList candidates = (ArrayList) ancestors;
1403                         ScopeInfo parent = (ScopeInfo) candidates [0];
1404                         for (int i = 1; i < candidates.Count; i++){
1405                                 if (IsAncestor (parent, (ScopeInfo) candidates [i]))
1406                                         parent = (ScopeInfo) candidates [i];
1407                         }
1408                         return parent;
1409                 }
1410                 
1411                 //
1412                 // Links all the scopes
1413                 //
1414                 bool linked;
1415                 public void LinkScopes ()
1416                 {
1417                         if (linked)
1418                                 return;
1419                         
1420                         linked = true;
1421                         if (ParentCaptureContext != null)
1422                                 ParentCaptureContext.LinkScopes ();
1423
1424                         int scope_count = scopes.Keys.Count;
1425                         ScopeInfo [] scope_list = new ScopeInfo [scope_count];
1426                         scopes.Values.CopyTo (scope_list, 0);
1427
1428                         for (int i = 0; i < scope_count; i++){
1429                                 ScopeInfo parent = GetParentScope (scope_list [i], scope_list);
1430
1431                                 if (parent == null){
1432                                         roots.Add (scope_list [i]);
1433                                         continue;
1434                                 }
1435
1436                                 scope_list [i].ParentScope = parent;
1437                                 parent.AddChild (scope_list [i]);
1438                         }
1439
1440                         //
1441                         // Link the roots to their parent containers if any.
1442                         //
1443                         if (ParentCaptureContext != null && roots.Count != 0){
1444                                 ScopeInfo one_root = (ScopeInfo) roots [0];
1445                                 bool found = false;
1446                                 
1447                                 foreach (ScopeInfo a_parent_root in ParentCaptureContext.roots){
1448                                         if (!IsAncestor (a_parent_root, one_root))
1449                                                 continue;
1450
1451                                         found = true;
1452                                         
1453                                         // Found, link all the roots to this root
1454                                         foreach (ScopeInfo root in roots){
1455                                                 root.ParentScope = a_parent_root;
1456                                                 a_parent_root.AddChild (root);
1457                                         }
1458                                         break;
1459                                 }
1460                                 if (!found){
1461                                         //
1462                                         // This is to catch a condition in which it is
1463                                         // not possible to determine the containing ScopeInfo
1464                                         // from an encapsulating CaptureContext
1465                                         //
1466                                         throw new Exception ("Internal compiler error: Did not find the parent for the root in the chain");
1467                                 }
1468                         }
1469                 }
1470         }
1471 }