2005-05-31 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / mcs / iterators.cs
index b5618af1782ceb8483efb287c9e2801fc6bb0cdc..62bb473c9a5862a4849d7f0ca0e0e5d87920a48a 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,8 @@ namespace Mono.CSharp {
        
        public class Yield : Statement {
                public Expression expr;
-
+               ArrayList finally_blocks;
+               
                public Yield (Expression expr, Location l)
                {
                        this.expr = expr;
@@ -40,22 +41,31 @@ 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");
+                       if (ec.InFinally) {
+                               Report.Error (1625, loc, "Cannot yield in the body of a " +
+                                             "finally clause");
+                               return false;
+                       } 
+                       
+                       if (ec.InUnsafe) {
+                               Report.Error (1629, loc, "Unsafe code may not appear in iterators");
                                return false;
                        }
-                       if (ec.CurrentBranching.InCatch ()){
-                               Report.Error (-209, loc, "yield statement can not appear in the catch clause");
+                       if (ec.InCatch){
+                               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, "The yield statement cannot be used inside anonymous method blocks");
                                return false;
                        }
 
-                       //
-                       // FIXME: Missing check for Yield inside try block that contains catch clauses
-                       //
+                       if (ec.CurrentBranching.InTryWithCatch ()) {
+                               Report.Error (1626, loc, "Cannot yield a value in the body of a " +
+                                       "try block with a catch clause");
+                               return false;
+                       }
                        return true;
                }
                
@@ -67,19 +77,21 @@ namespace Mono.CSharp {
                        if (!CheckContext (ec, loc))
                                return 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);
+                       ec.CurrentIterator.MarkYield (ec, expr, finally_blocks);
                }
        }
 
@@ -101,517 +113,785 @@ 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;
+               Hashtable fields;
 
-               //
-               // The value computed for Current
-               //
-               FieldBuilder current_field;
-
-               //
-               // 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;
                Type return_type;
-               Type [] param_types;
                InternalParameters parameters;
-               Block original_block;
-               Location loc;
-               int modifiers;
+
+               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)
+               public void EmitMoveNext (EmitContext ec)
                {
-                       ig.Emit (OpCodes.Newobj, TypeManager.invalid_operation_ctor);
-                       ig.Emit (OpCodes.Throw);
-               }
-               
-               void Create_MoveNext ()
-               {
-                       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;
+
+                       move_next_ok = ig.DefineLabel ();
+                       move_next_error = ig.DefineLabel ();
 
-                       ILGenerator ig = move_next_method.GetILGenerator ();
-                       EmitContext ec = new EmitContext (
-                               container, loc, ig,
-                               TypeManager.void_type, modifiers);
+                       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);
+                       ResumePoint entry_point = new ResumePoint (null);
+                       resume_points.Add (entry_point);
+                       entry_point.Define (ig);
 
-                               sw.CloseMethod ();
-                       } else {
-                               ec.EmitTopBlock (original_block, parameters, loc);
-                       }
-                       Current = null;
+                       ec.EmitTopBlock (original_block, parameters, Location);
+                       EmitYieldBreak (ig);
 
-                       EmitYieldBreak (ig, true);
-
-                       //
-                       // 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);
+
+                       Label end = ig.DefineLabel ();
+
+                       ig.MarkLabel (move_next_error);
                        ig.Emit (OpCodes.Ldc_I4_0); 
-                       ig.Emit (OpCodes.Ret); 
-               }
+                       ig.Emit (OpCodes.Stloc, retval);
+                       ig.Emit (OpCodes.Leave, end);
 
-               // 
-               // 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);
+                       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.MethodBuilder);
+
+                       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;
 
-                       current_property = enumerator_proxy_class.DefineProperty (
-                               "Current",
-                               PropertyAttributes.RTSpecialName | PropertyAttributes.SpecialName,
-                               TypeManager.object_type, null);
+                       Label end = ig.DefineLabel ();
+                       Label dispatcher = ig.DefineLabel ();
+                       ig.Emit (OpCodes.Br, dispatcher);
 
-                       current_property.SetGetMethod (get_current_method);
-                       
-                       ILGenerator ig = get_current_method.GetILGenerator ();
+                       ec.RemapToProxy = true;
+                       Label [] labels = new Label [resume_points.Count];
+                       for (int i = 0; i < labels.Length; i++) {
+                               ResumePoint point = (ResumePoint) resume_points [i];
 
-                       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);
+                               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);
+                       }
+                       ec.RemapToProxy = false;
                        
-                       ig.MarkLabel (return_current);
+                       ig.MarkLabel (dispatcher);
                        ig.Emit (OpCodes.Ldarg_0);
-                       ig.Emit (OpCodes.Ldfld, current_field);
-                       ig.Emit (OpCodes.Ret);
+                       ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder);
+                       ig.Emit (OpCodes.Switch, labels);
+
+                       ig.Emit (OpCodes.Ldarg_0);
+                       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)
+               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);
-                       
-                       // Return ok.
-                       ig.Emit (OpCodes.Ldc_I4_1);
-                       ig.Emit (OpCodes.Ret);
-                       
-                       Label resume_point = ig.DefineLabel ();
-                       ig.MarkLabel (resume_point);
-                       resume_labels.Add (resume_point);
+                       ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
+
+                       // Return ok
+                       ig.Emit (OpCodes.Br, move_next_ok);
+
+                       ResumePoint point = new ResumePoint (finally_blocks);
+                       resume_points.Add (point);
+                       point.Define (ig);
                }
 
