**** Merged r40732-r40872 from MCS ****
[mono.git] / mcs / gmcs / iterators.cs
index 6f2d32ab29e6e92160953a52c4ef0f8e690c3238..56bb333c94bec63521c23aa16b249520298a98c2 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
@@ -31,7 +31,7 @@ namespace Mono.CSharp {
        
        public class Yield : Statement {
                public Expression expr;
-               bool in_exc;
+               ArrayList finally_blocks;
                
                public Yield (Expression expr, Location l)
                {
@@ -42,15 +42,17 @@ namespace Mono.CSharp {
                public static bool CheckContext (EmitContext ec, Location loc)
                {
                        if (ec.CurrentBranching.InFinally (true)){
-                               Report.Error (-208, loc, "yield statement can not appear in finally clause");
+                               Report.Error (1625, loc, "Cannot yield in the body of a " +
+                                             "finally clause");
                                return false;
                        }
                        if (ec.CurrentBranching.InCatch ()){
-                               Report.Error (-209, loc, "yield statement can not appear in the catch clause");
+                               Report.Error (1631, loc, "Cannot yield in the body of a " +
+                                             "catch clause");
                                return false;
                        }
-                       if (ec.InAnonymousMethod){
-                               Report.Error (-209, loc, "yield statement can not appear inside an anonymoud method");
+                       if (ec.CurrentAnonymousMethod != null){
+                               Report.Error (1621, loc, "yield statement can not appear inside an anonymoud method");
                                return false;
                        }
 
@@ -68,19 +70,21 @@ namespace Mono.CSharp {
                        if (!CheckContext (ec, loc))
                                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);
                }
        }
 
@@ -102,532 +106,859 @@ 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 Iterator : Class {
+               ToplevelBlock original_block;
+               ToplevelBlock block;
+               string original_name;
 
-               //
-               // 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;
+               Type iterator_type;
+               TypeExpr iterator_type_expr;
+               bool is_enumerable;
+               bool is_static;
 
-               //
-               // The PC for the state machine.
-               //
-               FieldBuilder pc_field;
-
-               //
-               // The value computed for Current
-               //
-               FieldBuilder current_field;
+               Hashtable fields;
 
-               //
-               // Used to reference fields on the container class (instance methods)
-               //
-               public FieldBuilder this_field;
-               public FieldBuilder enumerable_this_field;
-
-               //
-               // References the parameters
-               //
-
-               public FieldBuilder [] parameter_fields;
-               FieldBuilder [] enumerable_parameter_fields;
-               
                //
                // The state as we generate the iterator
                //
-               ArrayList resume_labels = new ArrayList ();
+               Label move_next_ok, move_next_error;
+               ArrayList resume_points = new ArrayList ();
                int pc;
                
                //
                // Context from the original method
                //
-               string name;
                TypeContainer container;
+               TypeExpr current_type;
+               Type this_type;
                Type return_type;
                Type [] param_types;
                InternalParameters parameters;
-               Block original_block;
-               Location loc;
-               int modifiers;
+
+               MethodInfo dispose_method;
+
+               Expression enumerator_type;
+               Expression enumerable_type;
+               Expression generic_enumerator_type;
+               Expression generic_enumerable_type;
+               TypeArguments generic_args;
+
+               protected enum State {
+                       Uninitialized   = -2,
+                       After,
+                       Running
+               }
 
                static int proxy_count;
 
-               public void EmitYieldBreak (ILGenerator ig, bool add_return)
+               public void EmitYieldBreak (ILGenerator ig)
                {
                        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);
-                       }
+                       IntConstant.EmitInt (ig, (int) State.After);
+                       ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
+                       ig.Emit (OpCodes.Br, move_next_error);
                }
 
-               void EmitThrowInvalidOp (ILGenerator ig)
-               {
-                       ig.Emit (OpCodes.Newobj, TypeManager.invalid_operation_ctor);
-                       ig.Emit (OpCodes.Throw);
-               }
-               
-               void Create_MoveNext ()
+               public void EmitMoveNext (EmitContext ec)
                {
-                       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);
+                       ILGenerator ig = ec.ig;
 
-                       ILGenerator ig = move_next_method.GetILGenerator ();
-                       EmitContext ec = new EmitContext (
-                               container, loc, ig,
-                               TypeManager.void_type, modifiers);
+                       move_next_ok = ig.DefineLabel ();
+                       move_next_error = ig.DefineLabel ();
+
+                       LocalBuilder retval = ec.GetTemporaryLocal (TypeManager.int32_type);
+
+                       ig.BeginExceptionBlock ();
 
                        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 ();
-                       } else {
-                               ec.EmitTopBlock (original_block, parameters, loc);
-                       }
-                       Current = null;
 
-                       EmitYieldBreak (ig, true);
+                       ResumePoint entry_point = new ResumePoint (null);
+                       resume_points.Add (entry_point);
+                       entry_point.Define (ig);
+
+                       ec.EmitTopBlock (original_block, parameters, Location);
+                       EmitYieldBreak (ig);
 
-                       //
-                       // 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);
+
+                       Label [] labels = new Label [resume_points.Count];
+                       for (int i = 0; i < labels.Length; i++)
+                               labels [i] = ((ResumePoint) resume_points [i]).Label;
+
                        ig.Emit (OpCodes.Ldarg_0);
-                       ig.Emit (OpCodes.Ldfld, pc_field);
+                       ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder);
                        ig.Emit (OpCodes.Switch, labels);
-                       ig.Emit (OpCodes.Ldc_I4_0); 
-                       ig.Emit (OpCodes.Ret); 
-               }
 
