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