In mcs:
[mono.git] / mcs / mcs / anonymous.cs
index 3b4d54fdb27619ba0c349d7111534777c6369b37..7aead944f6c58c8c825f81972ce96f4985184b3e 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,17 +43,17 @@ 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 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,
@@ -64,9 +65,10 @@ namespace Mono.CSharp {
                //
                // 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 +77,20 @@ namespace Mono.CSharp {
                        //
                        // The order is important: this setups the CaptureContext tree hierarchy.
                        //
+                       if (container == null) {
+                               Report.Error (1706, l, "Anonymous methods are not allowed in attribute declaration");
+                               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 +109,27 @@ namespace Mono.CSharp {
                        return this;
                }
 
+               protected abstract bool CreateMethodHost (EmitContext ec);
+
+               public abstract void CreateScopeType (EmitContext ec, ScopeInfo scope);
+
+               public abstract bool IsIterator {
+                       get;
+               }
+       }
+
+       public class AnonymousMethod : AnonymousContainer
+       {
+               public AnonymousMethod (Parameters parameters, ToplevelBlock container,
+                                       ToplevelBlock block, Location l)
+                       : base (parameters, container, block, l)
+               {
+               }
+
+               public override bool IsIterator {
+                       get { return false; }
+               }
+
                public override void Emit (EmitContext ec)
                {
                        // nothing, as we only exist to not do anything.
@@ -105,7 +138,7 @@ namespace Mono.CSharp {
                //
                // Creates the host for the anonymous method
                //
-               bool CreateMethodHost (EmitContext ec, Type return_type)
+               protected override bool CreateMethodHost (EmitContext ec)
                {
                        //
                        // Crude hack follows: we replace the TypeBuilder during the
@@ -120,7 +153,10 @@ namespace Mono.CSharp {
                                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, Scope 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){
@@ -131,9 +167,9 @@ namespace Mono.CSharp {
 
                        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;
                        
                        //
@@ -186,7 +222,7 @@ namespace Mono.CSharp {
                                                continue;
                                        fixedpars [j] = new Parameter (
                                                new TypeExpression (invoke_pd.ParameterType (i), loc),
-                                               "+" + j, invoke_pd.ParameterModifier (i), null);
+                                               "+" + j, invoke_pd.ParameterModifier (i), null, loc);
                                        j++;
                                }
                                
@@ -194,10 +230,10 @@ namespace Mono.CSharp {
                                if (params_idx != -1){
                                        variable = new Parameter (
                                                new TypeExpression (invoke_pd.ParameterType (params_idx), loc),
-                                               "+" + params_idx, invoke_pd.ParameterModifier (params_idx), null);
+                                               "+" + params_idx, invoke_pd.ParameterModifier (params_idx), null, loc);
                                }
 
-                               Parameters = new Parameters (fixedpars, variable, loc);
+                               Parameters = new Parameters (fixedpars, variable);
                        }
                        
                        //
@@ -208,9 +244,8 @@ namespace Mono.CSharp {
                        
                        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);
+                                       Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
+                                               TypeManager.CSharpName (delegate_type), amp.Count);
                                        Error_ParameterMismatch (delegate_type);
                                }
                                return null;
@@ -219,33 +254,29 @@ namespace Mono.CSharp {
                        for (int i = 0; i < amp.Count; i++){
                                Parameter.Modifier amp_mod = amp.ParameterModifier (i);
 
-                               if ((amp_mod & (Parameter.Modifier.OUT | Parameter.Modifier.REF)) != 0){
-                                       if (!probe){
-                                               Error_ParameterMismatch (delegate_type);
-                                               Report.Error (1677, loc, "Parameter '{0}' should not be declared with the '{1}' keyword", 
+                               if (!probe) {
+                                       if ((amp_mod & (Parameter.Modifier.OUT | Parameter.Modifier.REF)) != 0){
+                                               Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword", 
                                                        i+1, amp.ModifierDesc (i));
+                                               Error_ParameterMismatch (delegate_type);
+                                               return null;
                                        }
-                                       return null;
-                               }
 
-                               if (amp_mod != invoke_pd.ParameterModifier (i)){
-                                       if (!probe){
-                                               Report.Error (1676, loc, 
-                                                     "Signature mismatch in parameter modifier for parameter #0", i + 1);
+                                       if (amp_mod != invoke_pd.ParameterModifier (i)){
+                                               Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
+                                                       i+1, Parameter.GetModifierSignature (invoke_pd.ParameterModifier (i)));
                                                Error_ParameterMismatch (delegate_type);
+                                               return null;
                                        }
-                                       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)));
+                                       if (amp.ParameterType (i) != invoke_pd.ParameterType (i)){
+                                               Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
+                                                       i+1,
+                                                       TypeManager.CSharpName (amp.ParameterType (i)),
+                                                       TypeManager.CSharpName (invoke_pd.ParameterType (i)));
                                                Error_ParameterMismatch (delegate_type);
+                                               return null;
                                        }
-                                       return null;
                                }
                        }
 
@@ -278,27 +309,39 @@ namespace Mono.CSharp {
                        ContainerAnonymousMethod = ec.CurrentAnonymousMethod;
                        ContainingBlock = ec.CurrentBlock;
 
-                       if (aec.ResolveTopBlock (ec, Block, amp, loc, out unreachable))
+                       if (aec.ResolveTopBlock (ec, Block, amp, null, out unreachable))
                                return new AnonymousDelegate (this, delegate_type, loc).Resolve (ec);
 
                        return null;
                }
 
+               public override string ExprClassName {
+                       get {
+                               return "anonymous method";
+                       }
+               }
+
                public MethodBuilder GetMethodBuilder ()
                {
                        return method.MethodData.MethodBuilder;
                }
+
+               public override string GetSignatureForError ()
+               {
+                       string s = TypeManager.CSharpSignature (invoke_mb);
+                       return s.Substring (0, s.IndexOf (".Invoke("));
+               }
                
                public bool EmitMethod (EmitContext ec)
                {
-                       if (!CreateMethodHost (ec, invoke_mb.ReturnType))
+                       if (!CreateMethodHost (ec))
                                return false;
 
                        MethodBuilder builder = GetMethodBuilder ();
                        ILGenerator ig = builder.GetILGenerator ();
                        aec.ig = ig;
                        
-                       Parameters.LabelParameters (aec, builder, loc);
+                       Parameters.LabelParameters (aec, builder);
 
                        //
                        // Adjust based on the computed state of the
@@ -311,10 +354,35 @@ namespace Mono.CSharp {
                        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 = TypeManager.NoTypes;
+                       Parameters constructor_parameters = Parameters.EmptyReadOnlyParameters;
+                       scope.ScopeConstructor = scope.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 (scope.ScopeConstructor, parameter_info, constructor_types);
+
+                       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);
                }
        }
 
@@ -419,8 +487,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)
                {
@@ -444,12 +511,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;
 
@@ -469,7 +557,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)
@@ -484,36 +572,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);
 