-               // 
-               // 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)
-               {
-                       return enumerator_proxy_class.DefineField (pfx + name, t, FieldAttributes.Public);
-               }
-               
-               void Create_Reset ()
-               {
-                       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);
+                       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, dispose_method);
+
+                       ig.EndExceptionBlock ();
+
+                       ig.MarkLabel (end);
+                       ig.Emit (OpCodes.Ldloc, retval);
+                       ig.Emit (OpCodes.Ret);
                }
 
-               void Create_Current ()
+               public void EmitDispose (EmitContext ec)
                {
-                       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);
+                       ILGenerator ig = ec.ig;
+
+                       Label end = ig.DefineLabel ();
+                       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];
 
-                       current_property = enumerator_proxy_class.DefineProperty (
-                               "Current",
-                               PropertyAttributes.RTSpecialName | PropertyAttributes.SpecialName,
-                               TypeManager.object_type, null);
+                               if (point.FinallyBlocks == null) {
+                                       labels [i] = end;
+                                       continue;
+                               }
+
+                               labels [i] = ig.DefineLabel ();
+                               ig.MarkLabel (labels [i]);
+
+                               ig.BeginExceptionBlock ();
+                               ig.BeginFinallyBlock ();
 
-                       current_property.SetGetMethod (get_current_method);
-                       
-                       ILGenerator ig = get_current_method.GetILGenerator ();
+                               foreach (ExceptionStatement stmt in point.FinallyBlocks) {
+                                       if (stmt != null)
+                                               stmt.EmitFinally (ec);
+                               }
+
+                               ig.EndExceptionBlock ();
+                               ig.Emit (OpCodes.Br, end);
+                       }
+                       ec.RemapToProxy = false;
 
+                       ig.MarkLabel (dispatcher);
                        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.Ldfld, pc_field.FieldBuilder);
+                       ig.Emit (OpCodes.Switch, labels);
+
                        ig.Emit (OpCodes.Ldarg_0);
-                       ig.Emit (OpCodes.Ldfld, current_field);
-                       ig.Emit (OpCodes.Ret);
+                       IntConstant.EmitInt (ig, (int) State.After);
+                       ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
+
+                       ig.MarkLabel (end);
                }
 
-               void Create_Dispose ()
+               protected class ResumePoint
                {
-                       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 Label Label;
+                       public readonly ExceptionStatement[] FinallyBlocks;
 
-                       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);
-                               }
-                               
-                               for (int i = 0; i < parameters.Count; i++){
-                                       ig.Emit (OpCodes.Ldloc, obj);   
-                                       ig.Emit (OpCodes.Ldarg_0);
-                                       ig.Emit (OpCodes.Ldfld, enumerable_parameter_fields [i]);
-                                       ig.Emit (OpCodes.Stfld, parameter_fields [i]);
+                       public ResumePoint (ArrayList list)
+                       {
+                               if (list != null) {
+                                       FinallyBlocks = new ExceptionStatement [list.Count];
+                                       list.CopyTo (FinallyBlocks, 0);
                                }
-                               ig.Emit (OpCodes.Ldloc, obj);
                        }
-                       
-                       ig.Emit (OpCodes.Ret);
+
+                       public void Define (ILGenerator ig)
+                       {
+                               Label = ig.DefineLabel ();
+                               ig.MarkLabel (Label);
+                       }
+               }
+
+               // 
+               // 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
                //
