* mcs/statement.cs (Foreach.ArrayForeach.Resolve): Set barrier after
[mono.git] / mcs / mcs / anonymous.cs
index 98cf47ee22e47c60b758d68ac52cabc1e0c02b11..e4822e289163de6f252dae4892961d1a77e8f670 100644 (file)
@@ -20,9 +20,10 @@ using System.Reflection.Emit;
 
 namespace Mono.CSharp {
 
-       public class AnonymousMethod : Expression {
+       public abstract class AnonymousContainer : Expression
+       {
                // Used to generate unique method names.
-               static int anonymous_method_count;
+               protected static int anonymous_method_count;
                    
                // An array list of AnonymousMethodParameter or null
                public Parameters Parameters;
@@ -42,31 +43,35 @@ namespace Mono.CSharp {
                //
                public Method method;
 
-               MethodInfo invoke_mb;
+               protected MethodInfo invoke_mb;
                
                // The emit context for the anonymous method
                public EmitContext aec;
-               public InternalParameters amp;
-               bool unreachable;
+               protected bool unreachable;
 
+               // The method scope
+               ScopeInfo method_scope;
+               bool computed_method_scope = false;
+               
                //
                // The modifiers applied to the method, we aggregate them
                //
-               int method_modifiers = Modifiers.INTERNAL;
+               protected int method_modifiers = Modifiers.PRIVATE;
                
                //
-               // During the resolve stage of the anonymous method body,
-               // we discover the actual scope where we are hosted, or
-               // null to host the method in the same class
+               // Track the scopes that this method has used.  At the
+               // end this is used to determine the ScopeInfo that will
+               // host the method
                //
-               public ScopeInfo Scope;
-
+               ArrayList scopes_used = new ArrayList ();
+               
                //
                // Points to our container anonymous method if its present
                //
-               public AnonymousMethod ContainerAnonymousMethod;
-               
-               public AnonymousMethod (Parameters parameters, ToplevelBlock container, ToplevelBlock block, Location l)
+               public AnonymousContainer ContainerAnonymousMethod;     
+
+               protected AnonymousContainer (Parameters parameters, ToplevelBlock container,
+                                             ToplevelBlock block, Location l)
                {
                        Parameters = parameters;
                        Block = block;
@@ -75,10 +80,19 @@ namespace Mono.CSharp {
                        //
                        // The order is important: this setups the CaptureContext tree hierarchy.
                        //
+                       if (container == null) {
+                               return;
+                       }
                        container.SetHaveAnonymousMethods (l, this);
                        block.SetHaveAnonymousMethods (l, this);
                }
 
+               protected AnonymousContainer (Parameters parameters, ToplevelBlock container,
+                                             Location l):
+                       this (parameters, container, new ToplevelBlock (container, parameters, l), l)
+               {
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        //
@@ -97,6 +111,113 @@ namespace Mono.CSharp {
                        return this;
                }
 
+               public void RegisterScope (ScopeInfo scope)
+               {
+                       if (scopes_used.Contains (scope))
+                               return;
+                       scopes_used.Add (scope);
+               }
+
+               // Returns the deepest of two scopes
+               ScopeInfo Deepest (ScopeInfo a, ScopeInfo b)
+               {
+                       ScopeInfo p;
+
+                       if (a == null)
+                               return b;
+                       if (b == null)
+                               return a;
+                       if (a == b)
+                               return a;
+
+                       //
+                       // If they Scopes are on the same CaptureContext, we do the double
+                       // checks just so if there is an invariant change in the future,
+                       // we get the exception at the end
+                       //
+                       for (p = a; p != null; p = p.ParentScope)
+                               if (p == b)
+                                       return a;
+                       
+                       for (p = b; p != null; p = p.ParentScope)
+                               if (p == a)
+                                       return b;
+
+                       CaptureContext ca = a.CaptureContext;
+                       CaptureContext cb = b.CaptureContext;
+
+                       for (CaptureContext c = ca; c != null; c = c.ParentCaptureContext)
+                               if (c == cb)
+                                       return a;
+
+                       for (CaptureContext c = cb; c != null; c = c.ParentCaptureContext)
+                               if (c == ca)
+                                       return b;
+                       throw new Exception ("Should never be reached");
+               }
+
+               //
+               // Determines the proper host for a method considering the
+               // scopes it references
+               //
+               public void ComputeMethodHost ()
+               {
+                       if (computed_method_scope)
+                               return;
+                       
+                       method_scope = null;
+                       int top = scopes_used.Count;
+                       computed_method_scope = true;
+
+                       if (top == 0)
+                               return;
+                       
+                       method_scope = (ScopeInfo) scopes_used [0];
+                       if (top == 1)
+                               return;
+                       
+                       for (int i = 1; i < top; i++)
+                               method_scope = Deepest (method_scope, (ScopeInfo) scopes_used [i]);
+               }
+
+               public ScopeInfo Scope {
+                       get {
+                               if (computed_method_scope)
+                                       return method_scope;
+
+                               //
+                               // This means that ComputeMethodHost is not being called, most
+                               // likely by someone who overwrote the CreateMethodHost method
+                               //
+                               throw new Exception ("Internal error, AnonymousContainer.Scope is being used before its container is computed");
+                       }
+               }
+               
+               
+               protected abstract bool CreateMethodHost (EmitContext ec);
+
+               public abstract void CreateScopeType (EmitContext ec, ScopeInfo scope);
+
+               public abstract bool IsIterator {
+                       get;
+               }
+       }
+
+       public class AnonymousMethod : AnonymousContainer
+       {
+               TypeContainer host;
+
+               public AnonymousMethod (TypeContainer host, Parameters parameters, ToplevelBlock container,
+                                       ToplevelBlock block, Location l)
+                       : base (parameters, container, block, l)
+               {
+                       this.host = host;
+               }
+
+               public override bool IsIterator {
+                       get { return false; }
+               }
+
                public override void Emit (EmitContext ec)
                {
                        // nothing, as we only exist to not do anything.
@@ -105,36 +226,37 @@ namespace Mono.CSharp {
                //
                // Creates the host for the anonymous method
                //
-               bool CreateMethodHost (EmitContext ec, Type return_type)
+               protected override bool CreateMethodHost (EmitContext ec)
                {
+                       ComputeMethodHost ();
+
                        //
                        // Crude hack follows: we replace the TypeBuilder during the
                        // definition to get the method hosted in the right class
                        //
-                       
                        TypeBuilder current_type = ec.TypeContainer.TypeBuilder;
-                       TypeBuilder type_host = (Scope == null ) // || Scope.ScopeTypeBuilder == null)
-                               ? current_type : Scope.ScopeTypeBuilder;
+                       TypeBuilder type_host = (Scope == null ) ? current_type : Scope.ScopeTypeBuilder;
 
                        if (current_type == null)
                                throw new Exception ("The current_type is null");
                        
                        if (type_host == null)
-                               throw new Exception ("Type host is null");
-                       
+                               throw new Exception (String.Format ("Type host is null, method_host is {0}", Scope == null ? "null" : "Not null"));
+
+                       if (current_type != type_host)
+                               method_modifiers = Modifiers.INTERNAL;
+
                        if (current_type == type_host && ec.IsStatic){
-                               if (ec.IsStatic)
-                                       method_modifiers |= Modifiers.STATIC;
+                               method_modifiers |= Modifiers.STATIC;
                                current_type = null;
                        } 
 
                        method = new Method (
                                (TypeContainer) ec.TypeContainer,
-                               new TypeExpression (return_type, loc),
-                               method_modifiers, false, new MemberName ("<#AnonymousMethod>" + anonymous_method_count++),
-                               Parameters, null, loc);
+                               new TypeExpression (invoke_mb.ReturnType, loc),
+                               method_modifiers, false, new MemberName ("<#AnonymousMethod>" + anonymous_method_count++, loc),
+                               Parameters, null);
                        method.Block = Block;
-
                        
                        //
                        // Swap the TypeBuilder while we define the method, then restore
@@ -146,119 +268,90 @@ namespace Mono.CSharp {
                                ec.TypeContainer.TypeBuilder = current_type;
                        return res;
                }
-               
+
                void Error_ParameterMismatch (Type t)
                {
                        Report.Error (1661, loc, "Anonymous method could not be converted to delegate `" +
-                                     "{0}' since there is a parameter mismatch", t);
+                                     "{0}' since there is a parameter mismatch", TypeManager.CSharpName (t));
+               }
+
+               public bool ImplicitStandardConversionExists (Type delegate_type)
+               {
+                       if (Parameters == null)
+                               return true;
+
+                       invoke_mb = (MethodInfo) Delegate.GetInvokeMethod (host.TypeBuilder, delegate_type, loc);
+                       ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
+
+                       if (Parameters.Count != invoke_pd.Count)
+                               return false;
+
+                       for (int i = 0; i < Parameters.Count; ++i) {
+                               if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i))
+                                       return false;
+                       }
+                       return true;
                }
 
                //
                // Returns true if this anonymous method can be implicitly
                // converted to the delegate type `delegate_type'
                //
-               public Expression Compatible (EmitContext ec, Type delegate_type, bool probe)
+               public Expression Compatible (EmitContext ec, Type delegate_type)
                {
                        //
                        // At this point its the first time we know the return type that is 
                        // needed for the anonymous method.  We create the method here.
                        //
 
-                       invoke_mb = (MethodInfo) Delegate.GetInvokeMethod (ec, delegate_type, loc);
+                       invoke_mb = (MethodInfo) Delegate.GetInvokeMethod (ec.ContainerType, delegate_type, loc);
                        ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
 
-                       //
-                       // If implicit parameters are set, then we must check for out in the parameters
-                       // and flag it accordingly.
-                       //
-                       bool out_invalid_check = false;
-                       
-                       if (Parameters == null){
-                               int i, j;
-                               out_invalid_check = true;
-                               
+                       if (Parameters == null) {
                                //
                                // We provide a set of inaccessible parameters
                                //
-                               int params_idx = -1;
-                               for (i = 0; i < invoke_pd.Count; i++){
-                                       if (invoke_pd.ParameterModifier (i) == Parameter.Modifier.PARAMS)
-                                               params_idx = i;
-                               }
-                               int n = invoke_pd.Count - (params_idx != -1 ? 1 : 0);
-                               Parameter [] fixedpars = new Parameter [n];
-                               
-                               for (i =  j = 0; i < invoke_pd.Count; i++){
-                                       if (invoke_pd.ParameterModifier (i) == Parameter.Modifier.PARAMS)
-                                               continue;
-                                       fixedpars [j] = new Parameter (
-                                               new TypeExpression (invoke_pd.ParameterType (i), loc),
-                                               "+" + j, invoke_pd.ParameterModifier (i), null);
-                                       j++;
+                               Parameter [] fixedpars = new Parameter [invoke_pd.Count];
+                                                               
+                               for (int i = 0; i < invoke_pd.Count; i++){
+                                       fixedpars [i] = new Parameter (
+                                               invoke_pd.ParameterType (i),
+                                               "+" + i, invoke_pd.ParameterModifier (i), null, loc);
                                }
-                               
-                               Parameter variable = null;
-                               if (params_idx != -1){
-                                       variable = new Parameter (
-                                               new TypeExpression (invoke_pd.ParameterType (params_idx), loc),
-                                               "+" + params_idx, invoke_pd.ParameterModifier (params_idx), null);
-                               }
-
-                               Parameters = new Parameters (fixedpars, variable, loc);
-                       }
-                       
-                       //
-                       // First, parameter types of `delegate_type' must be compatible
-                       // with the anonymous method.
-                       //
-                       amp = new InternalParameters (Parameters.GetParameterInfo (ec), Parameters);
-                       
-                       if (amp.Count != invoke_pd.Count){
-                               if (!probe){
-                                       Report.Error (1593, loc, 
-                                             "Anonymous method has {0} parameters, while delegate requires {1}",
-                                             amp.Count, invoke_pd.Count);
+                                                               
+                               Parameters = new Parameters (fixedpars);
+                       } else {
+                               if (Parameters.Count != invoke_pd.Count) {
+                                       Report.SymbolRelatedToPreviousError (delegate_type);
+                                       Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
+                                               TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
                                        Error_ParameterMismatch (delegate_type);
-                               }
-                               return null;
-                       }
-                       
-                       for (int i = 0; i < amp.Count; i++){
-                               Parameter.Modifier amp_mod = amp.ParameterModifier (i);
-                               if (amp_mod != invoke_pd.ParameterModifier (i)){
-                                       if (!probe){
-                                               Report.Error (1676, loc, 
-                                                     "Signature mismatch in parameter modifier for parameter #0", i + 1);
-                                               Error_ParameterMismatch (delegate_type);
-                                       }
                                        return null;
                                }
-                               
-                               if (amp.ParameterType (i) != invoke_pd.ParameterType (i)){
-                                       if (!probe){
-                                               Report.Error (1678, loc, 
-                                                                     "Signature mismatch in parameter {0}: need `{1}' got `{2}'", i + 1,
-                                                                     TypeManager.CSharpName (invoke_pd.ParameterType (i)),
-                                                                     TypeManager.CSharpName (amp.ParameterType (i)));
+
+                               for (int i = 0; i < Parameters.Count; ++i) {
+                                       Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
+                                       if (Parameters.ParameterModifier (i) != p_mod && p_mod != Parameter.Modifier.PARAMS) {
+                                               if (p_mod == Parameter.Modifier.NONE)
+                                                       Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
+                                                               (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.ParameterModifier (i)));
+                                               else
+                                                       Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
+                                                               (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
                                                Error_ParameterMismatch (delegate_type);
+                                               return null;
                                        }
-                                       return null;
-                               }
-                               
-                               if (out_invalid_check && (invoke_pd.ParameterModifier (i) & Parameter.Modifier.OUT) != 0){
-                                       if (!probe){
-                                               Report.Error (1676, loc,"Parameter {0} must include the `out' modifier ", i+1);
+
+                                       if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i)) {
+                                               Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
+                                                       (i+1).ToString (),
+                                                       TypeManager.CSharpName (Parameters.ParameterType (i)),
+                                                       TypeManager.CSharpName (invoke_pd.ParameterType (i)));
                                                Error_ParameterMismatch (delegate_type);
+                                               return null;
                                        }
-                                       return null;
                                }
                        }
-
-                       //
-                       // If we are only probing, return ourselves
-                       //
-                       if (probe)
-                               return this;
                        
                        //
                        // Second: the return type of the delegate must be compatible with 
@@ -270,55 +363,106 @@ namespace Mono.CSharp {
                        //MethodBuilder builder = method_data.MethodBuilder;
                        //ILGenerator ig = builder.GetILGenerator ();
 
-                       
-                       aec = new EmitContext (
-                               ec.TypeContainer, ec.DeclSpace, loc, null,
+                       aec = new EmitContext (ec.ResolveContext,
+                               ec.TypeContainer, ec.DeclContainer, loc, null,
                                invoke_mb.ReturnType,
                                /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) |
-                               (ec.InUnsafe ? Modifiers.UNSAFE : 0),
+                               (ec.InUnsafe ? Modifiers.UNSAFE : 0) |
+                               (ec.IsStatic ? Modifiers.STATIC : 0),
                                /* No constructor */ false);
 
                        aec.CurrentAnonymousMethod = this;
                        ContainerAnonymousMethod = ec.CurrentAnonymousMethod;
                        ContainingBlock = ec.CurrentBlock;
-               
-                       if (aec.ResolveTopBlock (ec, Block, amp, loc, out unreachable))
+
+                       if (aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable))
                                return new AnonymousDelegate (this, delegate_type, loc).Resolve (ec);
 
                        return null;
                }
 
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (!ec.IsAnonymousMethodAllowed) {
+                               Report.Error (1706, loc, "Anonymous methods are not allowed in the attribute declaration");
+                               return null;
+                       }
+
+                       if (Parameters != null && !Parameters.Resolve (ec)) {
+                               return null;
+                       }
+
+                       return base.DoResolve (ec);
+               }
+
+
+               public override string ExprClassName {
+                       get {
+                               return "anonymous method";
+                       }
+               }
+
                public MethodBuilder GetMethodBuilder ()
                {
-                       return method.MethodData.MethodBuilder;
+                       return method.MethodBuilder;
+               }
+
+               public override string GetSignatureForError ()
+               {
+                       string s = TypeManager.CSharpSignature (invoke_mb);
+                       return s.Substring (0, s.IndexOf (".Invoke("));
                }
                
-               public void EmitMethod (EmitContext ec)
+               public bool EmitMethod (EmitContext ec)
                {
-                       if (!CreateMethodHost (ec, invoke_mb.ReturnType))
-                               return;
+                       if (!CreateMethodHost (ec))
+                               return false;
 
                        MethodBuilder builder = GetMethodBuilder ();
                        ILGenerator ig = builder.GetILGenerator ();
                        aec.ig = ig;
                        
-                       Parameters.LabelParameters (aec, builder, loc);
+                       Parameters.ApplyAttributes (builder);
 
                        //
                        // Adjust based on the computed state of the
                        // method from CreateMethodHost
                        
-                       if ((method_modifiers & Modifiers.STATIC) != 0)
-                               aec.IsStatic = true;
+                       aec.MethodIsStatic = (method_modifiers & Modifiers.STATIC) != 0;
                        
-                       aec.EmitMeta (Block, amp);
+                       aec.EmitMeta (Block);
                        aec.EmitResolvedTopBlock (Block, unreachable);
+                       return true;
+               }
+
+               public override void CreateScopeType (EmitContext ec, ScopeInfo scope)
+               {
+                       TypeBuilder container = ec.TypeContainer.TypeBuilder;
+                       string name = String.Format ("<>AnonHelp<{0}>", scope.id);
+
+                       scope.ScopeTypeBuilder = container.DefineNestedType (
+                               name, TypeAttributes.AutoLayout | TypeAttributes.Class |
+                               TypeAttributes.NestedAssembly, TypeManager.object_type, null);
+
+                       Type [] constructor_types = Type.EmptyTypes;
+                       scope.ScopeConstructor = scope.ScopeTypeBuilder.DefineConstructor (
+                               MethodAttributes.Public | MethodAttributes.HideBySig |
+                               MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
+                               CallingConventions.HasThis, constructor_types);
+
+                       TypeManager.RegisterMethod (scope.ScopeConstructor, Parameters.EmptyReadOnlyParameters);
+
+                       ILGenerator cig = scope.ScopeConstructor.GetILGenerator ();
+                       cig.Emit (OpCodes.Ldarg_0);
+                       cig.Emit (OpCodes.Call, TypeManager.object_ctor);
+                       cig.Emit (OpCodes.Ret);
                }
 
                public static void Error_AddressOfCapturedVar (string name, Location loc)
                {
                        Report.Error (1686, loc,
-                                     "Variable {0} is captured in an anonymous method and its address is also being taken: they are exclusive", name);
+                               "Local variable `{0}' or its members cannot have their address taken and be used inside an anonymous method block",
+                               name);
                }
        }
 
@@ -338,12 +482,14 @@ namespace Mono.CSharp {
                public override Expression DoResolve (EmitContext ec)
                {
                        eclass = ExprClass.Value;
+
                        return this;
                }
                
                public override void Emit (EmitContext ec)
                {
-                       am.EmitMethod (ec);
+                       if (!am.EmitMethod (ec))
+                               return;
 
                        //
                        // Now emit the delegate creation.
@@ -351,7 +497,7 @@ namespace Mono.CSharp {
                        if ((am.method.ModFlags & Modifiers.STATIC) == 0)
                                delegate_instance_expression = new AnonymousInstance (am);
                        
-                       Expression ml = Expression.MemberLookup (ec, type, ".ctor", loc);
+                       Expression ml = Expression.MemberLookup (ec.ContainerType, type, ".ctor", loc);
                        constructor_method = ((MethodGroupExpr) ml).Methods [0];
                        delegate_method = am.GetMethodBuilder ();
                        base.Emit (ec);
@@ -421,8 +567,7 @@ namespace Mono.CSharp {
                // Points to the object of type `ScopeTypeBuilder' that
                // holds the data for the scope
                //
-               public LocalBuilder ScopeInstance;
-
+               LocalBuilder scope_instance;
                
                public ScopeInfo (CaptureContext cc, Block b)
                {
@@ -430,7 +575,7 @@ namespace Mono.CSharp {
                        ScopeBlock = b;
                        id = count++;
 
-                       cc.AddScope (this);
+                       cc.RegisterCaptureContext ();
                }
 
                public void AddLocal (LocalInfo li)
@@ -446,12 +591,33 @@ namespace Mono.CSharp {
                        return locals.Contains (li);
                }
                
-               public void AddChild (ScopeInfo si)
+               internal void AddChild (ScopeInfo si)
                {
                        if (children.Contains (si))
                                return;
+
+                       //
+                       // If any of the current children should be a children of `si', move them there
+                       //
+                       ArrayList move_queue = null;
+                       foreach (ScopeInfo child in children){
+                               if (child.ScopeBlock.IsChildOf (si.ScopeBlock)){
+                                       if (move_queue == null)
+                                               move_queue = new ArrayList ();
+                                       move_queue.Add (child);
+                                       child.ParentScope = si;
+                                       si.AddChild (child);
+                               }
+                       }
+                       
                        children.Add (si);
-               }
+
+                       if (move_queue != null){
+                               foreach (ScopeInfo child in move_queue){
+                                       children.Remove (child);
+                               }
+                       }
+               } 
 
                static int indent = 0;
 
@@ -471,7 +637,7 @@ namespace Mono.CSharp {
                        Console.WriteLine ("NeedThis=" + NeedThis);
                        foreach (LocalInfo li in locals){
                                Pad ();
-                               Console.WriteLine ("var {0}", li.Name);
+                               Console.WriteLine ("var {0}", MakeFieldName (li.Name));
                        }
                        
                        foreach (ScopeInfo si in children)
@@ -486,36 +652,22 @@ namespace Mono.CSharp {
                        return String.Format ("<>AnonHelp<{0}>", id);
                }
 
-               public void EmitScopeConstructor ()
+               private string MakeFieldName (string local_name)
                {
-                       Type [] constructor_types = TypeManager.NoTypes;
-                       Parameters constructor_parameters = Parameters.EmptyReadOnlyParameters;
-                       ScopeConstructor = ScopeTypeBuilder.DefineConstructor (
-                               MethodAttributes.Public | MethodAttributes.HideBySig |
-                               MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
-                               CallingConventions.HasThis, constructor_types);
-                       InternalParameters parameter_info = new InternalParameters (constructor_types, constructor_parameters);
-                       TypeManager.RegisterMethod (ScopeConstructor, parameter_info, constructor_types);
-
-                       ILGenerator cig = ScopeConstructor.GetILGenerator ();
-                       cig.Emit (OpCodes.Ldarg_0);
-                       cig.Emit (OpCodes.Call, TypeManager.object_ctor);
-                       cig.Emit (OpCodes.Ret);
+                       return "<" + id + ":" + local_name + ">";
                }
-               
+
                public void EmitScopeType (EmitContext ec)
                {
-                       //EmitDebug ();
+                       // EmitDebug ();
 
                        if (ScopeTypeBuilder != null)
                                return;
                        
                        TypeBuilder container = ec.TypeContainer.TypeBuilder;
 
-                       ScopeTypeBuilder = container.DefineNestedType (
-                               MakeHelperName (), TypeAttributes.AutoLayout | TypeAttributes.Class | TypeAttributes.NestedAssembly,
-                               TypeManager.object_type, null);
-
+                       CaptureContext.Host.CreateScopeType (ec, this);
+                       
                        if (NeedThis)
                                THIS = ScopeTypeBuilder.DefineField ("<>THIS", container, FieldAttributes.Assembly);
 
@@ -523,18 +675,18 @@ namespace Mono.CSharp {
                                if (ParentScope.ScopeTypeBuilder == null){
                                        throw new Exception (String.Format ("My parent has not been initialized {0} and {1}", ParentScope, this));
                                }
-                               
-                               ParentLink = ScopeTypeBuilder.DefineField ("<>parent", ParentScope.ScopeTypeBuilder,
-                                                                          FieldAttributes.Assembly);
+
+                               if (ParentScope.ScopeTypeBuilder != ScopeTypeBuilder)
+                                       ParentLink = ScopeTypeBuilder.DefineField ("<>parent", ParentScope.ScopeTypeBuilder,
+                                                                                  FieldAttributes.Assembly);
                        }
                        
                        if (NeedThis && ParentScope != null)
                                throw new Exception ("I was not expecting THIS && having a parent");
 
-                       foreach (LocalInfo info in locals){
+                       foreach (LocalInfo info in locals)
                                info.FieldBuilder = ScopeTypeBuilder.DefineField (
-                                       info.Name, info.VariableType, FieldAttributes.Assembly);
-                       }
+                                       MakeFieldName (info.Name), info.VariableType, FieldAttributes.Assembly);
 
                        if (HostsParameters){
                                Hashtable captured_parameters = CaptureContext.captured_parameters;
@@ -549,7 +701,6 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       EmitScopeConstructor ();
                        foreach (ScopeInfo si in children){
                                si.EmitScopeType (ec);
                        }
@@ -557,7 +708,7 @@ namespace Mono.CSharp {
 
                public void CloseTypes ()
                {
-                       RootContext.RegisterHelperClass (ScopeTypeBuilder);
+                       RootContext.RegisterCompilerGeneratedType (ScopeTypeBuilder);
                        foreach (ScopeInfo si in children)
                                si.CloseTypes ();
                }
@@ -572,13 +723,23 @@ namespace Mono.CSharp {
                        if (inited)
                                return;
 
-                       ig.Emit (OpCodes.Newobj, (ConstructorInfo) ScopeConstructor);
-                       ScopeInstance = ig.DeclareLocal (ScopeTypeBuilder);
-                       ig.Emit (OpCodes.Stloc, ScopeInstance);
+                       if (ScopeConstructor == null)
+                               throw new Exception ("ScopeConstructor is null for" + this.ToString ());
+                       
+                       if (!CaptureContext.Host.IsIterator) {
+                               scope_instance = ig.DeclareLocal (ScopeTypeBuilder);
+                               ig.Emit (OpCodes.Newobj, (ConstructorInfo) ScopeConstructor);
+                               ig.Emit (OpCodes.Stloc, scope_instance);
+                       }
 
                        if (THIS != null){
-                               ig.Emit (OpCodes.Ldloc, ScopeInstance);
-                               ig.Emit (OpCodes.Ldarg_0);
+                               if (CaptureContext.Host.IsIterator) {
+                                       ig.Emit (OpCodes.Ldarg_0);
+                                       ig.Emit (OpCodes.Ldarg_1);
+                               } else {
+                                       ig.Emit (OpCodes.Ldloc, scope_instance);
+                                       ig.Emit (OpCodes.Ldarg_0);
+                               }
                                ig.Emit (OpCodes.Stfld, THIS);
                        }
 
@@ -586,40 +747,87 @@ namespace Mono.CSharp {
                        // Copy the parameter values, if any
                        //
                        int extra = ec.IsStatic ? 0 : 1;
+                       if (CaptureContext.Host.IsIterator)
+                               extra++;
                        if (HostsParameters){
                                Hashtable captured_parameters = CaptureContext.captured_parameters;
                                
                                foreach (DictionaryEntry de in captured_parameters){
                                        CapturedParameter cp = (CapturedParameter) de.Value;
 
-                                       ig.Emit (OpCodes.Ldloc, ScopeInstance);
+                                       EmitScopeInstance (ig);
                                        ParameterReference.EmitLdArg (ig, cp.Idx + extra);
                                        ig.Emit (OpCodes.Stfld, cp.FieldBuilder);
                                }
                        }
-                       
+
                        if (ParentScope != null){
                                if (!ParentScope.inited)
                                        ParentScope.EmitInitScope (ec);
-                               
-                               //
-                               // Only emit initialization in our capturecontext world
-                               //
-                               if (ParentScope.CaptureContext == CaptureContext){
-                                       ig.Emit (OpCodes.Ldloc, ScopeInstance);
-                                       ig.Emit (OpCodes.Ldloc, ParentScope.ScopeInstance);
-                                       ig.Emit (OpCodes.Stfld, ParentLink);
-                               } else {
-                                       ig.Emit (OpCodes.Ldloc, ScopeInstance);
-                                       ig.Emit (OpCodes.Ldarg_0);
-                                       ig.Emit (OpCodes.Stfld, ParentLink);
+
+                               if (ParentScope.ScopeTypeBuilder != ScopeTypeBuilder) {
+                                       //
+                                       // Only emit initialization in our capturecontext world
+                                       //
+                                       if (ParentScope.CaptureContext == CaptureContext){
+                                               EmitScopeInstance (ig);
+                                               ParentScope.EmitScopeInstance (ig);
+                                               ig.Emit (OpCodes.Stfld, ParentLink);
+                                       } else {
+                                               EmitScopeInstance (ig);
+                                               ig.Emit (OpCodes.Ldarg_0);
+                                               ig.Emit (OpCodes.Stfld, ParentLink);
+                                       }
                                }
                        }
                        inited = true;
                }
 
+               public void EmitScopeInstance (ILGenerator ig)
+               {
+                       if (CaptureContext.Host.IsIterator)
+                               ig.Emit (OpCodes.Ldarg_0);
+                       else {
+                               if (scope_instance == null){
+                                       //
+                                       // This is needed if someone overwrites the Emit method
+                                       // of Statement and manually calls Block.Emit without
+                                       // this snippet first:
+                                       // 
+                                       //   ec.EmitScopeInitFromBlock (The_Block);
+                                       //   The_Block.Emit (ec);
+                                       // 
+
+                                       Console.WriteLine (
+                                               "The scope_instance has not been emitted, this typically means\n" +
+                                               "that inside the compiler someone is calling Block.Emit without\n" +
+                                               "first calling EmitScopeInitFromBlock for the block.  See compiler" +
+                                               "source code for an explanation");
+                                       throw new Exception ("Internal compiler error");
+                                       
+                               }
+                               ig.Emit (OpCodes.Ldloc, scope_instance);
+                       }
+               }
+
+               public static void CheckCycles (string msg, ScopeInfo s)
+               {
+                       ArrayList l = new ArrayList ();
+                       int n = 0;
+                       
+                       for (ScopeInfo p = s; p != null; p = p.ParentScope,n++){
+                               if (l.Contains (p)){
+                                       Console.WriteLine ("Loop detected {0} in {1}", n, msg);
+                                       throw new Exception ();
+                               }
+                               l.Add (p);
+                       }
+               }
+               
                static void DoPath (StringBuilder sb, ScopeInfo start)
                {
+                       CheckCycles ("print", start);
+                       
                        if (start.ParentScope != null){
                                DoPath (sb, start.ParentScope);
                                sb.Append (", ");
@@ -660,9 +868,19 @@ namespace Mono.CSharp {
                // Points to the toplevel block that owns this CaptureContext
                //
                ToplevelBlock toplevel_owner;
+
+               //
+               // All the scopes we capture
+               //
                Hashtable scopes = new Hashtable ();
+
+               //
+               // All the root scopes
+               //
+               ArrayList roots = new ArrayList ();
+               
                bool have_captured_vars = false;
-               ScopeInfo topmost = null;
+               bool referenced_this = false;
 
                //
                // Captured fields
@@ -670,9 +888,10 @@ namespace Mono.CSharp {
                Hashtable captured_fields = new Hashtable ();
                Hashtable captured_variables = new Hashtable ();
                public Hashtable captured_parameters = new Hashtable ();
-               public AnonymousMethod Host;
+               public AnonymousContainer Host;
                
-               public CaptureContext (ToplevelBlock toplevel_owner, Location loc, AnonymousMethod host)
+               public CaptureContext (ToplevelBlock toplevel_owner, Location loc,
+                                      AnonymousContainer host)
                {
                        cc_id = count++;
                        this.toplevel_owner = toplevel_owner;
@@ -688,7 +907,18 @@ namespace Mono.CSharp {
                                DoPath (sb, cc.ParentCaptureContext);
                                sb.Append (".");
                        }
-                       sb.Append (cc_id.ToString ());
+                       sb.Append (cc.cc_id.ToString ());
+               }
+
+               public void ReParent (ToplevelBlock new_toplevel, AnonymousContainer new_host)
+               {
+                       toplevel_owner = new_toplevel;
+                       Host = new_host;
+
+                       for (CaptureContext cc = ParentCaptureContext; cc != null;
+                            cc = cc.ParentCaptureContext) {
+                               cc.Host = new_host;
+                       }
                }
                
                public override string ToString ()
@@ -714,106 +944,34 @@ namespace Mono.CSharp {
                        }
                }
 
-               // Returns the deepest of two scopes
-               public ScopeInfo Deepest (ScopeInfo a, ScopeInfo b)
+               ScopeInfo GetScopeForBlock (Block block)
                {
-                       ScopeInfo p;
-
-                       if (a == null)
-                               return b;
-                       if (b == null)
-                               return a;
-                       if (a == b)
-                               return a;
-
-                       //
-                       // If they Scopes are on the same CaptureContext, we do the double
-                       // checks just so if there is an invariant change in the future,
-                       // we get the exception at the end
-                       //
-                       for (p = a; p != null; p = p.ParentScope)
-                               if (p == b)
-                                       return a;
-                       
-                       for (p = b; p != null; p = p.ParentScope)
-                               if (p == a)
-                                       return b;
-
-                       CaptureContext ca = a.CaptureContext;
-                       CaptureContext cb = b.CaptureContext;
-
-                       for (CaptureContext c = ca; c != null; c = c.ParentCaptureContext)
-                               if (c == cb)
-                                       return a;
-
-                       for (CaptureContext c = cb; c != null; c = c.ParentCaptureContext)
-                               if (c == ca)
-                                       return b;
-                       throw new Exception ("Should never be reached");
-               }
-
-               void AdjustMethodScope (AnonymousMethod am, ScopeInfo scope)
-               {
-                       am.Scope = Deepest (am.Scope, scope);
-               }
-
-               void LinkScope (ScopeInfo scope, int id)
-               {
-                       ScopeInfo parent = (ScopeInfo) scopes [id];
-                       scope.ParentScope = parent;
-                       parent.AddChild (scope);
-
-                       if (scope == topmost)
-                               topmost = parent;
+                       ScopeInfo si = (ScopeInfo) scopes [block.ID];
+                       if (si != null)
+                               return si;
+                       si = new ScopeInfo (this, block);
+                       scopes [block.ID] = si;
+                       return si;
                }
                
-               public void AddLocal (AnonymousMethod am, LocalInfo li)
+               public void AddLocal (AnonymousContainer am, LocalInfo li)
                {
                        if (li.Block.Toplevel != toplevel_owner){
                                ParentCaptureContext.AddLocal (am, li);
                                return;
                        }
-                       int block_id = li.Block.ID;
-                       ScopeInfo scope;
-                       if (scopes [block_id] == null){
-                               scope = new ScopeInfo (this, li.Block);
-                               scopes [block_id] = scope;
-                       } else
-                               scope = (ScopeInfo) scopes [block_id];
-
-                       if (topmost == null){
-                               topmost = scope;
-                       } else {
-                               // Link to parent
-                               for (Block b = scope.ScopeBlock.Parent; b != null; b = b.Parent){
-                                       if (scopes [b.ID] != null){
-                                               LinkScope (scope, b.ID);
-                                               break;
-                                       }
-                               }
-
-                               if (scope.ParentScope == null && ParentCaptureContext != null){
-                                       CaptureContext pcc = ParentCaptureContext;
-                                       
-                                       for (Block b = am.ContainingBlock; b != null; b = b.Parent){
-                                               if (pcc.scopes [b.ID] != null){
-                                                       pcc.LinkScope (scope, b.ID);
-                                                       break;
-                                               }
-                                       }
-                               }
-                       }
+                       ScopeInfo scope = GetScopeForBlock (li.Block);
 
                        //
                        // Adjust the owner
                        //
                        if (Host != null)
-                               AdjustMethodScope (Host, topmost);
+                               Host.RegisterScope (scope);
 
                        //
                        // Adjust the user
                        //
-                       AdjustMethodScope (am, scope);
+                       am.RegisterScope (scope);
                        
                        if (captured_variables [li] != null)
                                return;
@@ -850,7 +1008,8 @@ namespace Mono.CSharp {
                //
                // Records the captured parameter at the appropriate CaptureContext
                //
-               public void AddParameter (EmitContext ec, AnonymousMethod am, string name, Type t, int idx)
+               public void AddParameter (EmitContext ec, AnonymousContainer am,
+                                         string name, Type t, int idx)
                {
                        CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name);
 
@@ -860,53 +1019,50 @@ namespace Mono.CSharp {
                //
                // Records the parameters in the context
                //
-               void AddParameterToContext (AnonymousMethod am, string name, Type t, int idx)
+               public void AddParameterToContext (AnonymousContainer am, string name, Type t, int idx)
                {
                        if (captured_parameters == null)
                                captured_parameters = new Hashtable ();
-                       if (captured_parameters [name] != null)
-                               return;
-                       captured_parameters [name] = new CapturedParameter (t, idx);
+                       if (captured_parameters [name] == null)
+                               captured_parameters [name] = new CapturedParameter (t, idx);
 
-                       if (topmost == null){
-                               //
-                               // Create one ScopeInfo, if there are none.
-                               //
-                               topmost = new ScopeInfo (this, toplevel_owner);
-                               scopes [toplevel_owner.ID] = topmost;
-                       } else {
-                               //
-                               // If the topmost ScopeInfo is not at the topblock level, insert
-                               // a new ScopeInfo there.
-                               //
-                               if (topmost.ScopeBlock != toplevel_owner){
-                                       ScopeInfo par_si = new ScopeInfo (this, toplevel_owner);
-                                       scopes [toplevel_owner.ID] = topmost;
-                                       topmost.ParentScope = par_si;
-                                       topmost = par_si;
-                               }
-                       }
-                       
-                       topmost.HostsParameters = true;
-                       AdjustMethodScope (am, topmost);
+                       ScopeInfo scope = GetScopeForBlock (toplevel_owner);
+                       scope.HostsParameters = true;
+                       am.RegisterScope (scope);
                }
 
                //
                // Captured fields are only recorded on the topmost CaptureContext, because that
                // one is the one linked to the owner of instance fields
                //
-               public void AddField (FieldExpr fe)
+               public void AddField (EmitContext ec, AnonymousContainer am, FieldExpr fe)
                {
                        if (fe.FieldInfo.IsStatic)
                                throw new Exception ("Attempt to register a static field as a captured field");
-                       
                        CaptureContext parent = ParentCaptureContext;
-                       if (parent != null)
-                               parent.AddField (fe);
-                       else
-                               captured_fields [fe] = fe;
+                       if (parent != null) {
+                               parent.AddField (ec, am, fe);
+                               return;
+                       }
+
+                       ScopeInfo scope = GetScopeForBlock (toplevel_owner);
+                       am.RegisterScope (scope);
+               }
+
+               public void CaptureThis (AnonymousContainer am)
+               {
+                       if (am == null)
+                               throw new Exception ("Internal Compiler error: Capturethis called with a null method");
+                       CaptureContext parent = ParentCaptureContext;
+                       if (parent != null) {
+                               parent.CaptureThis (am);
+                               return;
+                       }
+                       referenced_this = true;
+
+                       ScopeInfo scope = GetScopeForBlock (toplevel_owner);
+                       am.RegisterScope (scope);
                }
-               
 
                public bool HaveCapturedVariables {
                        get {
@@ -947,56 +1103,86 @@ namespace Mono.CSharp {
 
                public void EmitAnonymousHelperClasses (EmitContext ec)
                {
-                       if (topmost != null){
-                               topmost.NeedThis = HaveCapturedFields;
-                               topmost.EmitScopeType (ec);
+                       if (roots.Count != 0){
+                               foreach (ScopeInfo root in roots){
+                                       //
+                                       // FIXME: We really should do this in a per-ScopeInfo
+                                       // basis, instead of having the NeedThis applied to
+                                       // all of the roots.
+                                       //
+                                       root.NeedThis = HaveCapturedFields || referenced_this;
+                                       
+                                       root.EmitScopeType (ec);
+                               }
                        } 
                }
 
                public void CloseAnonymousHelperClasses ()
                {
-                       if (topmost != null)
-                               topmost.CloseTypes ();
+                       if (roots.Count != 0)
+                               foreach (ScopeInfo root in roots)
+                                       root.CloseTypes ();
                }
 
-               ScopeInfo GetScopeFromBlock (EmitContext ec, Block b)
+               public void EmitInitScope (EmitContext ec)
                {
-                       ScopeInfo si;
-                       
-                       si = (ScopeInfo) scopes [b.ID];
+                       EmitAnonymousHelperClasses (ec);
+                       if (roots.Count != 0)
+                               foreach (ScopeInfo root in roots)
+                                       root.EmitInitScope (ec);                }
+
+               //
+               // This is called externally when we start emitting code for a block
+               // if the block has a ScopeInfo associated, emit the init code
+               //
+               public void EmitScopeInitFromBlock (EmitContext ec, Block b)
+               {
+                       ScopeInfo si = (ScopeInfo) scopes [b.ID];
                        if (si == null)
-                               throw new Exception ("Si is null for block " + b.ID);
-                       si.EmitInitScope (ec);
+                               return;
 
-                       return si;
+                       si.EmitInitScope (ec);
                }
-
+               
                //
                // Emits the opcodes necessary to load the instance of the captured
                // variable in `li'
                //
-               public void EmitCapturedVariableInstance (EmitContext ec, LocalInfo li, AnonymousMethod am)
+               public void EmitCapturedVariableInstance (EmitContext ec, LocalInfo li,
+                                                         AnonymousContainer am)
                {
                        ILGenerator ig = ec.ig;
                        ScopeInfo si;
-                       
+
                        if (li.Block.Toplevel == toplevel_owner){
-                               si = GetScopeFromBlock (ec, li.Block);
-                               ig.Emit (OpCodes.Ldloc, si.ScopeInstance);
+                               si = (ScopeInfo) scopes [li.Block.ID];
+                               si.EmitScopeInstance (ig);
                                return;
                        }
 
                        si = am.Scope;
                        ig.Emit (OpCodes.Ldarg_0);
                        if (si != null){
+                               if (am.IsIterator && (si.ScopeBlock.Toplevel == li.Block.Toplevel)) {
+                                       return;
+                               }
+
                                while (si.ScopeBlock.ID != li.Block.ID){
                                        if (si.ParentLink != null)
                                                ig.Emit (OpCodes.Ldfld, si.ParentLink);
                                        si = si.ParentScope;
-                                       if (si == null) 
+                                       if (si == null) {
+                                               si = am.Scope;
+                                               Console.WriteLine ("Target: {0} {1}", li.Block.ID, li.Name);
+                                               while (si.ScopeBlock.ID != li.Block.ID){
+                                                       Console.WriteLine ("Trying: {0}", si.ScopeBlock.ID);
+                                                       si = si.ParentScope;
+                                               }
+
                                                throw new Exception (
                                                             String.Format ("Never found block {0} starting at {1} while looking up {2}",
                                                                            li.Block.ID, am.Scope.ScopeBlock.ID, li.Name));
+                                       }
                                }
                        }
                }
@@ -1011,7 +1197,7 @@ namespace Mono.CSharp {
                                cc.EmitParameterInstance (ec, name);
                                return;
                        }
-                       
+
                        CapturedParameter par_info = (CapturedParameter) captured_parameters [name];
                        if (par_info != null){
                                // 
@@ -1021,14 +1207,15 @@ namespace Mono.CSharp {
                        ILGenerator ig = ec.ig;
 
                        ScopeInfo si;
-                       if (ec.CurrentBlock == toplevel_owner){
-                               si = GetScopeFromBlock (ec, toplevel_owner);
-                               ig.Emit (OpCodes.Ldloc, si.ScopeInstance);
-                               return;
+
+                       if (ec.CurrentBlock.Toplevel == toplevel_owner) {
+                               si = (ScopeInfo) scopes [toplevel_owner.ID];
+                               si.EmitScopeInstance (ig);
+                       } else {
+                               si = ec.CurrentAnonymousMethod.Scope;
+                               ig.Emit (OpCodes.Ldarg_0);
                        }
-                       
-                       si = ec.CurrentAnonymousMethod.Scope;
-                       ig.Emit (OpCodes.Ldarg_0);
+
                        if (si != null){
                                while (si.ParentLink != null) {
                                        ig.Emit (OpCodes.Ldfld, si.ParentLink);
@@ -1041,14 +1228,15 @@ namespace Mono.CSharp {
                // Emits the code necessary to load the parameter named `name' within
                // an anonymous method.
                //
-               public void EmitParameter (EmitContext ec, string name)
+               public void EmitParameter (EmitContext ec, string name, bool leave_copy, bool prepared, ref LocalTemporary temp)
                {
                        CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name);
                        if (cc != this){
-                               cc.EmitParameter (ec, name);
+                               cc.EmitParameter (ec, name, leave_copy, prepared, ref temp);
                                return;
                        }
-                       EmitParameterInstance (ec, name);
+                       if (!prepared)
+                               EmitParameterInstance (ec, name);
                        CapturedParameter par_info = (CapturedParameter) captured_parameters [name];
                        if (par_info != null){
                                // 
@@ -1056,27 +1244,40 @@ namespace Mono.CSharp {
                                //
                        }
                        ec.ig.Emit (OpCodes.Ldfld, par_info.FieldBuilder);
+
+                       if (leave_copy){
+                               ec.ig.Emit (OpCodes.Dup);
+                               temp = new LocalTemporary (par_info.FieldBuilder.FieldType);
+                               temp.Store (ec);
+                       }
                }
 
                //
                // Implements the assignment of `source' to the paramenter named `name' within
                // an anonymous method.
                //
-               public void EmitAssignParameter (EmitContext ec, string name, Expression source, bool leave_copy, bool prepare_for_load)
+               public void EmitAssignParameter (EmitContext ec, string name, Expression source, bool leave_copy, bool prepare_for_load, ref LocalTemporary temp)
                {
                        CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name);
                        if (cc != this){
-                               cc.EmitAssignParameter (ec, name, source, leave_copy, prepare_for_load);
+                               cc.EmitAssignParameter (ec, name, source, leave_copy, prepare_for_load, ref temp);
                                return;
                        }
                        ILGenerator ig = ec.ig;
                        CapturedParameter par_info = (CapturedParameter) captured_parameters [name];
 
                        EmitParameterInstance (ec, name);
+                       if (prepare_for_load)
+                               ig.Emit (OpCodes.Dup);
                        source.Emit (ec);
-                       if (leave_copy)
+                       if (leave_copy){
                                ig.Emit (OpCodes.Dup);
+                               temp = new LocalTemporary (par_info.FieldBuilder.FieldType);
+                               temp.Store (ec);
+                       }
                        ig.Emit (OpCodes.Stfld, par_info.FieldBuilder);
+                       if (temp != null)
+                               temp.Emit (ec);
                }
 
                //
@@ -1099,53 +1300,152 @@ namespace Mono.CSharp {
                // The following methods are only invoked on the host for the
                // anonymous method.
                //
-               public void EmitMethodHostInstance (EmitContext target, AnonymousMethod am)
+               public void EmitMethodHostInstance (EmitContext target, AnonymousContainer am)
                {
                        ILGenerator ig = target.ig;
                        ScopeInfo si = am.Scope;
-                       
-                       if (si == null){
+
+                       AnonymousContainer container = am.ContainerAnonymousMethod;
+
+                       if ((si == null) || ((container != null) && (si == container.Scope))) {
                                ig.Emit (OpCodes.Ldarg_0);
                                return;
                        }
 
                        si.EmitInitScope (target);
-                       ig.Emit (OpCodes.Ldloc, si.ScopeInstance);
+                       si.EmitScopeInstance (ig);
                }
 
-               ArrayList all_scopes = new ArrayList ();
-               
-               public void AddScope (ScopeInfo si)
+               public void RegisterCaptureContext ()
                {
-                       all_scopes.Add (si);
                        toplevel_owner.RegisterCaptureContext (this);
                }
 
                //
-               // Links any scopes that were not linked previously
+               // Returs true if `probe' is an ancestor of `scope' in the 
+               // scope chain
                //
-               public void AdjustScopes ()
+               bool IsAncestor (ScopeInfo probe, ScopeInfo scope)
                {
-                       foreach (ScopeInfo scope in all_scopes){
-                               if (scope.ParentScope != null)
-                                       continue;
+                       for (Block b = scope.ScopeBlock.Parent; b != null; b = b.Parent){
+                               if (probe.ScopeBlock == b)
+                                       return true;
+                       }
+                       return false;
+               }
 
-                               for (Block b = scope.ScopeBlock.Parent; b != null; b = b.Parent){
-                                       if (scopes [b.ID] != null){
-                                               LinkScope (scope, b.ID);
-                                               break;
+               //
+               // Returns an ArrayList of ScopeInfos that enumerates all the ancestors
+               // of `scope' found in `scope_list'.
+               //
+               // The value returned is either a ScopeInfo or an Arraylist of ScopeInfos
+               //
+               object GetAncestorScopes (ScopeInfo scope, ScopeInfo [] scope_list)
+               {
+                       object ancestors = null;
+                       
+                       for (int i = 0; i < scope_list.Length; i++){
+                               // Ignore the same scope
+                               if (scope_list [i] == scope)
+                                       continue;
+                               
+                               if (IsAncestor (scope_list [i], scope)){
+                                       if (ancestors == null){
+                                               ancestors = scope_list [i];
+                                               continue;
                                        }
+                                       
+                                       if (ancestors is ScopeInfo){
+                                               object old = ancestors;
+                                               ancestors = new ArrayList (4);
+                                               ((ArrayList)ancestors).Add (old);
+                                       } 
+                                       
+                                       ((ArrayList)ancestors).Add (scope_list [i]);
                                }
+                       }
+                       return ancestors;
+               }
+
+               //
+               // Returns the immediate parent of `scope' from all the captured
+               // scopes found in `scope_list', or null if this is a toplevel scope.
+               //
+               ScopeInfo GetParentScope (ScopeInfo scope, ScopeInfo [] scope_list)
+               {
+                       object ancestors = GetAncestorScopes (scope, scope_list);
+                       if (ancestors == null)
+                               return null;
 
-                               if (scope.ParentScope == null && ParentCaptureContext != null){
-                                       CaptureContext pcc = ParentCaptureContext;
+                       // Single match, thats the parent.
+                       if (ancestors is ScopeInfo)
+                               return (ScopeInfo) ancestors;
+
+                       ArrayList candidates = (ArrayList) ancestors;
+                       ScopeInfo parent = (ScopeInfo) candidates [0];
+                       for (int i = 1; i < candidates.Count; i++){
+                               if (IsAncestor (parent, (ScopeInfo) candidates [i]))
+                                       parent = (ScopeInfo) candidates [i];
+                       }
+                       return parent;
+               }
+               
+               //
+               // Links all the scopes
+               //
+               bool linked;
+               public void LinkScopes ()
+               {
+                       if (linked)
+                               return;
+                       
+                       linked = true;
+                       if (ParentCaptureContext != null)
+                               ParentCaptureContext.LinkScopes ();
+
+                       int scope_count = scopes.Keys.Count;
+                       ScopeInfo [] scope_list = new ScopeInfo [scope_count];
+                       scopes.Values.CopyTo (scope_list, 0);
+
+                       for (int i = 0; i < scope_count; i++){
+                               ScopeInfo parent = GetParentScope (scope_list [i], scope_list);
+
+                               if (parent == null){
+                                       roots.Add (scope_list [i]);
+                                       continue;
+                               }
+
+                               scope_list [i].ParentScope = parent;
+                               parent.AddChild (scope_list [i]);
+                       }
+
+                       //
+                       // Link the roots to their parent containers if any.
+                       //
+                       if (ParentCaptureContext != null && roots.Count != 0){
+                               ScopeInfo one_root = (ScopeInfo) roots [0];
+                               bool found = false;
+                               
+                               foreach (ScopeInfo a_parent_root in ParentCaptureContext.roots){
+                                       if (!IsAncestor (a_parent_root, one_root))
+                                               continue;
+
+                                       found = true;
                                        
-                                       for (Block b = Host.ContainingBlock; b != null; b = b.Parent){
-                                               if (pcc.scopes [b.ID] != null){
-                                                       pcc.LinkScope (scope, b.ID);
-                                                       break;
-                                               }
+                                       // Found, link all the roots to this root
+                                       foreach (ScopeInfo root in roots){
+                                               root.ParentScope = a_parent_root;
+                                               a_parent_root.AddChild (root);
                                        }
+                                       break;
+                               }
+                               if (!found){
+                                       //
+                                       // This is to catch a condition in which it is
+                                       // not possible to determine the containing ScopeInfo
+                                       // from an encapsulating CaptureContext
+                                       //
+                                       throw new Exception ("Internal compiler error: Did not find the parent for the root in the chain");
                                }
                        }
                }