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