-               public void MarkYield (EmitContext ec, Expression expr, bool in_exc)
+               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, current_field);
+                       ig.Emit (OpCodes.Stfld, current_field.FieldBuilder);
 
                        // increment pc
                        pc++;
                        ig.Emit (OpCodes.Ldarg_0);
                        IntConstant.EmitInt (ig, pc);
-                       ig.Emit (OpCodes.Stfld, pc_field);
+                       ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
 
                        // 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){
-                               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);
+                       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)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       // increment pc
+                       pc++;
+                       ig.Emit (OpCodes.Ldarg_0);
+                       IntConstant.EmitInt (ig, pc);
+                       ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
+
+                       ResumePoint point = new ResumePoint (finally_blocks);
+                       resume_points.Add (point);
+                       point.Define (ig);
+               }
+
+               private static MemberName MakeProxyName (string name)
+               {
+                       int pos = name.LastIndexOf ('.');
+                       if (pos > 0)
+                               name = name.Substring (pos + 1);
+
+                       return new MemberName ("<" + name + ">__" + (proxy_count++));
                }
 
                //
-               // Creates the IEnumerator Proxy class
+               // Our constructor
                //
-               void MakeEnumeratorProxy ()
+               public Iterator (TypeContainer container, string name, Type return_type,
+                                Type [] param_types, InternalParameters parameters,
+                                int modifiers, ToplevelBlock block, Location loc)
+                       : base (container.NamespaceEntry, container, MakeProxyName (name),
+                               Modifiers.PRIVATE, null, loc)
                {
-                       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;
+                       this.container = container;
+                       this.return_type = return_type;
+                       this.param_types = param_types;
+                       this.parameters = parameters;
+                       this.original_name = name;
+                       this.original_block = block;
+                       this.block = new ToplevelBlock (loc);
 
-                       //
-                       // 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);
+                       fields = new Hashtable ();
 
-                       TypeManager.RegisterBuilder (enumerator_proxy_class, proxy_base_interfaces);
+                       is_static = (modifiers & Modifiers.STATIC) != 0;
+               }
 
-                       //
-                       // 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);
+               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));
+                               return false;
+                       }
 
-                       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);
+                               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;
+                               }
                        }
-                       
-                       //
-                       // Define a constructor 
-                       //
 
-                       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);
+                       if (container.CurrentType != null)
+                               this_type = container.CurrentType;
+                       else
+                               this_type = container.TypeBuilder;
 
-                       //
-                       // Our constructor
-                       //
-                       ILGenerator ig = enumerator_proxy_constructor.GetILGenerator ();
-                       ig.Emit (OpCodes.Ldarg_0);
-                       ig.Emit (OpCodes.Call, TypeManager.object_ctor);
+                       generic_args = new TypeArguments (Location);
+                       generic_args.Add (new TypeExpression (iterator_type, Location));
 
-                       ig.Emit (OpCodes.Ret);
+                       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;
+                       return true;
+               }
+
+               MethodInfo FetchMethodDispose ()
+               {
+                       MemberList dispose_list;
+
+                       dispose_list = FindMembers (
+                               current_type.Type,
+                               MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance,
+                               Type.FilterName, "Dispose");
+
+                       if (dispose_list.Count != 1)
+                               throw new InternalErrorException ("Cannot find Dipose() method.");
+
+                       return (MethodInfo) dispose_list [0];
+               }
+
+               protected override bool DoDefineMembers ()
+               {
+                       if (!base.DoDefineMembers ())
+                               return false;
+
+                       dispose_method = FetchMethodDispose ();
+                       if (dispose_method == null)
+                               return false;
+
+                       return true;
                }
 
                //
-               // Creates the IEnumerable proxy class
+               // Returns the new block for the method, or null on failure
                //
