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