2007-02-06 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / iterators.cs
index 0b44fd5735014e03bc2033bffc876d8f175a6b3d..c259e530e6aaf5f9d540b6d0f8d371e80fa9e8a2 100644 (file)
@@ -8,7 +8,7 @@
 //
 // TODO:
 //    Flow analysis for Yield.
-//    Emit calls to parent object constructor.
+//    Emit calls to base object constructor.
 //
 // Generics note:
 //    Current should be defined to return T, and IEnumerator.Current returns object
@@ -21,69 +21,84 @@ using System.Reflection.Emit;
 
 namespace Mono.CSharp {
 
-       public interface IIteratorContainer {
-
-               //
-               // Invoked if a yield statement is found in the body
-               //
-               void SetYields ();
-       }
-       
        public class Yield : Statement {
-               public Expression expr;
-               bool in_exc;
-               
+               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;
                        }
-                       if (ec.CurrentBranching.InCatch ()){
-                               Report.Error (1631, loc, "Cannot yield in the body of a " +
-                                             "catch clause");
-                               return false;
-                       }
-                       if (ec.InAnonymousMethod){
-                               Report.Error (1621, loc, "yield statement can not appear " +
-                                             "inside an anonymoud method");
+
+                       for (Block block = ec.CurrentBlock; block != null; block = block.Parent) {
+                               if (!block.Unsafe)
+                                       continue;
+
+                               Report.Error (1629, loc, "Unsafe code may not appear in iterators");
                                return false;
                        }
 
                        //
-                       // FIXME: Missing check for Yield inside try block that contains catch clauses
+                       // We can't use `ec.InUnsafe' here because it's allowed to have an iterator
+                       // inside an unsafe class.  See test-martin-29.cs for an example.
                        //
+                       if (!ec.CurrentAnonymousMethod.IsIterator) {
+                               Report.Error (1621, loc,
+                                             "The yield statement cannot be used inside " +
+                                             "anonymous method blocks");
+                               return false;
+                       }
+
+                       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;
+                       }
+
                        return true;
                }
                
                public override bool Resolve (EmitContext ec)
                {
+                       Report.Debug (64, "RESOLVE YIELD", this, ec, expr, expr.GetType ());
                        expr = expr.Resolve (ec);
                        if (expr == null)
                                return false;
-                       if (!CheckContext (ec, loc))
+
+                       Report.Debug (64, "RESOLVE YIELD #1", this, ec, expr, expr.GetType (),
+                                     ec.CurrentAnonymousMethod, ec.CurrentIterator);
+
+                       if (!CheckContext (ec, loc, false))
                                return false;
 
-                       in_exc = ec.CurrentBranching.InTryOrCatch (false);
-                       Type iterator_type = IteratorHandler.Current.IteratorType;
-                       if (expr.Type != iterator_type){
-                               expr = Convert.ImplicitConversionRequired (ec, expr, iterator_type, loc);
+                       Iterator iterator = ec.CurrentIterator;
+                       if (expr.Type != iterator.IteratorType) {
+                               expr = Convert.ImplicitConversionRequired (
+                                       ec, expr, iterator.IteratorType, loc);
                                if (expr == null)
                                        return false;
                        }
+
+                       ec.CurrentBranching.StealFinallyClauses (ref finally_blocks);
                        return true;
                }
 
                protected override void DoEmit (EmitContext ec)
                {
-                       IteratorHandler.Current.MarkYield (ec, expr, in_exc);
+                       ec.CurrentIterator.MarkYield (ec, expr, finally_blocks);
                }
        }
 
@@ -96,7 +111,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 ();
@@ -105,591 +120,922 @@ namespace Mono.CSharp {
 
                protected override void DoEmit (EmitContext ec)
                {
-                       IteratorHandler.Current.EmitYieldBreak (ec.ig, true);
+                       ec.CurrentIterator.EmitYieldBreak (ec.ig);
                }
        }
 