-               void MakeEnumerableProxy ()
+               protected override bool DefineNestedTypes ()
                {
-                       TypeBuilder container_builder = container.TypeBuilder;
-                       Type [] proxy_base_interfaces = new Type [1];
-                       proxy_base_interfaces [0] = TypeManager.ienumerable_type;
+                       if (CurrentType != null)
+                               current_type = new TypeExpression (CurrentType, Location);
+                       else
+                               current_type = new TypeExpression (TypeBuilder, Location);
+
+                       Define_Fields ();
+                       Define_Constructor ();
+                       Define_Current (false);
+                       Define_Current (true);
+                       Define_MoveNext ();
+                       Define_Reset ();
+                       Define_Dispose ();
+
+                       if (is_enumerable) {
+                               Define_GetEnumerator (false);
+                               Define_GetEnumerator (true);
+                       }
 
-                       //
-                       // 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);
+                       Create_Block ();
 
-                       //
-                       // Constructor
-                       //
-                       if ((modifiers & Modifiers.STATIC) == 0){
-                               enumerable_this_field = enumerable_proxy_class.DefineField (
-                                       "THIS", container.TypeBuilder, FieldAttributes.Assembly);
+                       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;
+
+                       ArrayList args = new ArrayList ();
+                       if (!is_static) {
+                               Type t = this_type;
+                               args.Add (new Argument (
+                                       new ThisParameterReference (t, 0, Location)));
                        }
-                       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.Emit (OpCodes.Ldarg_0);
-                       ig.Emit (OpCodes.Call, TypeManager.object_ctor);
 
-                       ig.Emit (OpCodes.Ret);
+                       args.Add (new Argument (new BoolLiteral (false)));
+
+                       for (int i = 0; i < parameters.Count; i++) {
+                               Type t = parameters.ParameterType (i);
+                               args.Add (new Argument (
+                                       new SimpleParameterReference (t, first + i, Location)));
+                       }
+
+                       Expression new_expr = new New (current_type, args, Location);
+
+                       block.AddStatement (new NoCheckReturn (new_expr, Location));
                }
 
-               //
-               // Populates the Enumerator Proxy class
-               //
-               void PopulateProxy ()
+               void Define_Fields ()
                {
-                       RootContext.RegisterHelperClass (enumerator_proxy_class);
-                       
-                       Create_MoveNext ();
-                       Create_Reset ();
-                       Create_Current ();
-                       Create_Dispose ();
+                       Location loc = Location.Null;
+
+                       pc_field = new Field (
+                               this, TypeManager.system_int32_expr, Modifiers.PRIVATE, "PC",
+                               null, null, loc);
+                       AddField (pc_field);
+
+                       current_field = new Field (
+                               this, iterator_type_expr, Modifiers.PRIVATE, "current",
+                               null, null, loc);
+                       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);
+                       }
 
-                       if (IsIEnumerable (return_type)){
-                               Create_GetEnumerator ();
-                               RootContext.RegisterHelperClass (enumerable_proxy_class);
+                       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]);
                        }
                }
-               
 
-               //
-               // This is invoked by the EmitCode hook
-               //
-               void SetupIterator ()
+               void Define_Constructor ()
+               {
+                       Parameters ctor_params;
+
+                       ArrayList list = new ArrayList ();
+
+                       if (!is_static)
+                               list.Add (new Parameter (
+                                       new TypeExpression (this_type, Location),
+                                       "this", Parameter.Modifier.NONE, null));
+                       list.Add (new Parameter (
+                               TypeManager.system_boolean_expr, "initialized",
+                               Parameter.Modifier.NONE, null));
+
+                       Parameter[] old_fixed = parameters.Parameters.FixedParameters;
+                       if (old_fixed != null)
+                               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);
+
+                       Constructor ctor = new Constructor (
+                               this, Name, Modifiers.PUBLIC, ctor_params,
+                               new ConstructorBaseInitializer (
+                                       null, Parameters.EmptyReadOnlyParameters, 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);
+
+                               block.AddStatement (new StatementExpression (assign, Location));
+                       }
+
+                       State initial = is_enumerable ? State.Uninitialized : State.Running;
+                       block.AddStatement (new SetState (this, initial, Location));
+
+                       block.AddStatement (new If (
+                               new SimpleParameterReference (
+                                       TypeManager.bool_type, first - 1, Location),
+                               new SetState (this, State.Running, Location),
+                               Location));
+               }
+
+               Statement Create_ThrowInvalidOperation ()
                {
-                       PopulateProxy ();
+                       TypeExpr ex_type = new TypeExpression (
+                               TypeManager.invalid_operation_exception_type, Location);
+
+                       return new Throw (new New (ex_type, null, Location), Location);
                }
 