-               //
-               // Creates the IEnumerator Proxy class
-               //
-               void MakeEnumeratorProxy ()
-               {
-                       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;
-
-                       //
-                       // 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);
-
-                       TypeManager.RegisterBuilder (enumerator_proxy_class, proxy_base_interfaces);
-
-                       //
-                       // 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);
-
-                       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 
-                       //
-
-                       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);
-
-                       //
-                       // Our constructor
-                       //
-                       ILGenerator ig = enumerator_proxy_constructor.GetILGenerator ();
+               public void MarkFinally (EmitContext ec, ArrayList finally_blocks)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       // increment pc
+                       pc++;
                        ig.Emit (OpCodes.Ldarg_0);
-                       ig.Emit (OpCodes.Call, TypeManager.object_ctor);
+                       IntConstant.EmitInt (ig, pc);
+                       ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
 
-                       ig.Emit (OpCodes.Ret);
+                       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 IEnumerable proxy class
+               // Our constructor
                //
-               void MakeEnumerableProxy ()
-               {
-                       TypeBuilder container_builder = container.TypeBuilder;
-                       Type [] proxy_base_interfaces = new Type [1];
-                       proxy_base_interfaces [0] = TypeManager.ienumerable_type;
-
-                       //
-                       // 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);
-
-                       //
-                       // Constructor
-                       //
-                       if ((modifiers & Modifiers.STATIC) == 0){
-                               enumerable_this_field = enumerable_proxy_class.DefineField (
-                                       "THIS", container.TypeBuilder, FieldAttributes.Assembly);
-                       }
-                       enumerable_parameter_fields = new FieldBuilder [parameters.Count];
+               public Iterator (TypeContainer container, string name, Type return_type,
+                                InternalParameters parameters,
+                                int modifiers, ToplevelBlock block, Location loc)
+                       : base (container.NamespaceEntry, container, MakeProxyName (name),
+                               (modifiers & Modifiers.UNSAFE) | Modifiers.PRIVATE, null, loc)
+               {
+                       this.container = container;
+                       this.return_type = return_type;
+                       this.parameters = parameters;
+                       this.original_name = name;
+                       this.original_block = block;
+                       this.block = new ToplevelBlock (loc);
+
+                       fields = new Hashtable ();
+
+                       is_static = (modifiers & Modifiers.STATIC) != 0;
+               }
+
+               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;
+                       }
+
                        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);
+                               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;
+                               }
+
+                               if (parameters.ParameterType (i).IsPointer) {
+                                       Report.Error (1637, Location, "Iterators cannot have unsafe parameters or yield types");
+                                       return false;
+                               }
                        }
-                       
-                       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);
+                       ArrayList list = new ArrayList ();
+                       if (is_enumerable)
+                               list.Add (new TypeExpression (
+                                                 TypeManager.ienumerable_type, Location));
+                       list.Add (new TypeExpression (TypeManager.ienumerator_type, Location));
+                       list.Add (new TypeExpression (TypeManager.idisposable_type, Location));
+
+                       iterator_type_expr = new TypeExpression (iterator_type, Location);
+
+                       container.AddIterator (this);
+
+                       Bases = list;
+                       return true;
                }
 
                //
-               // Populates the Enumerator Proxy class
+               // Returns the new block for the method, or null on failure
                //
-               void PopulateProxy ()
+               protected override bool DefineNestedTypes ()
                {
-                       RootContext.RegisterHelperClass (enumerator_proxy_class);
-                       
-                       Create_MoveNext ();
-                       Create_Reset ();
-                       Create_Current ();
-                       Create_Dispose ();
+                       Define_Fields ();
+                       Define_Constructor ();
+                       Define_Current ();
+                       Define_MoveNext ();
+                       Define_Reset ();
+                       Define_Dispose ();
+
+                       if (is_enumerable)
+                               Define_GetEnumerator ();
+
+                       Create_Block ();
+
+                       return base.DefineNestedTypes ();
+               }
+
+
+               Field pc_field;
+               Field current_field;
+               Method dispose;
+
+               public Field this_field;
+               public Field[] parameter_fields;
 