-       public class IteratorHandler {
-               //
-               // Points to the current iterator handler, will be probed by
-               // Yield and YieldBreak to get their context information
-               //
-               public static IteratorHandler Current;
-               
-               //
-               // The typebuilder to the proxy class we create
-               //
-               TypeBuilder enumerator_proxy_class;
-               TypeBuilder enumerable_proxy_class;
+       public class IteratorHost : RootScopeInfo
+       {
+               public readonly Iterator Iterator;
 
-               //
-               // The type of this iterator, object by default.
-               //
-               public Type IteratorType;
-               
-               //
-               // The members we create on the proxy class
-               //
-               MethodBuilder move_next_method;
-               MethodBuilder reset_method;
-               MethodBuilder get_current_method;
-               MethodBuilder dispose_method;
-               MethodBuilder getenumerator_method;
-               PropertyBuilder current_property;
-               ConstructorBuilder enumerator_proxy_constructor;
-               ConstructorBuilder enumerable_proxy_constructor;
+               TypeExpr iterator_type_expr;
+               Field pc_field;
+               Field current_field;
+               MethodInfo dispose_method;
 
-               //
-               // The PC for the state machine.
-               //
-               FieldBuilder pc_field;
+               TypeExpr enumerator_type;
+               TypeExpr enumerable_type;
+               TypeArguments generic_args;
+               TypeExpr generic_enumerator_type;
+               TypeExpr generic_enumerable_type;
 
-               //
-               // The value computed for Current
-               //
-               FieldBuilder current_field;
+               public IteratorHost (Iterator iterator)
+                       : base (iterator.Container.Toplevel, iterator.Host, iterator.GenericMethod,
+                               iterator.Location)
+               {
+                       this.Iterator = iterator;
+               }
 
-               //
-               // Used to reference fields on the container class (instance methods)
-               //
-               public FieldBuilder this_field;
-               public FieldBuilder enumerable_this_field;
+               public override bool IsIterator {
+                       get { return true; }
+               }
 
-               //
-               // References the parameters
-               //
+               public MethodInfo Dispose {
+                       get { return dispose_method; }
+               }
 
-               public FieldBuilder [] parameter_fields;
-               FieldBuilder [] enumerable_parameter_fields;
-               
-               //
-               // The state as we generate the iterator
-               //
-               ArrayList resume_labels = new ArrayList ();
-               int pc;
-               
-               //
-               // Context from the original method
-               //
-               string name;
-               TypeContainer container;
-               Type return_type;
-               Type [] param_types;
-               InternalParameters parameters;
-               Block original_block;
-               Location loc;
-               int modifiers;
+               public Field PC {
+                       get { return pc_field; }
+               }
 
-               static int proxy_count;
+               public Field CurrentField {
+                       get { return current_field; }
+               }
+
+               public Type IteratorType {
+                       get { return iterator_type_expr.Type; }
+               }
 
-               public void EmitYieldBreak (ILGenerator ig, bool add_return)
+               public override TypeExpr [] GetClassBases (out TypeExpr base_class)
                {
-                       ig.Emit (OpCodes.Ldarg_0);
-                       IntConstant.EmitInt (ig, -1);
-                       ig.Emit (OpCodes.Stfld, pc_field);
-                       if (add_return){
-                               ig.Emit (OpCodes.Ldc_I4_0);
-                               ig.Emit (OpCodes.Ret);
+                       iterator_type_expr = InflateType (Iterator.OriginalIteratorType);
+
+#if GMCS_SOURCE
+                       generic_args = new TypeArguments (Location);
+                       generic_args.Add (iterator_type_expr);
+#endif
+
+                       ArrayList list = new ArrayList ();
+                       if (Iterator.IsEnumerable) {
+                               enumerable_type = new TypeExpression (
+                                       TypeManager.ienumerable_type, Location);
+                               list.Add (enumerable_type);
+
+#if GMCS_SOURCE
+                               generic_enumerable_type = new ConstructedType (
+                                       TypeManager.generic_ienumerable_type,
+                                       generic_args, Location);
+                               list.Add (generic_enumerable_type);
+#endif
                        }
+
+                       enumerator_type = new TypeExpression (
+                               TypeManager.ienumerator_type, Location);
+                       list.Add (enumerator_type);
+
+                       list.Add (new TypeExpression (TypeManager.idisposable_type, Location));
+
+#if GMCS_SOURCE
+                       generic_enumerator_type = new ConstructedType (
+                               TypeManager.generic_ienumerator_type,
+                               generic_args, Location);
+                       list.Add (generic_enumerator_type);
+#endif
+
+                       Bases = list;
+
+                       return base.GetClassBases (out base_class);
                }
 
-               void EmitThrowInvalidOp (ILGenerator ig)
+               protected override bool DoResolveMembers ()
                {
-                       ig.Emit (OpCodes.Newobj, TypeManager.invalid_operation_ctor);
-                       ig.Emit (OpCodes.Throw);
+                       pc_field = CaptureVariable ("$PC", TypeManager.system_int32_expr);
+                       current_field = CaptureVariable ("$current", iterator_type_expr);
+
+#if GMCS_SOURCE
+                       Define_Current (true);
+#endif
+                       Define_Current (false);
+                       new DisposeMethod (this);
+                       Define_Reset ();
+
+                       if (Iterator.IsEnumerable) {
+                               new GetEnumeratorMethod (this, false);
+#if GMCS_SOURCE
+                               new GetEnumeratorMethod (this, true);
+#endif
+                       }
+
+                       return base.DoResolveMembers ();
                }
-               
-               void Create_MoveNext ()
+
+               public void CaptureScopes ()
                {
-                       move_next_method = enumerator_proxy_class.DefineMethod (
-                               "System.IEnumerator.MoveNext",
-                               MethodAttributes.HideBySig | MethodAttributes.NewSlot |
-                               MethodAttributes.Virtual,
-                               CallingConventions.HasThis, TypeManager.bool_type, TypeManager.NoTypes);
-                       enumerator_proxy_class.DefineMethodOverride (move_next_method, TypeManager.bool_movenext_void);
+                       Report.Debug (128, "DEFINE ITERATOR HOST", this, scopes);
+
+                       foreach (ScopeInfo si in scopes)
+                               CaptureScope (si);
+
+                       foreach (ScopeInfo si in scopes) {
+                               if (!si.Define ())
+                                       throw new InternalErrorException ();
+                               if (si.DefineType () == null)
+                                       throw new InternalErrorException ();
+                               if (!si.ResolveType ())
+                                       throw new InternalErrorException ();
+                               if (!si.ResolveMembers ())
+                                       throw new InternalErrorException ();
+                               if (!si.DefineMembers ())
+                                       throw new InternalErrorException ();
+                       }
+               }
 
-                       ILGenerator ig = move_next_method.GetILGenerator ();
-                       EmitContext ec = new EmitContext (
-                               container, loc, ig,
-                               TypeManager.void_type, modifiers);
+               protected override bool DoDefineMembers ()
+               {
+                       if (!base.DoDefineMembers ())
+                               return false;
 
-                       Label dispatcher = ig.DefineLabel ();
-                       ig.Emit (OpCodes.Br, dispatcher);
-                       Label entry_point = ig.DefineLabel ();
-                       ig.MarkLabel (entry_point);
-                       resume_labels.Add (entry_point);
-                       
-                       Current = this;
-                       SymbolWriter sw = CodeGen.SymbolWriter;
-                       if ((sw != null) && !Location.IsNull (loc) && !Location.IsNull (original_block.EndLocation)) {
-                               sw.OpenMethod (container, move_next_method, loc, original_block.EndLocation);
-
-                               ec.EmitTopBlock (original_block, parameters, loc);
-
-                               sw.CloseMethod ();
+                       FetchMethodDispose ();
+
+                       return true;
+               }
+
+               protected override void EmitScopeConstructor (EmitContext ec)
+               {
+                       ec.ig.Emit (OpCodes.Ldarg_0);
+                       ec.ig.Emit (OpCodes.Ldarg_1);
+                       ec.ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
+                       base.EmitScopeConstructor (ec);
+               }
+
+               void FetchMethodDispose ()
+               {
+                       MemberList dispose_list;
+
+                       dispose_list = FindMembers (
+                               CurrentType != null ? CurrentType : TypeBuilder,
+                               MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance,
+                               Type.FilterName, "Dispose");
+
+                       if (dispose_list.Count != 1)
+                               throw new InternalErrorException ("Cannot find Dipose() method.");
+
+                       dispose_method = (MethodInfo) dispose_list [0];
+               }
+
+               void Define_Current (bool is_generic)
+               {
+                       MemberName left;
+                       Expression type;
+
+                       if (is_generic) {
+                               left = new MemberName (
+                                       "System.Collections.Generic.IEnumerator",
+                                       generic_args, Location);
+                               type = iterator_type_expr;
                        } else {
-                               ec.EmitTopBlock (original_block, parameters, loc);
+                               left = new MemberName ("System.Collections.IEnumerator", Location);
+                               type = TypeManager.system_object_expr;
                        }
-                       Current = null;
 
-                       EmitYieldBreak (ig, true);
+                       MemberName name = new MemberName (left, "Current", null, Location);
 
-                       //
-                       // FIXME: Split the switch in blocks that can be consumed by switch.
-                       //
-                       ig.MarkLabel (dispatcher);
-                       
-                       Label [] labels = new Label [resume_labels.Count];
-                       resume_labels.CopyTo (labels);
-                       ig.Emit (OpCodes.Ldarg_0);
-                       ig.Emit (OpCodes.Ldfld, pc_field);
-                       ig.Emit (OpCodes.Switch, labels);
-                       ig.Emit (OpCodes.Ldc_I4_0); 
-                       ig.Emit (OpCodes.Ret); 
+                       ToplevelBlock get_block = new ToplevelBlock (Location);
+                       get_block.AddStatement (new CurrentBlock (this, is_generic));
+
+                       Accessor getter = new Accessor (get_block, 0, null, Location);
+
+                       Property current = new Property (
+                               this, type, 0, false, name, null, getter, null, false);
+                       AddProperty (current);
                }
 
-               // 
-               // 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)
+               void Define_Reset ()
                {
-                       return enumerator_proxy_class.DefineField (pfx + name, t, FieldAttributes.Public);
+                       Method reset = new Method (
+                               this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
+                               false, new MemberName ("Reset", Location),
+                               Parameters.EmptyReadOnlyParameters, null);
+                       AddMethod (reset);
+
+                       reset.Block = new ToplevelBlock (Location);
+                       reset.Block.AddStatement (Create_ThrowNotSupported ());
                }
-               
-               void Create_Reset ()
+
+               Statement Create_ThrowNotSupported ()
+               {
+                       TypeExpr ex_type = new TypeExpression (
+                               TypeManager.not_supported_exception_type, Location);
+
+                       return new Throw (new New (ex_type, null, Location), Location);
+               }
+
+               ConstructorInfo GetInvalidOperationException ()
                {
-                       reset_method = enumerator_proxy_class.DefineMethod (
-                               "System.IEnumerator.Reset",
-                               MethodAttributes.HideBySig | MethodAttributes.NewSlot |
-                               MethodAttributes.Virtual,
-                               CallingConventions.HasThis, TypeManager.void_type, TypeManager.NoTypes);
-                       enumerator_proxy_class.DefineMethodOverride (reset_method, TypeManager.void_reset_void);
-                       ILGenerator ig = reset_method.GetILGenerator ();
-                       EmitThrowInvalidOp (ig);
+                       return TypeManager.GetConstructor (
+                               TypeManager.invalid_operation_exception_type, Type.EmptyTypes);
                }
 
-               void Create_Current ()
+               protected override ScopeInitializer CreateScopeInitializer ()
                {
-                       get_current_method = enumerator_proxy_class.DefineMethod (
-                               "System.IEnumerator.get_Current",
-                               MethodAttributes.HideBySig | MethodAttributes.SpecialName |
-                               MethodAttributes.NewSlot | MethodAttributes.Virtual,
-                               CallingConventions.HasThis, TypeManager.object_type, TypeManager.NoTypes);
-                       enumerator_proxy_class.DefineMethodOverride (get_current_method, TypeManager.object_getcurrent_void);
+                       return new IteratorHostInitializer (this);
+               }
 
-                       current_property = enumerator_proxy_class.DefineProperty (
-                               "Current",
-                               PropertyAttributes.RTSpecialName | PropertyAttributes.SpecialName,
-                               TypeManager.object_type, null);
+               protected class IteratorHostInitializer : RootScopeInitializer
+               {
+                       new public readonly IteratorHost Host;
+                       protected Iterator.State state;
 
-                       current_property.SetGetMethod (get_current_method);
-                       
-                       ILGenerator ig = get_current_method.GetILGenerator ();
+                       public IteratorHostInitializer (IteratorHost host)
+                               : base (host)
+                       {
+                               this.Host = host;
+                       }
 
-                       ig.Emit (OpCodes.Ldarg_0);
-                       ig.Emit (OpCodes.Ldfld, pc_field);
-                       ig.Emit (OpCodes.Ldc_I4_0);
-                       Label return_current = ig.DefineLabel ();
-                       ig.Emit (OpCodes.Bgt, return_current);
-                       EmitThrowInvalidOp (ig);
-                       
-                       ig.MarkLabel (return_current);
-                       ig.Emit (OpCodes.Ldarg_0);
-                       ig.Emit (OpCodes.Ldfld, current_field);
-                       ig.Emit (OpCodes.Ret);
+                       protected override bool DoResolveInternal (EmitContext ec)
+                       {
+                               if (this is EnumeratorScopeInitializer)
+                                       state = Iterator.State.Running;
+                               else if (Host.Iterator.IsEnumerable)
+                                       state = Iterator.State.Uninitialized;
+                               else
+                                       state = Iterator.State.Running;
+
+                               return base.DoResolveInternal (ec);
+                       }
+
+                       protected override void EmitScopeConstructor (EmitContext ec)
+                       {
+                               ec.ig.Emit (OpCodes.Ldc_I4, (int) state);
+                               base.EmitScopeConstructor (ec);
+                       }
                }
 
-               void Create_Dispose ()
+               protected class GetEnumeratorMethod : Method
                {
-                       dispose_method = enumerator_proxy_class.DefineMethod (
-                               "System.IDisposable.Dispose",
-                               MethodAttributes.HideBySig | MethodAttributes.SpecialName |
-                               MethodAttributes.NewSlot | MethodAttributes.Virtual,
-                               CallingConventions.HasThis, TypeManager.void_type, TypeManager.NoTypes);
-                       enumerator_proxy_class.DefineMethodOverride (dispose_method, TypeManager.void_dispose_void);
-                       ILGenerator ig = dispose_method.GetILGenerator (); 
+                       public IteratorHost Host;
 
-                       EmitYieldBreak (ig, false);
-                       ig.Emit (OpCodes.Ret);
-               }
-               
-               void Create_GetEnumerator ()
-               {
-                       getenumerator_method = enumerable_proxy_class.DefineMethod (
-                               "IEnumerable.GetEnumerator",
-                               MethodAttributes.HideBySig | MethodAttributes.SpecialName |
-                               MethodAttributes.NewSlot | MethodAttributes.Virtual,
-                               CallingConventions.HasThis, TypeManager.ienumerator_type, TypeManager.NoTypes);
-
-                       enumerable_proxy_class.DefineMethodOverride  (getenumerator_method, TypeManager.ienumerable_getenumerator_void);
-                       ILGenerator ig = getenumerator_method.GetILGenerator ();
-
-                       ig.Emit (OpCodes.Newobj, (ConstructorInfo) enumerator_proxy_constructor);
-                       if (enumerable_this_field != null || parameters.Count > 0){
-                               LocalBuilder obj = ig.DeclareLocal (enumerator_proxy_class);
-                               ig.Emit (OpCodes.Stloc, obj);
-                               if (enumerable_this_field != null){
-                                       ig.Emit (OpCodes.Ldloc, obj);
-                                       ig.Emit (OpCodes.Ldarg_0);
-                                       ig.Emit (OpCodes.Ldfld, enumerable_this_field);
-                                       ig.Emit (OpCodes.Stfld, this_field);
+                       static MemberName GetMemberName (IteratorHost host, bool is_generic)
+                       {
+                               MemberName left;
+                               if (is_generic) {
+                                       left = new MemberName (
+                                               "System.Collections.Generic.IEnumerable",
+                                               host.generic_args, host.Location);
+                               } else {
+                                       left = new MemberName (
+                                               "System.Collections.IEnumerable", host.Location);
+                               }
+
+                               return new MemberName (left, "GetEnumerator", host.Location);
+                       }
+
+                       public GetEnumeratorMethod (IteratorHost host, bool is_generic)
+                               : base (host, null, is_generic ?
+                                       host.generic_enumerator_type : host.enumerator_type,
+                                       0, false, GetMemberName (host, is_generic),
+                                       Parameters.EmptyReadOnlyParameters, null)
+                       {
+                               this.Host = host;
+
+                               host.AddMethod (this);
+
+                               Block = new ToplevelBlock (host.Iterator.Container.Toplevel, null, Location);
+                               Block.AddStatement (new GetEnumeratorStatement (host, Type));
+                       }
+
+                       public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
+                       {
+                               EmitContext ec = new EmitContext (
+                                       this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
+
+                               ec.CurrentAnonymousMethod = Host.Iterator;
+                               return ec;
+                       }
+
+                       protected class GetEnumeratorStatement : Statement
+                       {
+                               IteratorHost host;
+                               Expression type;
+
+                               ExpressionStatement initializer;
+                               Expression cast;
+                               MethodInfo ce;
+
+                               public GetEnumeratorStatement (IteratorHost host, Expression type)
+                               {
+                                       this.host = host;
+                                       this.type = type;
+                                       loc = host.Location;
+                               }
+
+                               public override bool Resolve (EmitContext ec)
+                               {
+                                       type = type.ResolveAsTypeTerminal (ec, false);
+                                       if ((type == null) || (type.Type == null))
+                                               return false;
+
+                                       initializer = host.GetEnumeratorInitializer (ec);
+                                       if (initializer == null)
+                                               return false;
+
+                                       cast = new ClassCast (initializer, type.Type);
+
+                                       ce = TypeManager.int_interlocked_compare_exchange;
+
+                                       ec.CurrentBranching.CurrentUsageVector.Return ();
+                                       return true;
                                }
-                               
-                               for (int i = 0; i < parameters.Count; i++){
-                                       ig.Emit (OpCodes.Ldloc, obj);   
+
+                               protected override void DoEmit (EmitContext ec)
+                               {
+                                       ILGenerator ig = ec.ig;
+                                       Label label_init = ig.DefineLabel ();
+
+                                       ig.Emit (OpCodes.Ldarg_0);
+                                       ig.Emit (OpCodes.Ldflda, host.PC.FieldBuilder);
+                                       ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Running);
+                                       ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
+                                       ig.Emit (OpCodes.Call, ce);
+
+                                       ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
+                                       ig.Emit (OpCodes.Bne_Un, label_init);
+
                                        ig.Emit (OpCodes.Ldarg_0);
-                                       ig.Emit (OpCodes.Ldfld, enumerable_parameter_fields [i]);
-                                       ig.Emit (OpCodes.Stfld, parameter_fields [i]);
+                                       ig.Emit (OpCodes.Ret);
+
+                                       ig.MarkLabel (label_init);
+
+                                       initializer.EmitStatement (ec);
+                                       cast.Emit (ec);
+                                       ig.Emit (OpCodes.Ret);
                                }
-                               ig.Emit (OpCodes.Ldloc, obj);
                        }
-                       
-                       ig.Emit (OpCodes.Ret);
                }
 
-               //
-               // Called back from Yield
-               //
-               public void MarkYield (EmitContext ec, Expression expr, bool in_exc)
+               protected class DisposeMethod : Method
                {
-                       ILGenerator ig = ec.ig;
+                       public IteratorHost Host;
 
-                       // Store the new current
-                       ig.Emit (OpCodes.Ldarg_0);
-                       expr.Emit (ec);
-                       ig.Emit (OpCodes.Stfld, current_field);
+                       public DisposeMethod (IteratorHost host)
+                               : base (host, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
+                                       false, new MemberName ("Dispose", host.Location),
+                                       Parameters.EmptyReadOnlyParameters, null)
+                       {
+                               this.Host = host;
 
-                       // increment pc
-                       pc++;
-                       ig.Emit (OpCodes.Ldarg_0);
-                       IntConstant.EmitInt (ig, pc);
-                       ig.Emit (OpCodes.Stfld, pc_field);
+                               host.AddMethod (this);
 
-                       // Return ok
-                       ig.Emit (OpCodes.Ldc_I4_1);
-                       
-                       // Find out how to "leave"
-                       if (in_exc || !ec.IsLastStatement){
-                               Type old = ec.ReturnType;
-                               ec.ReturnType = TypeManager.int32_type;
-                               ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
-                               ec.ReturnType = old;
-                       }
-
-                       if (in_exc){
-                               ec.NeedReturnLabel ();
-                               ig.Emit (OpCodes.Leave, ec.ReturnLabel);
-                       } else if (ec.IsLastStatement){
+                               Block = new ToplevelBlock (host.Iterator.Block, null, Location);
+                               Block.AddStatement (new DisposeMethodStatement (Host.Iterator));
+
+                               Report.Debug (64, "DISPOSE METHOD", host, Block);
+                       }
+
+                       public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
+                       {
+                               EmitContext ec = new EmitContext (
+                                       this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
+
+                               ec.CurrentAnonymousMethod = Host.Iterator;
+                               return ec;
+                       }
+
+                       protected class DisposeMethodStatement : Statement
+                       {
+                               Iterator iterator;
+
+                               public DisposeMethodStatement (Iterator iterator)
+                               {
+                                       this.iterator = iterator;
+                                       this.loc = iterator.Location;
+                               }
+
+                               public override bool Resolve (EmitContext ec)
+                               {
+                                       return true;
+                               }
+
+                               protected override void DoEmit (EmitContext ec)
+                               {
+                                       iterator.EmitDispose (ec);
+                               }
+                       }
+               }
+
+               protected ScopeInitializer GetEnumeratorInitializer (EmitContext ec)
+               {
+                       ScopeInitializer init = new EnumeratorScopeInitializer (this);
+                       if (init.Resolve (ec) == null)
+                               throw new InternalErrorException ();
+                       return init;
+               }
+
+               protected class EnumeratorScopeInitializer : IteratorHostInitializer
+               {
+                       IteratorHost host;
+
+                       public EnumeratorScopeInitializer (IteratorHost host)
+                               : base (host)
+                       {
+                               this.host = host;
+                       }
+
+                       protected override bool DoResolveInternal (EmitContext ec)
+                       {
+                               type = host.IsGeneric ? host.CurrentType : host.TypeBuilder;
+                               return base.DoResolveInternal (ec);
+                       }
+
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               DoEmitInstance (ec);
+                       }
+
+                       protected override bool IsGetEnumerator {
+                               get { return true; }
+                       }
+
+                       protected override void EmitParameterReference (EmitContext ec,
+                                                                       CapturedParameter cp)
+                       {
+                               ec.ig.Emit (OpCodes.Ldarg_0);
+                               ec.ig.Emit (OpCodes.Ldfld, cp.Field.FieldBuilder);
+                       }
+               }
+
+               protected class CurrentBlock : Statement {
+                       IteratorHost host;
+                       bool is_generic;
+
+                       public CurrentBlock (IteratorHost host, bool is_generic)
+                       {
+                               this.host = host;
+                               this.is_generic = is_generic;
+                               loc = host.Location;
+                       }
+
+                       public override bool Resolve (EmitContext ec)
+                       {
+                               ec.CurrentBranching.CurrentUsageVector.Return ();
+                               return true;
+                       }
+
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               ILGenerator ig = ec.ig;
+                               Label label_ok = ig.DefineLabel ();
+
+                               ig.Emit (OpCodes.Ldarg_0);
+                               ig.Emit (OpCodes.Ldfld, host.PC.FieldBuilder);
+                               ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Running);
+                               ig.Emit (OpCodes.Bgt, label_ok);
+
+                               ig.Emit (OpCodes.Newobj, host.GetInvalidOperationException ());
+                               ig.Emit (OpCodes.Throw);
+
+                               ig.MarkLabel (label_ok);
+                               ig.Emit (OpCodes.Ldarg_0);
+                               ig.Emit (OpCodes.Ldfld, host.CurrentField.FieldBuilder);
+                               if (!is_generic)
+                                       ig.Emit (OpCodes.Box, host.CurrentField.MemberType);
                                ig.Emit (OpCodes.Ret);
-                       } else {
-                               ec.NeedReturnLabel ();
-                               ig.Emit (OpCodes.Br, ec.ReturnLabel);
                        }
-                       
-                       Label resume_point = ig.DefineLabel ();
-                       ig.MarkLabel (resume_point);
-                       resume_labels.Add (resume_point);
                }
+       }
+
+       public class Iterator : AnonymousContainer {
+               protected readonly ToplevelBlock OriginalBlock;
+               protected readonly IMethodData OriginalMethod;
+               protected ToplevelBlock block;
+
+               public readonly bool IsEnumerable;
+               public readonly bool IsStatic;
 
                //
-               // Creates the IEnumerator Proxy class
+               // The state as we generate the iterator
                //
-               void MakeEnumeratorProxy ()
+               Label move_next_ok, move_next_error;
+               ArrayList resume_points = new ArrayList ();
+               int pc;
+               
+               public readonly Type OriginalIteratorType;
+               public readonly IteratorHost IteratorHost;
+
+               public enum State {
+                       Uninitialized   = -2,
+                       After,
+                       Running
+               }
+
+               public void EmitYieldBreak (ILGenerator ig)
                {
-                       TypeExpr [] proxy_base_interfaces = new TypeExpr [2];
-                       proxy_base_interfaces [0] = new TypeExpression (TypeManager.ienumerator_type, loc);
-                       proxy_base_interfaces [1] = new TypeExpression (TypeManager.idisposable_type, loc);
-                       Type [] proxy_base_itypes = new Type [2];
-                       proxy_base_itypes [0] = TypeManager.ienumerator_type;
-                       proxy_base_itypes [1] = TypeManager.idisposable_type;
-                       TypeBuilder container_builder = container.TypeBuilder;
+                       ig.Emit (OpCodes.Ldarg_0);
+                       IntConstant.EmitInt (ig, (int) State.After);
+                       ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
+                       ig.Emit (OpCodes.Br, move_next_error);
+               }
 
-                       //
-                       // Create the class
-                       //
-                       enumerator_proxy_class = container_builder.DefineNestedType (
-                               "<Enumerator:" + name + ":" + (proxy_count++) + ">",
-                               TypeAttributes.AutoLayout | TypeAttributes.Class |TypeAttributes.NestedPrivate,
-                               TypeManager.object_type, proxy_base_itypes);
+               internal void EmitMoveNext (EmitContext ec, Block original_block)
+               {
+                       ILGenerator ig = ec.ig;
 
-                       TypeManager.RegisterBuilder (enumerator_proxy_class, proxy_base_interfaces);
+                       move_next_ok = ig.DefineLabel ();
+                       move_next_error = ig.DefineLabel ();
 
-                       //
-                       // Define our fields
-                       //
-                       pc_field = enumerator_proxy_class.DefineField ("PC", TypeManager.int32_type, FieldAttributes.Assembly);
-                       current_field = enumerator_proxy_class.DefineField ("current", IteratorType, FieldAttributes.Assembly);
-                       if ((modifiers & Modifiers.STATIC) == 0)
-                               this_field = enumerator_proxy_class.DefineField ("THIS", container.TypeBuilder, FieldAttributes.Assembly);
+                       LocalBuilder retval = ec.GetTemporaryLocal (TypeManager.int32_type);
 
-                       parameter_fields = new FieldBuilder [parameters.Count];
-                       for (int i = 0; i < parameters.Count; i++){
-                               parameter_fields [i] = enumerator_proxy_class.DefineField (
-                                       String.Format ("tor{0}_{1}", i, parameters.ParameterName (i)),
-                                       parameters.ParameterType (i), FieldAttributes.Assembly);
-                       }
-                       
-                       //
-                       // Define a constructor 
-                       //
+                       ig.BeginExceptionBlock ();
+
+                       Label dispatcher = ig.DefineLabel ();
+                       ig.Emit (OpCodes.Br, dispatcher);
 
-                       enumerator_proxy_constructor = enumerator_proxy_class.DefineConstructor (
-                               MethodAttributes.Public | MethodAttributes.HideBySig |
-                               MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
-                               CallingConventions.HasThis, TypeManager.NoTypes);
-                       InternalParameters parameter_info = new InternalParameters (
-                               TypeManager.NoTypes, Parameters.EmptyReadOnlyParameters);
-                       TypeManager.RegisterMethod (enumerator_proxy_constructor, parameter_info, TypeManager.NoTypes);
+                       ResumePoint entry_point = new ResumePoint (null);
+                       resume_points.Add (entry_point);
+                       entry_point.Define (ig);
+
+                       original_block.Emit (ec);
+
+                       EmitYieldBreak (ig);
+
+                       ig.MarkLabel (dispatcher);
+
+                       Label [] labels = new Label [resume_points.Count];
+                       for (int i = 0; i < labels.Length; i++)
+                               labels [i] = ((ResumePoint) resume_points [i]).Label;
 
-                       //
-                       // Our constructor
-                       //
-                       ILGenerator ig = enumerator_proxy_constructor.GetILGenerator ();
                        ig.Emit (OpCodes.Ldarg_0);
-                       ig.Emit (OpCodes.Call, TypeManager.object_ctor);
+                       ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
+                       ig.Emit (OpCodes.Switch, labels);
 
+                       Label end = ig.DefineLabel ();
+
+                       ig.MarkLabel (move_next_error);
+                       ig.Emit (OpCodes.Ldc_I4_0); 
+                       ig.Emit (OpCodes.Stloc, retval);
+                       ig.Emit (OpCodes.Leave, end);
+
+                       ig.MarkLabel (move_next_ok);
+                       ig.Emit (OpCodes.Ldc_I4_1);
+                       ig.Emit (OpCodes.Stloc, retval);
+                       ig.Emit (OpCodes.Leave, end);
+
+                       ig.BeginFaultBlock ();
+
+                       ig.Emit (OpCodes.Ldarg_0);
+                       ig.Emit (OpCodes.Callvirt, IteratorHost.Dispose);
+
+                       ig.EndExceptionBlock ();
+
+                       ig.MarkLabel (end);
+                       ig.Emit (OpCodes.Ldloc, retval);
                        ig.Emit (OpCodes.Ret);
                }
 
-               //
-               // Creates the IEnumerable proxy class
-               //
-               void MakeEnumerableProxy ()
+               public void EmitDispose (EmitContext ec)
                {
-                       TypeBuilder container_builder = container.TypeBuilder;
-                       Type [] proxy_base_interfaces = new Type [1];
-                       proxy_base_interfaces [0] = TypeManager.ienumerable_type;
+                       ILGenerator ig = ec.ig;
 
-                       //
-                       // Creates the Enumerable proxy class.
-                       //
-                       enumerable_proxy_class = container_builder.DefineNestedType (
-                               "<Enumerable:" + name + ":" + (proxy_count++)+ ">",
-                               TypeAttributes.AutoLayout | TypeAttributes.Class |TypeAttributes.NestedPublic,
-                               TypeManager.object_type, proxy_base_interfaces);
+                       Label end = ig.DefineLabel ();
+                       Label dispatcher = ig.DefineLabel ();
+                       ig.Emit (OpCodes.Br, dispatcher);
 
-                       //
-                       // Constructor
-                       //
-                       if ((modifiers & Modifiers.STATIC) == 0){
-                               enumerable_this_field = enumerable_proxy_class.DefineField (
-                                       "THIS", container.TypeBuilder, FieldAttributes.Assembly);
+                       Label [] labels = new Label [resume_points.Count];
+                       for (int i = 0; i < labels.Length; i++) {
+                               ResumePoint point = (ResumePoint) resume_points [i];
+
+                               if (point.FinallyBlocks == null) {
+                                       labels [i] = end;
+                                       continue;
+                               }
+
+                               labels [i] = ig.DefineLabel ();
+                               ig.MarkLabel (labels [i]);
+
+                               ig.BeginExceptionBlock ();
+                               ig.BeginFinallyBlock ();
+
+                               foreach (ExceptionStatement stmt in point.FinallyBlocks) {
+                                       if (stmt != null)
+                                               stmt.EmitFinally (ec);
+                               }
+
+                               ig.EndExceptionBlock ();
+                               ig.Emit (OpCodes.Br, end);
                        }
-                       enumerable_parameter_fields = new FieldBuilder [parameters.Count];
-                       for (int i = 0; i < parameters.Count; i++){
-                               enumerable_parameter_fields [i] = enumerable_proxy_class.DefineField (
-                                       String.Format ("able{0}_{1}", i, parameters.ParameterName (i)),
-                                       parameters.ParameterType (i), FieldAttributes.Assembly);
-                       }
-                       
-                       enumerable_proxy_constructor = enumerable_proxy_class.DefineConstructor (
-                               MethodAttributes.Public | MethodAttributes.HideBySig |
-                               MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
-                               CallingConventions.HasThis, TypeManager.NoTypes);
-                       InternalParameters parameter_info = new InternalParameters (
-                               TypeManager.NoTypes, Parameters.EmptyReadOnlyParameters);
-                       TypeManager.RegisterMethod (enumerable_proxy_constructor, parameter_info, TypeManager.NoTypes);
-                       
-                       ILGenerator ig = enumerable_proxy_constructor.GetILGenerator ();
+
+                       ig.MarkLabel (dispatcher);
+                       ig.Emit (OpCodes.Ldarg_0);
+                       ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
+                       ig.Emit (OpCodes.Switch, labels);
+
                        ig.Emit (OpCodes.Ldarg_0);
-                       ig.Emit (OpCodes.Call, TypeManager.object_ctor);
+                       IntConstant.EmitInt (ig, (int) State.After);
+                       ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
 
-                       ig.Emit (OpCodes.Ret);
+                       ig.MarkLabel (end);
                }
 
-               //
-               // Populates the Enumerator Proxy class
-               //
-               void PopulateProxy ()
+               protected class ResumePoint
                {
-                       RootContext.RegisterHelperClass (enumerator_proxy_class);
-                       
-                       Create_MoveNext ();
-                       Create_Reset ();
-                       Create_Current ();
-                       Create_Dispose ();
+                       public Label Label;
+                       public readonly ExceptionStatement[] FinallyBlocks;
+
+                       public ResumePoint (ArrayList list)
+                       {
+                               if (list != null) {
+                                       FinallyBlocks = new ExceptionStatement [list.Count];
+                                       list.CopyTo (FinallyBlocks, 0);
+                               }
+                       }
 
-                       if (IsIEnumerable (return_type)){
-                               Create_GetEnumerator ();
-                               RootContext.RegisterHelperClass (enumerable_proxy_class);
+                       public void Define (ILGenerator ig)
+                       {
+                               Label = ig.DefineLabel ();
+                               ig.MarkLabel (Label);
                        }
                }
-               
 
                //
-               // This is invoked by the EmitCode hook
+               // Called back from Yield
                //
-               void SetupIterator ()
+               public void MarkYield (EmitContext ec, Expression expr,
+                                      ArrayList finally_blocks)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       // Store the new current
+                       ig.Emit (OpCodes.Ldarg_0);
+                       expr.Emit (ec);
+                       ig.Emit (OpCodes.Stfld, IteratorHost.CurrentField.FieldBuilder);
+
+                       // increment pc
+                       pc++;
+                       ig.Emit (OpCodes.Ldarg_0);
+                       IntConstant.EmitInt (ig, pc);
+                       ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
+
+                       // Return ok
+                       ig.Emit (OpCodes.Br, move_next_ok);
+
+                       ResumePoint point = new ResumePoint (finally_blocks);
+                       resume_points.Add (point);
+                       point.Define (ig);
+               }
+
+               public void MarkFinally (EmitContext ec, ArrayList finally_blocks)
                {
-                       PopulateProxy ();
+                       ILGenerator ig = ec.ig;
+
+                       // increment pc
+                       pc++;
+                       ig.Emit (OpCodes.Ldarg_0);
+                       IntConstant.EmitInt (ig, pc);
+                       ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
+
+                       ResumePoint point = new ResumePoint (finally_blocks);
+                       resume_points.Add (point);
+                       point.Define (ig);
+               }
+
+               public override bool IsIterator {
+                       get { return true; }
+               }
+
+               public override RootScopeInfo RootScope {
+                       get { return IteratorHost; }
+               }
+
+               public override ScopeInfo Scope {
+                       get { return IteratorHost; }
                }
 
                //
                // Our constructor
                //
-               public IteratorHandler (string name, TypeContainer container, Type return_type, Type [] param_types,
-                                       InternalParameters parameters, int modifiers, Location loc)
+               private Iterator (IMethodData m_container, DeclSpace host, GenericMethod generic,
+                                int modifiers, Type iterator_type, bool is_enumerable)
+                       : base (null, host, generic, m_container.ParameterInfo,
+                               new ToplevelBlock (m_container.ParameterInfo, m_container.Location),
+                               m_container.Block, TypeManager.bool_type, modifiers,
+                               m_container.Location)
                {
-                       this.name = name;
-                       this.container = container;
-                       this.return_type = return_type;
-                       this.param_types = param_types;
-                       this.parameters = parameters;
-                       this.modifiers = modifiers;
-                       this.loc = loc;
+                       this.OriginalBlock = m_container.Block;
+                       this.OriginalMethod = m_container;
+                       this.OriginalIteratorType = iterator_type;
+                       this.IsEnumerable = is_enumerable;
+
+                       Report.Debug (64, "NEW ITERATOR", host, generic, OriginalBlock,
+                                     Container, Block);
+
+                       IteratorHost = new IteratorHost (this);
+                       Block.CreateIteratorHost (IteratorHost);
 
-                       IteratorType = TypeManager.object_type;
-                       
-                       RootContext.EmitCodeHook += new RootContext.Hook (SetupIterator);
+                       OriginalBlock.ReParent (Container.Toplevel);
+
+                       m_container.Block = Container.Toplevel;
+
+                       OriginalBlock.MakeIterator (this);
                }
 
-               //
-               // This class is just an expression that evaluates to a type, and the
-               // type is our internal proxy class.  Used in the generated new body
-               // of the original method
-               //
-               class NewInnerType : Expression {
-                       IteratorHandler handler;
-                       
-                       public NewInnerType (IteratorHandler handler, Location l) 
+               protected class TestStatement : Statement
+               {
+                       public override bool Resolve (EmitContext ec)
                        {
-                               this.handler = handler;
-                               eclass = ExprClass.Value;
-                               loc = l;
+                               return true;
                        }
 
-                       public override Expression DoResolve (EmitContext ec)
+                       protected override void DoEmit (EmitContext ec)
                        {
-                               // Create the proxy class type.
-                               handler.MakeEnumeratorProxy ();
+                               ec.ig.Emit (OpCodes.Nop);
+                               ec.ig.Emit (OpCodes.Neg);
+                               ec.ig.Emit (OpCodes.Pop);
+                               ec.ig.Emit (OpCodes.Ret);
+                       }
+               }
+
+               public override string GetSignatureForError ()
+               {
+                       return OriginalMethod.GetSignatureForError ();
+               }
 
-                               if (IsIEnumerable (handler.return_type))
-                                       handler.MakeEnumerableProxy ();
+               public override bool Resolve (EmitContext ec)
+               {
+                       Report.Debug (64, "RESOLVE ITERATOR", this, Container, Block);
+
+                       Parameters parameters = OriginalMethod.ParameterInfo;
+                       for (int i = 0; i < parameters.Count; i++){
+                               Parameter.Modifier mod = parameters.ParameterModifier (i);
+                               if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
+                                       Report.Error (1623, Location,
+                                                     "Iterators cannot have ref or out parameters");
+                                       return false;
+                               }
+
+                               if ((mod & Parameter.Modifier.ARGLIST) != 0) {
+                                       Report.Error (1636, Location,
+                                                     "__arglist is not allowed in parameter list " +
+                                                     "of iterators");
+                                       return false;
+                               }
 
-                               type = handler.return_type;
-                               return this;
+                               if (parameters.ParameterType (i).IsPointer) {
+                                       Report.Error (1637, Location,
+                                                     "Iterators cannot have unsafe parameters or " +
+                                                     "yield types");
+                                       return false;
+                               }
                        }
 
-                       public override Expression ResolveAsTypeStep (EmitContext ec)
-                       {
-                               return DoResolve (ec);
+                       if ((ModFlags & Modifiers.UNSAFE) != 0) {
+                               Report.Error (1629, Location, "Unsafe code may not appear in iterators");
+                               return false;
                        }
 
-                       public override void Emit (EmitContext ec)
+                       if (!base.Resolve (ec))
+                               return false;
+
+                       Report.Debug (64, "RESOLVE ITERATOR #1", this, method, method.Parent,
+                                     RootScope, ec);
+
+                       if (!RootScope.ResolveType ())
+                               return false;
+                       if (!RootScope.ResolveMembers ())
+                               return false;
+                       if (!RootScope.DefineMembers ())
+                               return false;
+
+                       ExpressionStatement scope_init = RootScope.GetScopeInitializer (ec);
+                       Container.AddStatement (new StatementExpression (scope_init));
+                       Expression cast = new ClassCast (scope_init, OriginalMethod.ReturnType);
+                       Container.AddStatement (new NoCheckReturn (cast));
+
+                       return true;
+               }
+
+               protected override Method DoCreateMethodHost (EmitContext ec)
+               {
+                       Report.Debug (128, "CREATE METHOD HOST", this, IteratorHost);
+
+                       IteratorHost.CaptureScopes ();
+
+                       return new AnonymousMethodMethod (
+                               this, RootScope, null, TypeManager.system_boolean_expr,
+                               Modifiers.PUBLIC, new MemberName ("MoveNext", Location),
+                               Parameters.EmptyReadOnlyParameters);
+               }
+
+               protected class MoveNextStatement : Statement {
+                       Iterator iterator;
+
+                       public MoveNextStatement (Iterator iterator, Location loc)
                        {
-                               ILGenerator ig = ec.ig;
-                               FieldBuilder this_field = null;
-                               bool is_ienumerable = IsIEnumerable (handler.return_type);
-                               Type temp_type;
-                               
-                               if (is_ienumerable){
-                                       temp_type = handler.enumerable_proxy_class;
-                                       ig.Emit (OpCodes.Newobj, (ConstructorInfo) handler.enumerable_proxy_constructor);
-                                       this_field = handler.enumerable_this_field;
-                               } else {
-                                       temp_type = handler.enumerator_proxy_class;
-                                       ig.Emit (OpCodes.Newobj, (ConstructorInfo) handler.enumerator_proxy_constructor);
-                                       this_field = handler.this_field;
-                               }
+                               this.loc = loc;
+                               this.iterator = iterator;
+                       }
 
-                               if (this_field == null && handler.parameters.Count == 0)
-                                       return;
-                               
-                               LocalBuilder temp = ec.GetTemporaryLocal (temp_type);
-
-                               ig.Emit (OpCodes.Stloc, temp);
-                               //
-                               // Initialize This
-                               //
-                               int first = 0;
-                               if (this_field != null){
-                                       ig.Emit (OpCodes.Ldloc, temp);
-                                       ig.Emit (OpCodes.Ldarg_0);
-                                       if (handler.container is Struct)
-                                               ig.Emit (OpCodes.Ldobj, handler.container.TypeBuilder);
-                                       ig.Emit (OpCodes.Stfld, this_field);
-                                       first = 1;
-                               }
+                       public override bool Resolve (EmitContext ec)
+                       {
+                               return iterator.OriginalBlock.Resolve (ec);
+                       }
 
-                               for (int i = 0; i < handler.parameters.Count; i++){
-                                       ig.Emit (OpCodes.Ldloc, temp);
-                                       ParameterReference.EmitLdArg (ig, i + first);
-                                       if (is_ienumerable)
-                                               ig.Emit (OpCodes.Stfld, handler.enumerable_parameter_fields [i]);
-                                       else
-                                               ig.Emit (OpCodes.Stfld, handler.parameter_fields [i]);
-                               }
-                               
-                               //
-                               // Initialize fields
-                               //
-                               ig.Emit (OpCodes.Ldloc, temp);
-                               ec.FreeTemporaryLocal (temp, handler.container.TypeBuilder);
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               iterator.EmitMoveNext (ec, iterator.Block);
                        }
                }
 
+               public Type IteratorType {
+                       get { return IteratorHost.IteratorType; }
+               }
+
                //
                // 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)
                        {
+                               Expr = expr;
+                               loc = expr.Location;
                        }
-                       
+
                        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;
                        }
-               }
 
-               static bool IsIEnumerable (Type t)
-               {
-                       return t == TypeManager.ienumerable_type;
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               Expr.Emit (ec);
+                               ec.ig.Emit (OpCodes.Ret);
+                       }
                }
 
-               static bool IsIEnumerator (Type t)
-               {
-                       return t == TypeManager.ienumerator_type;
-               }
-               
-               //
-               // Returns the new block for the method, or null on failure
-               //
-               public Block Setup (Block block)
+               public static Iterator CreateIterator (IMethodData method, DeclSpace parent,
+                                                      GenericMethod generic, int modifiers)
                {
-                       if (!(IsIEnumerator (return_type) || IsIEnumerable (return_type))){
-                               Report.Error (
-                                       1624, loc, "The body of `{0}' cannot be an iterator " +
-                                       "block because '{1}' is not an iterator interface type",
-                                       name, TypeManager.CSharpName (return_type));
+                       bool is_enumerable;
+                       Type iterator_type;
+
+                       if (!CheckType (method.ReturnType, out iterator_type, out is_enumerable)) {
+                               Report.Error (1624, method.Location,
+                                             "The body of `{0}' cannot be an iterator block " +
+                                             "because `{1}' is not an iterator interface type",
+                                             method.GetSignatureForError (),
+                                             TypeManager.CSharpName (method.ReturnType));
                                return null;
                        }
 
-                       for (int i = 0; i < parameters.Count; i++){
-                               Parameter.Modifier mod = parameters.ParameterModifier (i);
-                               if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
-                                       Report.Error (1623, loc, "Iterators cannot have ref " +
-                                                     "or out parameters");
-                                       return null;
-                               }
+                       return new Iterator (method, parent, generic, modifiers,
+                                            iterator_type, is_enumerable);
+               }
+
+               static bool CheckType (Type ret, out Type original_iterator_type, out bool is_enumerable)
+               {
+                       original_iterator_type = null;
+                       is_enumerable = false;
+
+                       if (ret == TypeManager.ienumerable_type) {
+                               original_iterator_type = TypeManager.object_type;
+                               is_enumerable = true;
+                               return true;
                        }
+                       if (ret == TypeManager.ienumerator_type) {
+                               original_iterator_type = TypeManager.object_type;
+                               is_enumerable = false;
+                               return true;
+                       }
+
+#if GMCS_SOURCE
+                       if (!ret.IsGenericType)
+                               return false;
 
-                       original_block = block;
-                       Block b = new Block (null);
+                       Type[] args = TypeManager.GetTypeArguments (ret);
+                       if (args.Length != 1)
+                               return false;
+
+                       Type gt = ret.GetGenericTypeDefinition ();
+                       if (gt == TypeManager.generic_ienumerable_type) {
+                               original_iterator_type = args [0];
+                               is_enumerable = true;
+                               return true;
+                       } else if (gt == TypeManager.generic_ienumerator_type) {
+                               original_iterator_type = args [0];
+                               is_enumerable = false;
+                               return true;
+                       }
+#endif
 
-                       // return new InnerClass ()
-                       b.AddStatement (new NoCheckReturn (new NewInnerType (this, loc), loc));
-                       return b;
+                       return false;
                }
        }
 }