-               //
-               // Our constructor
-               //
-               public IteratorHandler (string name, TypeContainer container, Type return_type, Type [] param_types,
-                                       InternalParameters parameters, int modifiers, Location loc)
+               Statement Create_ThrowNotSupported ()
                {
-                       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;
+                       TypeExpr ex_type = new TypeExpression (
+                               TypeManager.not_supported_exception_type, Location);
 
-                       IteratorType = TypeManager.object_type;
-                       
-                       RootContext.EmitCodeHook += new RootContext.Hook (SetupIterator);
+                       return new Throw (new New (ex_type, null, Location), Location);
                }
 
-               //
-               // 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) 
+               void Define_Current (bool is_generic)
+               {
+                       MemberName left;
+                       Expression type;
+                       if (is_generic) {
+                               left = new MemberName (
+                                       "System.Collections.Generic.IEnumerator",
+                                       generic_args);
+                               type = iterator_type_expr;
+                       } else {
+                               left = new MemberName ("System.Collections.IEnumerator");
+                               type = TypeManager.system_object_expr;
+                       }
+
+                       MemberName name = new MemberName (left, "Current", null);
+
+                       ToplevelBlock get_block = new ToplevelBlock (Location);
+
+                       get_block.AddStatement (new If (
+                               new Binary (
+                                       Binary.Operator.LessThanOrEqual,
+                                       new FieldExpression (pc_field),
+                                       new IntLiteral ((int) State.Running), Location),
+                               Create_ThrowInvalidOperation (),
+                               new Return (
+                                       new FieldExpression (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);
+                       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);
+
+                       ToplevelBlock block = move_next.Block = new ToplevelBlock (Location);
+
+                       MoveNextMethod inline = new MoveNextMethod (this, Location);
+                       block.AddStatement (inline);
+               }
+
+               void Define_GetEnumerator (bool is_generic)
+               {
+                       MemberName left;
+                       Expression type;
+                       if (is_generic) {
+                               left = new MemberName (
+                                       "System.Collections.Generic.IEnumerable",
+                                       generic_args);
+                               type = generic_enumerator_type;
+                       } else {
+                               left = new MemberName ("System.Collections.IEnumerable");
+                               type = enumerator_type;
+                       }
+
+                       MemberName name = new MemberName (left, "GetEnumerator", null);
+
+                       Method get_enumerator = new Method (
+                               this, null, type, 0, false, name,
+                               Parameters.EmptyReadOnlyParameters, null,
+                               Location.Null);
+                       AddMethod (get_enumerator);
+
+                       get_enumerator.Block = new ToplevelBlock (Location);
+
+                       Expression ce = new MemberAccess (
+                               new SimpleName ("System.Threading.Interlocked", Location),
+                               "CompareExchange", Location);
+
+                       Expression pc = new FieldExpression (pc_field);
+                       Expression before = new IntLiteral ((int) State.Running);
+                       Expression uninitialized = new IntLiteral ((int) State.Uninitialized);
+
+                       ArrayList args = new ArrayList ();
+                       args.Add (new Argument (pc, Argument.AType.Ref));
+                       args.Add (new Argument (before, Argument.AType.Expression));
+                       args.Add (new Argument (uninitialized, Argument.AType.Expression));
+
+                       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),
+                               Location));
+
+                       args = new ArrayList ();
+                       if (!is_static)
+                               args.Add (new Argument (new FieldExpression (this_field)));
+
+                       args.Add (new Argument (new BoolLiteral (true)));
+
+                       for (int i = 0; i < parameters.Count; i++)
+                               args.Add (new Argument (
+                                                 new FieldExpression (parameter_fields [i])));
+
+                       Expression new_expr = new New (current_type, args, Location);
+                       get_enumerator.Block.AddStatement (new Return (new_expr, Location));
+               }
+
+               protected class SimpleParameterReference : Expression
+               {
+                       int idx;
+
+                       public SimpleParameterReference (Type type, int idx, Location loc)
                        {
-                               this.handler = handler;
-                               eclass = ExprClass.Value;
-                               loc = l;
+                               this.idx = idx;
+                               this.loc = loc;
+                               this.type = type;
+                               eclass = ExprClass.Variable;
                        }
 
                        public override Expression DoResolve (EmitContext ec)
                        {
-                               // Create the proxy class type.
-                               handler.MakeEnumeratorProxy ();
+                               return this;
+                       }
 
-                               if (IsIEnumerable (handler.return_type))
-                                       handler.MakeEnumerableProxy ();
+                       public override void Emit (EmitContext ec)
+                       {
+                               DoEmit (ec);
+                       }
 
-                               type = handler.return_type;
-                               return this;
+                       protected virtual void DoEmit (EmitContext ec)
+                       {
+                               ParameterReference.EmitLdArg (ec.ig, idx);
                        }
+               }
+
+               protected class ThisParameterReference : SimpleParameterReference
+               {
+                       public ThisParameterReference (Type type, int idx, Location loc)
+                               : base (type, idx, loc)
+                       { }
 
-                       public override Expression ResolveAsTypeStep (EmitContext ec)
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               base.DoEmit (ec);
+                               if (ec.TypeContainer is Struct)
+                                       ec.ig.Emit (OpCodes.Ldobj, type);
+                       }
+               }
+
+               protected class FieldExpression : Expression
+               {
+                       Field field;
+
+                       public FieldExpression (Field field)
+                       {
+                               this.field = field;
+                       }
+
+                       public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
                        {
                                return DoResolve (ec);
                        }
 
+                       public override Expression DoResolve (EmitContext ec)
+                       {
+                               FieldExpr fexpr = new FieldExpr (field.FieldBuilder, loc);
+                               fexpr.InstanceExpression = ec.GetThis (loc);
+                               return fexpr.Resolve (ec);
+                       }
+
                        public override void Emit (EmitContext ec)
                        {
-                               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;
-                               }
+                               throw new InvalidOperationException ();
+                       }
+               }
 