-                       if (IsIEnumerable (return_type)){
-                               Create_GetEnumerator ();
-                               RootContext.RegisterHelperClass (enumerable_proxy_class);
+               void Create_Block ()
+               {
+                       int first = is_static ? 0 : 1;
+
+                       ArrayList args = new ArrayList ();
+                       if (!is_static) {
+                               Type t = container.TypeBuilder;
+                               args.Add (new Argument (
+                                       new ThisParameterReference (t, 0, Location)));
+                       }
+
+                       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 (
+                               new TypeExpression (TypeBuilder, Location), args, Location);
+
+                       block.AddStatement (new NoCheckReturn (new_expr, Location));
                }
-               
 
-               //
-               // This is invoked by the EmitCode hook
-               //
-               void SetupIterator ()
+               void Define_Fields ()
                {
-                       PopulateProxy ();
+                       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 (container.TypeBuilder, Location),
+                                       Modifiers.PRIVATE, "this", null, null, loc);
+                               AddField (this_field);
+                       }
+
+                       parameter_fields = new Field [parameters.Count];
+                       for (int i = 0; i < parameters.Count; i++) {
+                               string fname = String.Format (
+                                       "field{0}_{1}", i, parameters.ParameterName (i));
+
+                               parameter_fields [i] = new Field (
+                                       this,
+                                       new TypeExpression (parameters.ParameterType (i), loc),
+                                       Modifiers.PRIVATE, fname, null, null, loc);
+                               AddField (parameter_fields [i]);
+                       }
                }
 
-               //
-               // Our constructor
-               //
-               public IteratorHandler (string name, TypeContainer container, Type return_type, Type [] param_types,
-                                       InternalParameters parameters, int modifiers, Location loc)
+               void Define_Constructor ()
                {
-                       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;
+                       Parameters ctor_params;
 
-                       IteratorType = TypeManager.object_type;
-                       
-                       RootContext.EmitCodeHook += new RootContext.Hook (SetupIterator);
+                       ArrayList list = new ArrayList ();
+
+                       if (!is_static)
+                               list.Add (new Parameter (
+                                       new TypeExpression (container.TypeBuilder, Location),
+                                       "this", Parameter.Modifier.NONE,
+                                       null, Location));
+                       list.Add (new Parameter (
+                               TypeManager.system_boolean_expr, "initialized",
+                               Parameter.Modifier.NONE, null, Location));
+
+                       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);
+
+                       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 = container.TypeBuilder;
+
+                               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));
                }
 
-               //
-               // 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) 
+               Statement Create_ThrowInvalidOperation ()
+               {
+                       TypeExpr ex_type = new TypeExpression (
+                               TypeManager.invalid_operation_exception_type, Location);
+
+                       return new Throw (new New (ex_type, null, Location), Location);
+               }
+
+               Statement Create_ThrowNotSupported ()
+               {
+                       TypeExpr ex_type = new TypeExpression (
+                               TypeManager.not_supported_exception_type, Location);
+
+                       return new Throw (new New (ex_type, null, Location), Location);
+               }
+
+               void Define_Current ()
+               {
+                       ToplevelBlock get_block = new ToplevelBlock (Location);
+                       MemberName left = new MemberName ("System.Collections.IEnumerator");
+                       MemberName name = new MemberName (left, "Current");
+
+                       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, iterator_type_expr, 0,
+                               false, name, null, getter, null, Location);
+                       AddProperty (current);
+               }
+
+               void Define_MoveNext ()
+               {
+                       Method move_next = new Method (
+                               this, 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 ()
+               {
+                       MemberName left = new MemberName ("System.Collections.IEnumerable");
+                       MemberName name = new MemberName (left, "GetEnumerator");
+
+                       Method get_enumerator = new Method (
+                               this,
+                               new TypeExpression (TypeManager.ienumerator_type, Location),
+                               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 (
+                               new TypeExpression (TypeBuilder, Location), 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);
                        }
+               }
 
-                       public override Expression ResolveAsTypeStep (EmitContext ec)
+               protected class ThisParameterReference : SimpleParameterReference
+               {
+                       public ThisParameterReference (Type type, int idx, Location loc)
+                               : base (type, idx, loc)
+                       { }
+
+                       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 (false)
-                                       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;
+
+                               code_flags |= iterator.ModFlags & Modifiers.UNSAFE;
+
+                               EmitContext new_ec = new EmitContext (
+                                       iterator.container, loc, ec.ig,
+                                       TypeManager.int32_type, code_flags);
+
+                               new_ec.CurrentIterator = iterator;
+
+                               iterator.EmitMoveNext (new_ec);
+                       }
+               }
+
+               protected class DisposeMethod : Statement {
+                       Iterator iterator;
+
+                       public DisposeMethod (Iterator iterator, Location loc)
+                       {
+                               this.loc = loc;
+                               this.iterator = iterator;
+                       }
 
-                               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]);
+                       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, 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, 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; }
+               }
+
                //
                // This return statement tricks return into not flagging an error for being
                // used in a Yields method
@@ -620,7 +900,7 @@ namespace Mono.CSharp {
                        public NoCheckReturn (Expression expr, Location loc) : base (expr, loc)
                        {
                        }
-                       
+
                        public override bool Resolve (EmitContext ec)
                        {
                                ec.InIterator = false;
@@ -631,45 +911,19 @@ namespace Mono.CSharp {
                        }
                }
 
-               static bool IsIEnumerable (Type t)
+               bool CheckType (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)
-               {
-                       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;
-                       }
-
-                       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 == 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;
                        }
 
-                       original_block = block;
-                       Block b = new Block (null);
-
-                       // return new InnerClass ()
-                       b.AddStatement (new NoCheckReturn (new NewInnerType (this, loc), loc));
-                       return b;
+                       return false;
                }
        }
 }