2005-03-16 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / gmcs / iterators.cs
index 998073f76543f371ae72ac03900262b42fef5fba..85cd202458601957feeb19acffd112fa21a28714 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
@@ -51,9 +51,8 @@ namespace Mono.CSharp {
                                              "catch clause");
                                return false;
                        }
-                       if (ec.InAnonymousMethod){
-                               Report.Error (1621, 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;
                        }
 
@@ -112,9 +111,9 @@ namespace Mono.CSharp {
        }
 
        public class Iterator : Class {
+               ToplevelBlock original_block;
+               ToplevelBlock block;
                string original_name;
-               Block original_block;
-               Block block;
 
                Type iterator_type;
                TypeExpr iterator_type_expr;
@@ -134,10 +133,14 @@ namespace Mono.CSharp {
                // Context from the original method
                //
                TypeContainer container;
+               TypeExpr current_type;
+               Type this_type;
                Type return_type;
                Type [] param_types;
                InternalParameters parameters;
 
+               MethodInfo dispose_method;
+
                Expression enumerator_type;
                Expression enumerable_type;
                Expression generic_enumerator_type;
@@ -156,6 +159,7 @@ namespace Mono.CSharp {
                {
                        ig.Emit (OpCodes.Ldarg_0);
                        IntConstant.EmitInt (ig, (int) State.After);
+                       ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
                        ig.Emit (OpCodes.Br, move_next_error);
                }
 
@@ -205,7 +209,7 @@ namespace Mono.CSharp {
                        ig.BeginFaultBlock ();
 
                        ig.Emit (OpCodes.Ldarg_0);
-                       ig.Emit (OpCodes.Callvirt, dispose.MethodBuilder);
+                       ig.Emit (OpCodes.Callvirt, dispose_method);
 
                        ig.EndExceptionBlock ();
 
@@ -222,6 +226,7 @@ namespace Mono.CSharp {
                        Label dispatcher = ig.DefineLabel ();
                        ig.Emit (OpCodes.Br, dispatcher);
 
+                       ec.RemapToProxy = true;
                        Label [] labels = new Label [resume_points.Count];
                        for (int i = 0; i < labels.Length; i++) {
                                ResumePoint point = (ResumePoint) resume_points [i];
@@ -245,6 +250,7 @@ namespace Mono.CSharp {
                                ig.EndExceptionBlock ();
                                ig.Emit (OpCodes.Br, end);
                        }
+                       ec.RemapToProxy = false;
 
                        ig.MarkLabel (dispatcher);
                        ig.Emit (OpCodes.Ldarg_0);
@@ -354,7 +360,7 @@ namespace Mono.CSharp {
                //
                public Iterator (TypeContainer container, string name, Type return_type,
                                 Type [] param_types, InternalParameters parameters,
-                                int modifiers, Block block, Location loc)
+                                int modifiers, ToplevelBlock block, Location loc)
                        : base (container.NamespaceEntry, container, MakeProxyName (name),
                                Modifiers.PRIVATE, null, loc)
                {
@@ -364,7 +370,7 @@ namespace Mono.CSharp {
                        this.parameters = parameters;
                        this.original_name = name;
                        this.original_block = block;
-                       this.block = new Block (null);
+                       this.block = new ToplevelBlock (loc);
 
                        fields = new Hashtable ();
 
@@ -373,6 +379,8 @@ namespace Mono.CSharp {
 
                public bool DefineIterator ()
                {
+                       ec = new EmitContext (this, Mono.CSharp.Location.Null, null, null, ModFlags);
+
                        if (!CheckType (return_type)) {
                                Report.Error (
                                        1624, Location,
@@ -392,6 +400,11 @@ namespace Mono.CSharp {
                                }
                        }
 
+                       if (container.CurrentType != null)
+                               this_type = container.CurrentType;
+                       else
+                               this_type = container.TypeBuilder;
+
                        generic_args = new TypeArguments (Location);
                        generic_args.Add (new TypeExpression (iterator_type, Location));
 
@@ -426,11 +439,43 @@ namespace Mono.CSharp {
                        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;
+               }
+
                //
                // Returns the new block for the method, or null on failure
                //
                protected override bool DefineNestedTypes ()
                {
+                       if (CurrentType != null)
+                               current_type = new TypeExpression (CurrentType, Location);
+                       else
+                               current_type = new TypeExpression (TypeBuilder, Location);
+
                        Define_Fields ();
                        Define_Constructor ();
                        Define_Current (false);
@@ -463,7 +508,7 @@ namespace Mono.CSharp {
 
                        ArrayList args = new ArrayList ();
                        if (!is_static) {
-                               Type t = container.TypeBuilder;
+                               Type t = this_type;
                                args.Add (new Argument (
                                        new ThisParameterReference (t, 0, Location)));
                        }
@@ -476,8 +521,7 @@ namespace Mono.CSharp {
                                        new SimpleParameterReference (t, first + i, Location)));
                        }
 
-                       Expression new_expr = new New (
-                               new TypeExpression (TypeBuilder, Location), args, Location);
+                       Expression new_expr = new New (current_type, args, Location);
 
                        block.AddStatement (new NoCheckReturn (new_expr, Location));
                }
@@ -498,8 +542,7 @@ namespace Mono.CSharp {
 
                        if (!is_static) {
                                this_field = new Field (
-                                       this,
-                                       new TypeExpression (container.TypeBuilder, Location),
+                                       this, new TypeExpression (this_type, loc),
                                        Modifiers.PRIVATE, "this", null, null, loc);
                                AddField (this_field);
                        }
@@ -525,7 +568,7 @@ namespace Mono.CSharp {
 
                        if (!is_static)
                                list.Add (new Parameter (
-                                       new TypeExpression (container.TypeBuilder, Location),
+                                       new TypeExpression (this_type, Location),
                                        "this", Parameter.Modifier.NONE, null));
                        list.Add (new Parameter (
                                TypeManager.system_boolean_expr, "initialized",
@@ -549,10 +592,10 @@ namespace Mono.CSharp {
                                Location);
                        AddConstructor (ctor);
 
-                       Block block = ctor.Block = new Block (null);
+                       ToplevelBlock block = ctor.Block = new ToplevelBlock (Location);
 
                        if (!is_static) {
-                               Type t = container.TypeBuilder;
+                               Type t = this_type;
 
                                Assign assign = new Assign (
                                        new FieldExpression (this_field),
@@ -617,7 +660,7 @@ namespace Mono.CSharp {
 
                        MemberName name = new MemberName (left, "Current", null);
 
-                       Block get_block = new Block (null);
+                       ToplevelBlock get_block = new ToplevelBlock (Location);
 
                        get_block.AddStatement (new If (
                                new Binary (
@@ -629,7 +672,7 @@ namespace Mono.CSharp {
                                        new FieldExpression (current_field), Location),
                                Location));
 
-                       Accessor getter = new Accessor (get_block, null, Location);
+                       Accessor getter = new Accessor (get_block, 0, null, Location);
 
                        Property current = new Property (
                                this, type, 0, false, name, null, getter, null, Location);
@@ -645,7 +688,7 @@ namespace Mono.CSharp {
                                Location.Null);
                        AddMethod (move_next);
 
-                       Block block = move_next.Block = new Block (null);
+                       ToplevelBlock block = move_next.Block = new ToplevelBlock (Location);
 
                        MoveNextMethod inline = new MoveNextMethod (this, Location);
                        block.AddStatement (inline);
@@ -673,7 +716,7 @@ namespace Mono.CSharp {
                                Location.Null);
                        AddMethod (get_enumerator);
 
-                       get_enumerator.Block = new Block (null);
+                       get_enumerator.Block = new ToplevelBlock (Location);
 
                        Expression ce = new MemberAccess (
                                new SimpleName ("System.Threading.Interlocked", Location),
@@ -706,8 +749,7 @@ namespace Mono.CSharp {
                                args.Add (new Argument (
                                                  new FieldExpression (parameter_fields [i])));
 
-                       Expression new_expr = new New (
-                               new TypeExpression (TypeBuilder, Location), args, Location);
+                       Expression new_expr = new New (current_type, args, Location);
                        get_enumerator.Block.AddStatement (new Return (new_expr, Location));
                }
 
@@ -890,7 +932,7 @@ namespace Mono.CSharp {
                                Parameters.EmptyReadOnlyParameters, null, Location);
                        AddMethod (reset);
 
-                       reset.Block = new Block (null);
+                       reset.Block = new ToplevelBlock (Location);
                        reset.Block.AddStatement (Create_ThrowNotSupported ());
                }
 
@@ -902,11 +944,11 @@ namespace Mono.CSharp {
                                Parameters.EmptyReadOnlyParameters, null, Location);
                        AddMethod (dispose);
 
-                       dispose.Block = new Block (null);
+                       dispose.Block = new ToplevelBlock (Location);
                        dispose.Block.AddStatement (new DisposeMethod (this, Location));
                }
 
-               public Block Block {
+               public ToplevelBlock Block {
                        get { return block; }
                }