In mcs:
[mono.git] / mcs / gmcs / iterators.cs
index 3593c21ce872f3cc49cbfe959bee5fd61d40a35b..82250f6bb91c6a674bb7c893de85283e02c8d181 100644 (file)
@@ -30,42 +30,42 @@ namespace Mono.CSharp {
        }
        
        public class Yield : Statement {
-               public Expression expr;
+               Expression expr;
                ArrayList finally_blocks;
-               
+
                public Yield (Expression expr, Location l)
                {
                        this.expr = expr;
                        loc = l;
                }
 
-               public static bool CheckContext (EmitContext ec, Location loc)
+               public static bool CheckContext (EmitContext ec, Location loc, bool isYieldBreak)
                {
-                       if (ec.CurrentBranching.InFinally (true)){
+                       if (ec.InFinally) {
                                Report.Error (1625, loc, "Cannot yield in the body of a " +
                                              "finally clause");
                                return false;
-                       } else {
-                               Report.Debug ("Not in finally");
-                       }
+                       } 
                        
                        if (ec.InUnsafe) {
                                Report.Error (1629, loc, "Unsafe code may not appear in iterators");
                                return false;
                        }
-                       if (ec.CurrentBranching.InCatch ()){
-                               Report.Error (1631, loc, "Cannot yield in the body of a " +
-                                             "catch clause");
+
+                       AnonymousContainer am = ec.CurrentAnonymousMethod;
+                       if ((am != null) && !am.IsIterator){
+                               Report.Error (1621, loc, "The yield statement cannot be used inside anonymous method blocks");
                                return false;
                        }
-                       if (ec.CurrentAnonymousMethod != null){
-                               Report.Error (1621, loc, "yield statement can not appear inside an anonymoud method");
+
+                       if (ec.CurrentBranching.InTryWithCatch () && (!isYieldBreak || !ec.InCatch)) {
+                               if (!ec.InCatch)
+                                       Report.Error (1626, loc, "Cannot yield a value in the body of a " +
+                                       "try block with a catch clause");
+                               else
+                                       Report.Error (1631, loc, "Cannot yield a value in the body of a catch clause");
                                return false;
                        }
-
-                       //
-                       // FIXME: Missing check for Yield inside try block that contains catch clauses
-                       //
                        return true;
                }
                
@@ -74,10 +74,12 @@ namespace Mono.CSharp {
                        expr = expr.Resolve (ec);
                        if (expr == null)
                                return false;
-                       if (!CheckContext (ec, loc))
+
+                       if (!CheckContext (ec, loc, false))
                                return false;
 
                        Iterator iterator = ec.CurrentIterator;
+
                        if (expr.Type != iterator.IteratorType){
                                expr = Convert.ImplicitConversionRequired (
                                        ec, expr, iterator.IteratorType, loc);
@@ -104,7 +106,7 @@ namespace Mono.CSharp {
 
                public override bool Resolve (EmitContext ec)
                {
-                       if (!Yield.CheckContext (ec, loc))
+                       if (!Yield.CheckContext (ec, loc, true))
                                return false;
 
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
@@ -118,16 +120,13 @@ namespace Mono.CSharp {
        }
 
        public class Iterator : Class {
-               ToplevelBlock original_block;
-               ToplevelBlock block;
-               string original_name;
+               protected ToplevelBlock original_block;
+               protected ToplevelBlock block;
 
-               Type iterator_type;
+               Type original_iterator_type;
                TypeExpr iterator_type_expr;
                bool is_enumerable;
-               bool is_static;
-
-               Hashtable fields;
+               public readonly bool IsStatic;
 
                //
                // The state as we generate the iterator
@@ -139,19 +138,25 @@ namespace Mono.CSharp {
                //
                // Context from the original method
                //
+               GenericMethod generic_method;
                TypeContainer container;
                TypeExpr current_type;
                Type this_type;
-               Type return_type;
-               InternalParameters parameters;
+               Parameters parameters;
+               Parameters original_parameters;
+               IMethodData orig_method;
 
                MethodInfo dispose_method;
+               MoveNextMethod move_next_method;
+               Constructor ctor;
+               CaptureContext cc;
 
                Expression enumerator_type;
                Expression enumerable_type;
                Expression generic_enumerator_type;
                Expression generic_enumerable_type;
                TypeArguments generic_args;
+               EmitContext ec;
 
                protected enum State {
                        Uninitialized   = -2,
@@ -187,7 +192,8 @@ namespace Mono.CSharp {
                        resume_points.Add (entry_point);
                        entry_point.Define (ig);
 
-                       ec.EmitTopBlock (original_block, parameters, Location);
+                       ec.EmitTopBlock (orig_method, original_block);
+
                        EmitYieldBreak (ig);
 
                        ig.MarkLabel (dispatcher);
@@ -232,7 +238,6 @@ namespace Mono.CSharp {
                        Label dispatcher = ig.DefineLabel ();
                        ig.Emit (OpCodes.Br, dispatcher);
 
-                       ec.RemapToProxy = true;
                        Label [] labels = new Label [resume_points.Count];
                        for (int i = 0; i < labels.Length; i++) {
                                ResumePoint point = (ResumePoint) resume_points [i];
@@ -256,7 +261,6 @@ namespace Mono.CSharp {
                                ig.EndExceptionBlock ();
                                ig.Emit (OpCodes.Br, end);
                        }
-                       ec.RemapToProxy = false;
 
                        ig.MarkLabel (dispatcher);
                        ig.Emit (OpCodes.Ldarg_0);
@@ -290,26 +294,6 @@ namespace Mono.CSharp {
                        }
                }
 
-               // 
-               // Invoked when a local variable declaration needs to be mapped to
-               // a field in our proxy class
-               //
-               // Prefixes registered:
-               //   v_   for EmitContext.MapVariable
-               //   s_   for Storage
-               //
-               public FieldBuilder MapVariable (string pfx, string name, Type t)
-               {
-                       string full_name = pfx + name;
-                       FieldBuilder fb = (FieldBuilder) fields [full_name];
-                       if (fb != null)
-                               return fb;
-
-                       fb = TypeBuilder.DefineField (full_name, t, FieldAttributes.Private);
-                       fields.Add (full_name, fb);
-                       return fb;
-               }
-
                //
                // Called back from Yield
                //
@@ -352,51 +336,70 @@ namespace Mono.CSharp {
                        point.Define (ig);
                }
 
-               private static MemberName MakeProxyName (string name)
+               private static MemberName MakeProxyName (string name, GenericMethod generic, Location loc)
                {
                        int pos = name.LastIndexOf ('.');
                        if (pos > 0)
                                name = name.Substring (pos + 1);
 
-                       return new MemberName ("<" + name + ">__" + (proxy_count++));
+                       string proxy_name = "<" + name + ">__" + (proxy_count++);
+
+                       if (generic != null) {
+                               TypeArguments args = new TypeArguments (loc);
+                               foreach (TypeParameter tparam in generic.CurrentTypeParameters)
+                                       args.Add (new SimpleName (tparam.Name, loc));
+                               return new MemberName (proxy_name, args, loc);
+                       } else
+                               return new MemberName (proxy_name, loc);
                }
 
                //
                // Our constructor
                //
-               public Iterator (TypeContainer container, string name, Type return_type,
-                                InternalParameters parameters,
-                                int modifiers, ToplevelBlock block, Location loc)
-                       : base (container.NamespaceEntry, container, MakeProxyName (name),
-                               (modifiers & Modifiers.UNSAFE) | Modifiers.PRIVATE, null, loc)
+               public Iterator (IMethodData m_container, DeclSpace parent, GenericMethod generic,
+                                int modifiers)
+                       : base (parent.NamespaceEntry, parent,
+                               MakeProxyName (m_container.MethodName.Name, generic, m_container.Location),
+                               (modifiers & Modifiers.UNSAFE) | Modifiers.PRIVATE, null)
                {
-                       this.container = container;
-                       this.return_type = return_type;
-                       this.parameters = parameters;
-                       this.original_name = name;
-                       this.original_block = block;
-                       this.block = new ToplevelBlock (loc);
+                       this.orig_method = m_container;
+
+                       this.generic_method = generic;
+                       this.container = parent.PartialContainer;
+                       this.original_parameters = m_container.ParameterInfo;
+                       this.original_block = orig_method.Block;
+                       this.block = new ToplevelBlock (orig_method.Block, parameters, orig_method.Location);
 
-                       fields = new Hashtable ();
+                       if (generic != null) {
+                               ArrayList constraints = new ArrayList ();
+                               foreach (TypeParameter tparam in generic.TypeParameters)
+                                       constraints.Add (tparam.Constraints);
 
-                       is_static = (modifiers & Modifiers.STATIC) != 0;
+                               SetParameterInfo (constraints);
+                       }
+
+                       IsStatic = (modifiers & Modifiers.STATIC) != 0;
+               }
+
+               public AnonymousContainer Host {
+                       get { return move_next_method; }
                }
 
                public bool DefineIterator ()
                {
-                       ec = new EmitContext (this, Mono.CSharp.Location.Null, null, null, ModFlags);
-
-                       if (!CheckType (return_type)) {
-                               Report.Error (
-                                       1624, Location,
-                                       "The body of `{0}' cannot be an iterator block " +
-                                       "because '{1}' is not an iterator interface type",
-                                       original_name, TypeManager.CSharpName (return_type));
+                       ec = new EmitContext (this, this, Location, null, null, ModFlags);
+                       ec.CurrentAnonymousMethod = move_next_method;
+                       ec.InIterator = true;
+
+                       if (!CheckType ()) {
+                               Report.Error (1624, Location,
+                                       "The body of `{0}' cannot be an iterator block because `{1}' is not an iterator interface type",
+                                       orig_method.GetSignatureForError (), TypeManager.CSharpName (orig_method.ReturnType));
                                return false;
                        }
 
-                       for (int i = 0; i < parameters.Count; i++){
-                               Parameter.Modifier mod = parameters.ParameterModifier (i);
+                       for (int i = 0; i < original_parameters.Count; i++){
+                               Parameter.Modifier mod = original_parameters.ParameterModifier (i);
                                if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
                                        Report.Error (
                                                1623, Location,
@@ -409,7 +412,7 @@ namespace Mono.CSharp {
                                        return false;
                                }
 
-                               if (parameters.ParameterType (i).IsPointer) {
+                               if (original_parameters.ParameterType (i).IsPointer) {
                                        Report.Error (1637, Location, "Iterators cannot have unsafe parameters or yield types");
                                        return false;
                                }
@@ -420,37 +423,9 @@ namespace Mono.CSharp {
                        else
                                this_type = container.TypeBuilder;
 
-                       generic_args = new TypeArguments (Location);
-                       generic_args.Add (new TypeExpression (iterator_type, Location));
-
-                       ArrayList list = new ArrayList ();
-                       if (is_enumerable) {
-                               enumerable_type = new TypeExpression (
-                                       TypeManager.ienumerable_type, Location);
-                               list.Add (enumerable_type);
-
-                               generic_enumerable_type = new ConstructedType (
-                                       TypeManager.generic_ienumerable_type,
-                                       generic_args, Location);
-                               list.Add (generic_enumerable_type);
-                       }
-
-                       enumerator_type = new TypeExpression (
-                               TypeManager.ienumerator_type, Location);
-                       list.Add (enumerator_type);
-
-                       list.Add (new TypeExpression (TypeManager.idisposable_type, Location));
-
-                       generic_enumerator_type = new ConstructedType (
-                               TypeManager.generic_ienumerator_type,
-                               generic_args, Location);
-                       list.Add (generic_enumerator_type);
-
-                       iterator_type_expr = new TypeExpression (iterator_type, Location);
-
                        container.AddIterator (this);
 
-                       Bases = list;
+                       orig_method.Block = block;
                        return true;
                }
 
@@ -471,6 +446,10 @@ namespace Mono.CSharp {
 
                protected override bool DoDefineMembers ()
                {
+                       ec.InIterator = true;
+                       ec.CurrentAnonymousMethod = move_next_method;
+                       ec.capture_context = cc;
+
                        if (!base.DoDefineMembers ())
                                return false;
 
@@ -481,6 +460,123 @@ namespace Mono.CSharp {
                        return true;
                }
 
+               public override bool Define ()
+               {
+                       if (!base.Define ())
+                               return false;
+
+                       ec.InIterator = true;
+                       ec.CurrentAnonymousMethod = move_next_method;
+                       ec.capture_context = cc;
+
+                       ec.TypeContainer = ec.TypeContainer.Parent;
+
+                       if (ec.TypeContainer.CurrentType != null)
+                               ec.ContainerType = ec.TypeContainer.CurrentType;
+                       else
+                               ec.ContainerType = ec.TypeContainer.TypeBuilder;
+
+                       ec.ig = move_next_method.method.MethodBuilder.GetILGenerator ();
+
+                       if (!ctor.Define ())
+                               return false;
+
+                       bool unreachable;
+
+                       if (!ec.ResolveTopBlock (null, original_block, parameters, orig_method, out unreachable))
+                               return false;
+
+                       if (!ec.ResolveTopBlock (null, block, parameters, orig_method, out unreachable))
+                               return false;
+
+                       original_block.CompleteContexts ();
+
+                       cc.EmitAnonymousHelperClasses (ec);
+
+                       return true;
+               }
+
+               TypeExpr InflateType (Type it)
+               {
+                       if (generic_method == null)
+                               return new TypeExpression (it, Location);
+
+                       if (it.IsGenericParameter && (it.DeclaringMethod != null)) {
+                               int pos = it.GenericParameterPosition;
+                               it = CurrentTypeParameters [pos].Type;
+                       } else if (it.IsGenericType) {
+                               Type[] args = it.GetGenericArguments ();
+
+                               TypeArguments inflated = new TypeArguments (Location);
+                               foreach (Type t in args)
+                                       inflated.Add (InflateType (t));
+
+                               return new ConstructedType (it, inflated, Location);
+                       } else if (it.IsArray) {
+                               TypeExpr et_expr = InflateType (it.GetElementType ());
+                               int rank = it.GetArrayRank ();
+
+                               Type et = et_expr.ResolveAsTypeTerminal (ec, false).Type;
+                               it = et.MakeArrayType (rank);
+                       }
+
+                       return new TypeExpression (it, Location);
+               }
+
+               Parameter InflateParameter (Parameter param)
+               {
+                       TypeExpr te = InflateType (param.ParameterType);
+                       return new Parameter (
+                               te, param.Name, param.ModFlags, param.OptAttributes, param.Location);
+               }
+
+               Parameters InflateParameters (Parameters parameters, EmitContext ec)
+               {
+                       int count = parameters.FixedParameters.Length;
+                       if (count == 0)
+                               return Parameters.EmptyReadOnlyParameters;
+                       Parameter[] fixed_params = new Parameter [count];
+                       for (int i = 0; i < count; i++)
+                               fixed_params [i] = InflateParameter (parameters.FixedParameters [i]);
+
+                       return new Parameters (fixed_params, parameters.HasArglist);
+               }
+
+               public override TypeExpr [] GetClassBases (out TypeExpr base_class)
+               {
+                       iterator_type_expr = InflateType (original_iterator_type);
+
+                       generic_args = new TypeArguments (Location);
+                       generic_args.Add (iterator_type_expr);
+
+                       ArrayList list = new ArrayList ();
+                       if (is_enumerable) {
+                               enumerable_type = new TypeExpression (
+                                       TypeManager.ienumerable_type, Location);
+                               list.Add (enumerable_type);
+
+                               generic_enumerable_type = new ConstructedType (
+                                       TypeManager.generic_ienumerable_type,
+                                       generic_args, Location);
+                               list.Add (generic_enumerable_type);
+                       }
+
+                       enumerator_type = new TypeExpression (
+                               TypeManager.ienumerator_type, Location);
+                       list.Add (enumerator_type);
+
+                       list.Add (new TypeExpression (TypeManager.idisposable_type, Location));
+
+                       generic_enumerator_type = new ConstructedType (
+                               TypeManager.generic_ienumerator_type,
+                               generic_args, Location);
+                       list.Add (generic_enumerator_type);
+
+                       Bases = list;
+
+                       return base.GetClassBases (out base_class);
+               }
+
                //
                // Returns the new block for the method, or null on failure
                //
@@ -491,88 +587,98 @@ namespace Mono.CSharp {
                        else
                                current_type = new TypeExpression (TypeBuilder, Location);
 
+                       if (IsGeneric) {
+                               foreach (TypeParameter tparam in TypeParameters)
+                                       tparam.InflateConstraints (current_type.Type);
+                       }
+
+                       parameters = InflateParameters (original_parameters, ec);
+                       if (!parameters.Resolve (ec)) {
+                               // TODO:
+                       }
+
                        Define_Fields ();
-                       Define_Constructor ();
                        Define_Current (false);
                        Define_Current (true);
                        Define_MoveNext ();
                        Define_Reset ();
                        Define_Dispose ();
 
+                       Define_Constructor ();
+
+                       Create_Block ();
+
                        if (is_enumerable) {
                                Define_GetEnumerator (false);
                                Define_GetEnumerator (true);
                        }
 
-                       Create_Block ();
-
                        return base.DefineNestedTypes ();
                }
 
-
                Field pc_field;
                Field current_field;
                Method dispose;
 
-               public Field this_field;
-               public Field[] parameter_fields;
-
                void Create_Block ()
                {
-                       int first = is_static ? 0 : 1;
+                       original_block.SetHaveAnonymousMethods (Location, move_next_method);
+                       block.SetHaveAnonymousMethods (Location, move_next_method);
+
+                       cc = original_block.CaptureContext;
+
+                       int first = IsStatic ? 0 : 1;
 
                        ArrayList args = new ArrayList ();
-                       if (!is_static) {
+                       if (!IsStatic) {
                                Type t = this_type;
                                args.Add (new Argument (
-                                       new ThisParameterReference (t, 0, Location)));
+                                       new ThisParameterReference (t, Location)));
+                               cc.CaptureThis (move_next_method);
                        }
 
-                       args.Add (new Argument (new BoolLiteral (false)));
+                       args.Add (new Argument (new BoolLiteral (false, Location)));
 
                        for (int i = 0; i < parameters.Count; i++) {
-                               Type t = parameters.ParameterType (i);
+                               Type t = original_parameters.ParameterType (i);
+                               Type inflated = parameters.ParameterType (i);
+                               string name = parameters.ParameterName (i);
+
                                args.Add (new Argument (
                                        new SimpleParameterReference (t, first + i, Location)));
-                       }
 
-                       Expression new_expr = new New (current_type, args, Location);
+                               cc.AddParameterToContext (move_next_method, name, inflated, first + i);
+                       }
 
+                       TypeExpr proxy_type;
+                       if (generic_method != null) {
+                               TypeArguments new_args = new TypeArguments (Location);
+                               if (Parent.IsGeneric) {
+                                       foreach (TypeParameter tparam in Parent.TypeParameters)
+                                               new_args.Add (new TypeParameterExpr (tparam, Location));
+                               }
+                               foreach (TypeParameter tparam in generic_method.TypeParameters)
+                                       new_args.Add (new TypeParameterExpr (tparam, Location));
+                               ConstructedType ct = new ConstructedType (CurrentType, new_args, Location);
+                               proxy_type = ct.ResolveAsTypeTerminal (ec, false);
+                       } else
+                               proxy_type = current_type;
+
+                       Expression new_expr = new New (proxy_type, args, Location);
                        block.AddStatement (new NoCheckReturn (new_expr, Location));
                }
 
                void Define_Fields ()
                {
-                       Location loc = Location.Null;
-
                        pc_field = new Field (
-                               this, TypeManager.system_int32_expr, Modifiers.PRIVATE, "PC",
-                               null, null, loc);
+                               this, TypeManager.system_int32_expr, Modifiers.PRIVATE, "$PC",
+                               null, Location);
                        AddField (pc_field);
 
                        current_field = new Field (
-                               this, iterator_type_expr, Modifiers.PRIVATE, "current",
-                               null, null, loc);
+                               this, iterator_type_expr, Modifiers.PRIVATE, "$current",
+                               null, Location);
                        AddField (current_field);
-
-                       if (!is_static) {
-                               this_field = new Field (
-                                       this, new TypeExpression (this_type, loc),
-                                       Modifiers.PRIVATE, "this", null, null, loc);
-                               AddField (this_field);
-                       }
-
-                       parameter_fields = new Field [parameters.Count];
-                       for (int i = 0; i < parameters.Count; i++) {
-                               string fname = String.Format (
-                                       "field{0}_{1}", i, parameters.ParameterName (i));
-
-                               parameter_fields [i] = new Field (
-                                       this,
-                                       new TypeExpression (parameters.ParameterType (i), loc),
-                                       Modifiers.PRIVATE, fname, null, null, loc);
-                               AddField (parameter_fields [i]);
-                       }
                }
 
                void Define_Constructor ()
@@ -581,66 +687,43 @@ namespace Mono.CSharp {
 
                        ArrayList list = new ArrayList ();
 
-                       if (!is_static)
+                       if (!IsStatic)
                                list.Add (new Parameter (
                                        new TypeExpression (this_type, Location),
-                                       "this", Parameter.Modifier.NONE, null));
+                                       "this", Parameter.Modifier.NONE,
+                                       null, Location));
                        list.Add (new Parameter (
-                               TypeManager.system_boolean_expr, "initialized",
-                               Parameter.Modifier.NONE, null));
+                               TypeManager.bool_type, "initialized",
+                               Parameter.Modifier.NONE, null, Location));
 
-                       Parameter[] old_fixed = parameters.Parameters.FixedParameters;
-                       if (old_fixed != null)
-                               list.AddRange (old_fixed);
+                       Parameter[] old_fixed = parameters.FixedParameters;
+                       list.AddRange (old_fixed);
 
                        Parameter[] fixed_params = new Parameter [list.Count];
                        list.CopyTo (fixed_params);
 
-                       ctor_params = new Parameters (
-                               fixed_params, parameters.Parameters.ArrayParameter,
-                               Location);
+                       ctor_params = new Parameters (fixed_params);
 
-                       Constructor ctor = new Constructor (
-                               this, Name, Modifiers.PUBLIC, ctor_params,
-                               new ConstructorBaseInitializer (
-                                       null, Parameters.EmptyReadOnlyParameters, Location),
+                       ctor = new Constructor (
+                               this, MemberName.Name, Modifiers.PUBLIC, ctor_params,
+                               new GeneratedBaseInitializer (Location),
                                Location);
                        AddConstructor (ctor);
 
-                       ToplevelBlock block = ctor.Block = new ToplevelBlock (Location);
-
-                       if (!is_static) {
-                               Type t = this_type;
-
-                               Assign assign = new Assign (
-                                       new FieldExpression (this_field),
-                                       new SimpleParameterReference (t, 1, Location),
-                                       Location);
-
-                               block.AddStatement (new StatementExpression (assign, Location));
-                       }
-
-                       int first = is_static ? 2 : 3;
-
-                       for (int i = 0; i < parameters.Count; i++) {
-                               Type t = parameters.ParameterType (i);
-
-                               Assign assign = new Assign (
-                                       new FieldExpression (parameter_fields [i]),
-                                       new SimpleParameterReference (t, first + i, Location),
-                                       Location);
+                       ctor.Block = new ToplevelBlock (block, parameters, Location);
 
-                               block.AddStatement (new StatementExpression (assign, Location));
-                       }
+                       int first = IsStatic ? 2 : 3;
 
                        State initial = is_enumerable ? State.Uninitialized : State.Running;
-                       block.AddStatement (new SetState (this, initial, Location));
+                       ctor.Block.AddStatement (new SetState (this, initial, Location));
 
-                       block.AddStatement (new If (
+                       ctor.Block.AddStatement (new If (
                                new SimpleParameterReference (
                                        TypeManager.bool_type, first - 1, Location),
                                new SetState (this, State.Running, Location),
                                Location));
+
+                       ctor.Block.AddStatement (new InitScope (this, Location));
                }
 
                Statement Create_ThrowInvalidOperation ()
@@ -666,47 +749,44 @@ namespace Mono.CSharp {
                        if (is_generic) {
                                left = new MemberName (
                                        "System.Collections.Generic.IEnumerator",
-                                       generic_args);
+                                       generic_args, Location);
                                type = iterator_type_expr;
                        } else {
-                               left = new MemberName ("System.Collections.IEnumerator");
+                               left = new MemberName ("System.Collections.IEnumerator", Location);
                                type = TypeManager.system_object_expr;
                        }
 
-                       MemberName name = new MemberName (left, "Current", null);
+                       MemberName name = new MemberName (left, "Current", null, Location);
 
-                       ToplevelBlock get_block = new ToplevelBlock (Location);
+                       ToplevelBlock get_block = new ToplevelBlock (
+                               block, parameters, Location);
 
                        get_block.AddStatement (new If (
                                new Binary (
                                        Binary.Operator.LessThanOrEqual,
-                                       new FieldExpression (pc_field),
-                                       new IntLiteral ((int) State.Running), Location),
+                                       new FieldExpression (this, pc_field),
+                                       new IntLiteral ((int) State.Running, pc_field.Location)),
                                Create_ThrowInvalidOperation (),
                                new Return (
-                                       new FieldExpression (current_field), Location),
+                                       new FieldExpression (this, current_field), Location),
                                Location));
 
                        Accessor getter = new Accessor (get_block, 0, null, Location);
 
                        Property current = new Property (
-                               this, type, 0, false, name, null, getter, null, Location);
+                               this, type, 0, false, name, null, getter, null);
                        AddProperty (current);
                }
 
                void Define_MoveNext ()
                {
-                       Method move_next = new Method (
-                               this, null, TypeManager.system_boolean_expr,
-                               Modifiers.PUBLIC, false, new MemberName ("MoveNext"),
-                               Parameters.EmptyReadOnlyParameters, null,
-                               Location.Null);
-                       AddMethod (move_next);
+                       move_next_method = new MoveNextMethod (this, Location);
 
-                       ToplevelBlock block = move_next.Block = new ToplevelBlock (Location);
+                       original_block.ReParent (block, move_next_method);
 
-                       MoveNextMethod inline = new MoveNextMethod (this, Location);
-                       block.AddStatement (inline);
+                       move_next_method.CreateMethod (ec);
+
+                       AddMethod (move_next_method.method);
                }
 
                void Define_GetEnumerator (bool is_generic)
@@ -716,30 +796,39 @@ namespace Mono.CSharp {
                        if (is_generic) {
                                left = new MemberName (
                                        "System.Collections.Generic.IEnumerable",
-                                       generic_args);
+                                       generic_args, Location);
                                type = generic_enumerator_type;
                        } else {
-                               left = new MemberName ("System.Collections.IEnumerable");
+                               left = new MemberName ("System.Collections.IEnumerable", Location);
                                type = enumerator_type;
                        }
 
-                       MemberName name = new MemberName (left, "GetEnumerator", null);
+                       MemberName name = new MemberName (left, "GetEnumerator", Location);
 
                        Method get_enumerator = new Method (
                                this, null, type, 0, false, name,
-                               Parameters.EmptyReadOnlyParameters, null,
-                               Location.Null);
-                       AddMethod (get_enumerator);
+                               Parameters.EmptyReadOnlyParameters, null);
 
-                       get_enumerator.Block = new ToplevelBlock (Location);
+                       //
+                       // We call append instead of add, as we need to make sure that
+                       // this method is resolved after the MoveNext method, as that one
+                       // triggers the computation of the AnonymousMethod Scope, which is
+                       // required during the code generation of the enumerator
+                       //
+                       AppendMethod (get_enumerator);
+
+                       get_enumerator.Block = new ToplevelBlock (
+                               block, parameters, Location);
+
+                       get_enumerator.Block.SetHaveAnonymousMethods (Location, move_next_method);
 
                        Expression ce = new MemberAccess (
                                new SimpleName ("System.Threading.Interlocked", Location),
-                               "CompareExchange", Location);
+                               "CompareExchange");
 
-                       Expression pc = new FieldExpression (pc_field);
-                       Expression before = new IntLiteral ((int) State.Running);
-                       Expression uninitialized = new IntLiteral ((int) State.Uninitialized);
+                       Expression pc = new FieldExpression (this, pc_field);
+                       Expression before = new IntLiteral ((int) State.Running, Location);
+                       Expression uninitialized = new IntLiteral ((int) State.Uninitialized, Location);
 
                        ArrayList args = new ArrayList ();
                        args.Add (new Argument (pc, Argument.AType.Ref));
@@ -749,20 +838,25 @@ namespace Mono.CSharp {
                        get_enumerator.Block.AddStatement (new If (
                                new Binary (
                                        Binary.Operator.Equality,
-                                       new Invocation (ce, args, Location),
-                                       uninitialized, Location),
-                               new Return (new This (block, Location), Location),
+                                       new Invocation (ce, args),
+                                       uninitialized),
+                               new Return (new ThisParameterReference (type.Type, Location),
+                                           Location),
                                Location));
 
                        args = new ArrayList ();
-                       if (!is_static)
-                               args.Add (new Argument (new FieldExpression (this_field)));
+                       if (!IsStatic) {
+                               args.Add (new Argument (new CapturedThisReference (this, Location)));
+                       }
 
-                       args.Add (new Argument (new BoolLiteral (true)));
+                       args.Add (new Argument (new BoolLiteral (true, Location)));
 
-                       for (int i = 0; i < parameters.Count; i++)
-                               args.Add (new Argument (
-                                                 new FieldExpression (parameter_fields [i])));
+                       for (int i = 0; i < parameters.Count; i++) {
+                               Expression cp = new CapturedParameterReference (
+                                       this, parameters.ParameterType (i),
+                                       parameters.ParameterName (i), Location);
+                               args.Add (new Argument (cp));
+                       }
 
                        Expression new_expr = new New (current_type, args, Location);
                        get_enumerator.Block.AddStatement (new Return (new_expr, Location));
@@ -796,10 +890,10 @@ namespace Mono.CSharp {
                        }
                }
 
-               protected class ThisParameterReference : SimpleParameterReference
+               protected class ThisParameterReference : SimpleParameterReference, IMemoryLocation
                {
-                       public ThisParameterReference (Type type, int idx, Location loc)
-                               : base (type, idx, loc)
+                       public ThisParameterReference (Type type, Location loc)
+                               : base (type, 0, loc)
                        { }
 
                        protected override void DoEmit (EmitContext ec)
@@ -808,26 +902,91 @@ namespace Mono.CSharp {
                                if (ec.TypeContainer is Struct)
                                        ec.ig.Emit (OpCodes.Ldobj, type);
                        }
+
+                       public void AddressOf (EmitContext ec, AddressOp mode)
+                       {
+                               if (ec.TypeContainer is Struct)
+                                       ec.ig.Emit (OpCodes.Ldarga, 0);
+                               else
+                                       ec.ig.Emit (OpCodes.Ldarg, 0);
+                       }
+               }
+
+               protected class CapturedParameterReference : Expression
+               {
+                       Iterator iterator;
+                       string name;
+
+                       public CapturedParameterReference (Iterator iterator, Type type,
+                                                          string name, Location loc)
+                       {
+                               this.iterator = iterator;
+                               this.loc = loc;
+                               this.type = type;
+                               this.name = name;
+                               eclass = ExprClass.Variable;
+                       }
+
+                       public override Expression DoResolve (EmitContext ec)
+                       {
+                               return this;
+                       }
+
+                       public override void Emit (EmitContext ec)
+                       {
+                               ec.CurrentAnonymousMethod = iterator.move_next_method;
+
+                               LocalTemporary dummy = null;
+                               
+                               iterator.cc.EmitParameter (ec, name, false, false, ref dummy);
+                       }
+               }
+
+               protected class CapturedThisReference : Expression
+               {
+                       public CapturedThisReference (Iterator iterator, Location loc)
+                       {
+                               this.loc = loc;
+                               this.type = iterator.this_type;
+                               eclass = ExprClass.Variable;
+                       }
+
+                       public override Expression DoResolve (EmitContext ec)
+                       {
+                               return this;
+                       }
+
+                       public override void Emit (EmitContext ec)
+                       {
+                               ec.EmitThis (false);
+                       }
                }
 
                protected class FieldExpression : Expression
                {
+                       Iterator iterator;
                        Field field;
 
-                       public FieldExpression (Field field)
+                       public FieldExpression (Iterator iterator, Field field)
                        {
+                               this.iterator = iterator;
                                this.field = field;
+                               this.loc = iterator.Location;
                        }
 
                        public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
                        {
-                               return DoResolve (ec);
+                               FieldExpr fexpr = new FieldExpr (field.FieldBuilder, loc);
+                               fexpr.InstanceExpression = new ThisParameterReference (
+                                       iterator.this_type, loc);
+                               return fexpr.ResolveLValue (ec, right_side, loc);
                        }
 
                        public override Expression DoResolve (EmitContext ec)
                        {
                                FieldExpr fexpr = new FieldExpr (field.FieldBuilder, loc);
-                               fexpr.InstanceExpression = ec.GetThis (loc);
+                               fexpr.InstanceExpression = new ThisParameterReference (
+                                       iterator.this_type, loc);
                                return fexpr.Resolve (ec);
                        }
 
@@ -837,36 +996,82 @@ namespace Mono.CSharp {
                        }
                }
 
-               protected class MoveNextMethod : Statement {
+               protected class MoveNextMethod : AnonymousContainer
+               {
                        Iterator iterator;
 
                        public MoveNextMethod (Iterator iterator, Location loc)
+                               : base (iterator.parameters, iterator.original_block, loc)
                        {
-                               this.loc = loc;
                                this.iterator = iterator;
                        }
 
-                       public override bool Resolve (EmitContext ec)
+                       protected override bool CreateMethodHost (EmitContext ec)
                        {
-                               ec.CurrentBranching.CurrentUsageVector.Return ();
+                               method = new Method (
+                                       iterator, null, TypeManager.system_boolean_expr,
+                                       Modifiers.PUBLIC, false, new MemberName ("MoveNext", loc),
+                                       Parameters.EmptyReadOnlyParameters, null);
+
+                               method.Block = Block;
+
+                               MoveNextStatement inline = new MoveNextStatement (iterator, loc);
+                               Block.AddStatement (inline);
+
                                return true;
                        }
 
-                       protected override void DoEmit (EmitContext ec)
+                       public bool CreateMethod (EmitContext ec)
                        {
-                               int code_flags = Modifiers.METHOD_YIELDS;
-                               if (iterator.is_static)
-                                       code_flags |= Modifiers.STATIC;
+                               return CreateMethodHost (ec);
+                       }
+
+                       public override Iterator Iterator {
+                               get { return iterator; }
+                       }
 
-                               code_flags |= iterator.ModFlags & Modifiers.UNSAFE;
+                       public void ComputeHost ()
+                       {
+                               ComputeMethodHost ();
+                       }
+                       
+                       public override bool IsIterator {
+                               get { return true; }
+                       }
 
-                               EmitContext new_ec = new EmitContext (
-                                       iterator.container, loc, ec.ig,
-                                       TypeManager.int32_type, code_flags);
+                       public override void CreateScopeType (EmitContext ec, ScopeInfo scope)
+                       {
+                               scope.ScopeTypeBuilder = iterator.TypeBuilder;
+                               scope.ScopeConstructor = iterator.ctor.ConstructorBuilder;
+                       }
 
-                               new_ec.CurrentIterator = iterator;
+                       public override void Emit (EmitContext ec)
+                       {
+                               throw new InternalErrorException ();
+                       }
+               }
+
+               protected class MoveNextStatement : Statement {
+                       Iterator iterator;
+
+                       public MoveNextStatement (Iterator iterator, Location loc)
+                       {
+                               this.loc = loc;
+                               this.iterator = iterator;
+                       }
+
+                       public override bool Resolve (EmitContext ec)
+                       {
+                               return true;
+                       }
+
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               iterator.move_next_method.ComputeHost ();
+                               ec.CurrentAnonymousMethod = iterator.move_next_method;
+                               ec.InIterator = true;
 
-                               iterator.EmitMoveNext (new_ec);
+                               iterator.EmitMoveNext (ec);
                        }
                }
 
@@ -946,15 +1151,39 @@ namespace Mono.CSharp {
                        }
                }
 
+               protected class InitScope : Statement
+               {
+                       Iterator iterator;
+
+                       public InitScope (Iterator iterator, Location loc)
+                       {
+                               this.iterator = iterator;
+                               this.loc = loc;
+                       }
+
+                       public override bool Resolve (EmitContext ec)
+                       {
+                               return true;
+                       }
+
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               iterator.cc.EmitInitScope (ec);
+                       }
+               }
+
                void Define_Reset ()
                {
                        Method reset = new Method (
                                this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
-                               false, new MemberName ("Reset"),
-                               Parameters.EmptyReadOnlyParameters, null, Location);
+                               false, new MemberName ("Reset", Location),
+                               Parameters.EmptyReadOnlyParameters, null);
                        AddMethod (reset);
 
                        reset.Block = new ToplevelBlock (Location);
+                       reset.Block = new ToplevelBlock (block, parameters, Location);
+                       reset.Block.SetHaveAnonymousMethods (Location, move_next_method);
+
                        reset.Block.AddStatement (Create_ThrowNotSupported ());
                }
 
@@ -962,67 +1191,80 @@ namespace Mono.CSharp {
                {
                        dispose = new Method (
                                this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
-                               false, new MemberName ("Dispose"),
-                               Parameters.EmptyReadOnlyParameters, null, Location);
+                               false, new MemberName ("Dispose", Location),
+                               Parameters.EmptyReadOnlyParameters, null);
                        AddMethod (dispose);
 
-                       dispose.Block = new ToplevelBlock (Location);
-                       dispose.Block.AddStatement (new DisposeMethod (this, Location));
-               }
+                       dispose.Block = new ToplevelBlock (block, parameters, Location);
+                       dispose.Block.SetHaveAnonymousMethods (Location, move_next_method);
 
-               public ToplevelBlock Block {
-                       get { return block; }
+                       dispose.Block.AddStatement (new DisposeMethod (this, Location));
                }
 
                public Type IteratorType {
-                       get { return iterator_type; }
+                       get { return iterator_type_expr.Type; }
                }
 
                //
                // This return statement tricks return into not flagging an error for being
                // used in a Yields method
                //
-               class NoCheckReturn : Return {
-                       public NoCheckReturn (Expression expr, Location loc) : base (expr, loc)
+               class NoCheckReturn : Statement {
+                       public Expression Expr;
+               
+                       public NoCheckReturn (Expression expr, Location l)
                        {
+                               Expr = expr;
+                               loc = l;
                        }
 
                        public override bool Resolve (EmitContext ec)
                        {
-                               ec.InIterator = false;
-                               bool ret_val = base.Resolve (ec);
-                               ec.InIterator = true;
+                               Expr = Expr.Resolve (ec);
+                               if (Expr == null)
+                                       return false;
 
-                               return ret_val;
+                               ec.CurrentBranching.CurrentUsageVector.Return ();
+
+                               return true;
+                       }
+
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               Expr.Emit (ec);
+                               ec.ig.Emit (OpCodes.Ret);
                        }
                }
 
-               bool CheckType (Type t)
+               bool CheckType ()
                {
-                       if (t == TypeManager.ienumerable_type) {
-                               iterator_type = TypeManager.object_type;
+                       Type ret = orig_method.ReturnType;
+
+                       if (ret == TypeManager.ienumerable_type) {
+                               original_iterator_type = TypeManager.object_type;
                                is_enumerable = true;
                                return true;
-                       } else if (t == TypeManager.ienumerator_type) {
-                               iterator_type = TypeManager.object_type;
+                       }
+                       if (ret == TypeManager.ienumerator_type) {
+                               original_iterator_type = TypeManager.object_type;
                                is_enumerable = false;
                                return true;
                        }
 
-                       if (!t.IsGenericInstance)
+                       if (!ret.IsGenericType)
                                return false;
 
-                       Type[] args = TypeManager.GetTypeArguments (t);
+                       Type[] args = TypeManager.GetTypeArguments (ret);
                        if (args.Length != 1)
                                return false;
 
-                       Type gt = t.GetGenericTypeDefinition ();
+                       Type gt = ret.GetGenericTypeDefinition ();
                        if (gt == TypeManager.generic_ienumerable_type) {
-                               iterator_type = args [0];
+                               original_iterator_type = args [0];
                                is_enumerable = true;
                                return true;
                        } else if (gt == TypeManager.generic_ienumerator_type) {
-                               iterator_type = args [0];
+                               original_iterator_type = args [0];
                                is_enumerable = false;
                                return true;
                        }