@@ -521,18 +595,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;
@@ -547,7 +621,6 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       EmitScopeConstructor ();
                        foreach (ScopeInfo si in children){
                                si.EmitScopeType (ec);
                        }
@@ -570,13 +643,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);
                        }
 
@@ -584,38 +667,50 @@ 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
+                               ig.Emit (OpCodes.Ldloc, scope_instance);
+               }
+
                static void DoPath (StringBuilder sb, ScopeInfo start)
                {
                        if (start.ParentScope != null){
@@ -669,9 +764,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;
@@ -687,7 +783,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 ()
@@ -751,7 +858,7 @@ namespace Mono.CSharp {
                        throw new Exception ("Should never be reached");
                }
 
-               void AdjustMethodScope (AnonymousMethod am, ScopeInfo scope)
+               void AdjustMethodScope (AnonymousContainer am, ScopeInfo scope)
                {
                        am.Scope = Deepest (am.Scope, scope);
                }
@@ -766,7 +873,7 @@ namespace Mono.CSharp {
                                topmost = parent;
                }
                
-               public void AddLocal (AnonymousMethod am, LocalInfo li)
+               public void AddLocal (AnonymousContainer am, LocalInfo li)
                {
                        if (li.Block.Toplevel != toplevel_owner){
                                ParentCaptureContext.AddLocal (am, li);
@@ -784,6 +891,7 @@ namespace Mono.CSharp {
                                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);
@@ -849,7 +957,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);
 
@@ -859,7 +968,7 @@ 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 ();
@@ -878,11 +987,16 @@ namespace Mono.CSharp {
                                // If the topmost ScopeInfo is not at the topblock level, insert
                                // a new ScopeInfo there.
                                //
+                               // FIXME: This code probably should be evolved to be like the code
+                               // in AddLocal
+                               //
                                if (topmost.ScopeBlock != toplevel_owner){
                                        ScopeInfo par_si = new ScopeInfo (this, toplevel_owner);
+                                       ScopeInfo old_top = topmost;
                                        scopes [toplevel_owner.ID] = topmost;
                                        topmost.ParentScope = par_si;
                                        topmost = par_si;
+                                       topmost.AddChild (old_top);
                                }
                        }
                        
@@ -894,16 +1008,25 @@ namespace Mono.CSharp {
                // 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;
+                       }
+
+                       if (topmost == null){
+                               //
+                               // Create one ScopeInfo, if there are none.
+                               //
+                               topmost = new ScopeInfo (this, toplevel_owner);
+                               scopes [toplevel_owner.ID] = topmost;
+                       }
+                       
+                       AdjustMethodScope (am, topmost);
                }
 
                public void CaptureThis ()
@@ -965,6 +1088,13 @@ namespace Mono.CSharp {
                                topmost.CloseTypes ();
                }
 
+               public void EmitInitScope (EmitContext ec)
+               {
+                       EmitAnonymousHelperClasses (ec);
+                       if (topmost != null)
+                               topmost.EmitInitScope (ec);
+               }
+
                ScopeInfo GetScopeFromBlock (EmitContext ec, Block b)
                {
                        ScopeInfo si;
@@ -981,28 +1111,41 @@ namespace Mono.CSharp {
                // 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.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));
+                                       }
                                }
                        }
                }
@@ -1017,7 +1160,7 @@ namespace Mono.CSharp {
                                cc.EmitParameterInstance (ec, name);
                                return;
                        }
-                       
+
                        CapturedParameter par_info = (CapturedParameter) captured_parameters [name];
                        if (par_info != null){
                                // 
@@ -1027,14 +1170,15 @@ namespace Mono.CSharp {
                        ILGenerator ig = ec.ig;
 
                        ScopeInfo si;
-                       if (ec.CurrentBlock == toplevel_owner){
+
+                       if (ec.CurrentBlock.Toplevel == toplevel_owner) {
                                si = GetScopeFromBlock (ec, toplevel_owner);
-                               ig.Emit (OpCodes.Ldloc, si.ScopeInstance);
-                               return;
+                               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);
@@ -1105,18 +1249,18 @@ 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){
                                ig.Emit (OpCodes.Ldarg_0);
                                return;
                        }
 
                        si.EmitInitScope (target);
-                       ig.Emit (OpCodes.Ldloc, si.ScopeInstance);
+                       si.EmitScopeInstance (ig);
                }
 
                ArrayList all_scopes = new ArrayList ();