-                               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;
-                               }
+               protected class MoveNextMethod : Statement {
+                       Iterator iterator;
+
+                       public MoveNextMethod (Iterator iterator, Location loc)
+                       {
+                               this.loc = loc;
+                               this.iterator = iterator;
+                       }
+
+                       public override bool Resolve (EmitContext ec)
+                       {
+                               ec.CurrentBranching.CurrentUsageVector.Return ();
+                               return true;
+                       }
+
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               int code_flags = Modifiers.METHOD_YIELDS;
+                               if (iterator.is_static)
+                                       code_flags |= Modifiers.STATIC;
+
+                               EmitContext new_ec = new EmitContext (
+                                       iterator.container, loc, ec.ig,
+                                       TypeManager.int32_type, code_flags);
+
+                               new_ec.CurrentIterator = iterator;
+
+                               iterator.EmitMoveNext (new_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]);
+               protected class DisposeMethod : Statement {
+                       Iterator iterator;
+
+                       public DisposeMethod (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.EmitDispose (ec);
+                       }
+               }
+
+               protected class StatementList : Statement {
+                       ArrayList statements;
+
+                       public StatementList (Location loc)
+                       {
+                               this.loc = loc;
+                               statements = new ArrayList ();
+                       }
+
+                       public void Add (Statement statement)
+                       {
+                               statements.Add (statement);
+                       }
+
+                       public override bool Resolve (EmitContext ec)
+                       {
+                               foreach (Statement stmt in statements) {
+                                       if (!stmt.Resolve (ec))
+                                               return false;
                                }
-                               
-                               //
-                               // Initialize fields
-                               //
-                               ig.Emit (OpCodes.Ldloc, temp);
-                               ec.FreeTemporaryLocal (temp, handler.container.TypeBuilder);
+
+                               return true;
                        }
+
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               foreach (Statement stmt in statements)
+                                       stmt.Emit (ec);
+                       }
+               }
+
+               protected class SetState : Statement
+               {
+                       Iterator iterator;
+                       State state;
+
+                       public SetState (Iterator iterator, State state, Location loc)
+                       {
+                               this.iterator = iterator;
+                               this.state = state;
+                               this.loc = loc;
+                       }
+
+                       public override bool Resolve (EmitContext ec)
+                       {
+                               return true;
+                       }
+
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               ec.ig.Emit (OpCodes.Ldarg_0);
+                               IntConstant.EmitInt (ec.ig, (int) state);
+                               ec.ig.Emit (OpCodes.Stfld, iterator.pc_field.FieldBuilder);
+                       }
+               }
+
+               void Define_Reset ()
+               {
+                       Method reset = new Method (
+                               this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
+                               false, new MemberName ("Reset"),
+                               Parameters.EmptyReadOnlyParameters, null, Location);
+                       AddMethod (reset);
+
+                       reset.Block = new ToplevelBlock (Location);
+                       reset.Block.AddStatement (Create_ThrowNotSupported ());
+               }
+
+               void Define_Dispose ()
+               {
+                       dispose = new Method (
+                               this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
+                               false, new MemberName ("Dispose"),
+                               Parameters.EmptyReadOnlyParameters, null, Location);
+                       AddMethod (dispose);
+
+                       dispose.Block = new ToplevelBlock (Location);
+                       dispose.Block.AddStatement (new DisposeMethod (this, Location));
+               }
+
+               public ToplevelBlock Block {
+                       get { return block; }
+               }
+
+               public Type IteratorType {
+                       get { return iterator_type; }
                }
 
                //
@@ -638,7 +969,7 @@ namespace Mono.CSharp {
                        public NoCheckReturn (Expression expr, Location loc) : base (expr, loc)
                        {
                        }
-                       
+
                        public override bool Resolve (EmitContext ec)
                        {
                                ec.InIterator = false;
@@ -649,45 +980,37 @@ namespace Mono.CSharp {
                        }
                }
 
-               static bool IsIEnumerable (Type t)
-               {
-                       return t == TypeManager.ienumerable_type || TypeManager.ImplementsInterface (t, TypeManager.ienumerable_type);
-               }
-
-               static bool IsIEnumerator (Type t)
-               {
-                       return t == TypeManager.ienumerator_type || TypeManager.ImplementsInterface (t, TypeManager.ienumerator_type);
-               }
-               
-               //
-               // Returns the new block for the method, or null on failure
-               //
-               public Block Setup (Block block)
+               bool CheckType (Type t)
                {
-                       if (!(IsIEnumerator (return_type) || IsIEnumerable (return_type))){
-                               Report.Error (
-                                       -205, loc, String.Format (
-                                               "The method `{0}' contains a yield statement, but has an invalid return type for an iterator `{1}'",
-                                               name, TypeManager.CSharpName (return_type)));
-                               return null;
+                       if (t == TypeManager.ienumerable_type) {
+                               iterator_type = TypeManager.object_type;
+                               is_enumerable = true;
+                               return true;
+                       } else if (t == TypeManager.ienumerator_type) {
+                               iterator_type = TypeManager.object_type;
+                               is_enumerable = false;
+                               return true;
                        }
 
-                       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 (-207, loc, String.Format (
-                                                             "Parameter {0} of `{1}' is {2} and not allowed for an iterator method",
-                                                             i+1, name, parameters.ParameterDesc (i)));
-                                       return null;
-                               }
-                       }
+                       if (!t.IsGenericInstance)
+                               return false;
 
-                       original_block = block;
-                       Block b = new Block (null);
+                       Type[] args = TypeManager.GetTypeArguments (t);
+                       if (args.Length != 1)
+                               return false;
+
+                       Type gt = t.GetGenericTypeDefinition ();
+                       if (gt == TypeManager.generic_ienumerable_type) {
+                               iterator_type = args [0];
+                               is_enumerable = true;
+                               return true;
+                       } else if (gt == TypeManager.generic_ienumerator_type) {
+                               iterator_type = args [0];
+                               is_enumerable = false;
+                               return true;
+                       }
 
-                       // return new InnerClass ()
-                       b.AddStatement (new NoCheckReturn (new NewInnerType (this, loc), loc));
-                       return b;
+                       return false;
                }
        }
 }