Better messages than a throw
[mono.git] / mcs / mcs / iterators.cs
index c51524a3cf0095b1b8fc3f97e181ce803a2c1fb3..e8a57c1775449e3463f2689316439d5417639347 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
@@ -46,14 +46,17 @@ namespace Mono.CSharp {
                                              "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 (1631, loc, "Cannot yield in the body of a " +
                                              "catch clause");
                                return false;
                        }
-                       if (ec.InAnonymousMethod){
-                               Report.Error (1621, loc, "yield statement can not appear " +
-                                             "inside an anonymoud method");
+                       if (ec.CurrentAnonymousMethod != null){
+                               Report.Error (1621, loc, "yield statement can not appear inside an anonymoud method");
                                return false;
                        }
 
@@ -112,9 +115,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;
@@ -217,6 +220,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];
@@ -240,7 +244,8 @@ namespace Mono.CSharp {
                                ig.EndExceptionBlock ();
                                ig.Emit (OpCodes.Br, end);
                        }
-
+                       ec.RemapToProxy = false;
+                       
                        ig.MarkLabel (dispatcher);
                        ig.Emit (OpCodes.Ldarg_0);
                        ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder);
@@ -335,13 +340,13 @@ namespace Mono.CSharp {
                        point.Define (ig);
                }
 
-               private static string MakeProxyName (string name)
+               private static MemberName MakeProxyName (string name)
                {
                        int pos = name.LastIndexOf ('.');
                        if (pos > 0)
                                name = name.Substring (pos + 1);
 
-                       return "<" + name + ">__" + (proxy_count++);
+                       return new MemberName ("<" + name + ">__" + (proxy_count++));
                }
 
                //
@@ -349,9 +354,9 @@ 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)
+                               (modifiers & Modifiers.UNSAFE) | Modifiers.PRIVATE, null, loc)
                {
                        this.container = container;
                        this.return_type = return_type;
@@ -359,15 +364,17 @@ 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 ();
 
                        is_static = (modifiers & Modifiers.STATIC) != 0;
                }
 
-               public bool Define ()
+               public bool DefineIterator ()
                {
+                       ec = new EmitContext (this, Mono.CSharp.Location.Null, null, null, ModFlags);
+
                        if (!CheckType (return_type)) {
                                Report.Error (
                                        1624, Location,
@@ -405,7 +412,7 @@ namespace Mono.CSharp {
                //
                // Returns the new block for the method, or null on failure
                //
-               protected override bool DoDefineType ()
+               protected override bool DefineNestedTypes ()
                {
                        Define_Fields ();
                        Define_Constructor ();
@@ -419,15 +426,15 @@ namespace Mono.CSharp {
 
                        Create_Block ();
 
-                       return true;
+                       return base.DefineNestedTypes ();
                }
 
 
                Field pc_field;
-               Field this_field;
                Field current_field;
                Method dispose;
 
+               public Field this_field;
                public Field[] parameter_fields;
 
                void Create_Block ()
@@ -438,7 +445,7 @@ namespace Mono.CSharp {
                        if (!is_static) {
                                Type t = container.TypeBuilder;
                                args.Add (new Argument (
-                                       new SimpleParameterReference (t, 0, Location)));
+                                       new ThisParameterReference (t, 0, Location)));
                        }
 
                        args.Add (new Argument (new BoolLiteral (false)));
@@ -460,17 +467,18 @@ namespace Mono.CSharp {
                        Location loc = Location.Null;
 
                        pc_field = new Field (
-                               TypeManager.system_int32_expr, Modifiers.PRIVATE, "PC",
+                               this, TypeManager.system_int32_expr, Modifiers.PRIVATE, "PC",
                                null, null, loc);
                        AddField (pc_field);
 
                        current_field = new Field (
-                               iterator_type_expr, Modifiers.PRIVATE, "current",
+                               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);
@@ -482,6 +490,7 @@ namespace Mono.CSharp {
                                        "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]);
@@ -520,7 +529,7 @@ 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;
@@ -574,7 +583,9 @@ namespace Mono.CSharp {
 
                void Define_Current ()
                {
-                       Block get_block = new Block (null);
+                       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 (
@@ -586,11 +597,11 @@ namespace Mono.CSharp {
                                        new FieldExpression (current_field), Location),
                                Location));
 
-                       Accessor getter = new Accessor (get_block, null);
+                       Accessor getter = new Accessor (get_block, 0, null, Location);
 
                        Property current = new Property (
-                               this, iterator_type_expr, Modifiers.PUBLIC,
-                               false, "Current", null, getter, null, Location);
+                               this, iterator_type_expr, 0,
+                               false, name, null, getter, null, Location);
                        AddProperty (current);
                }
 
@@ -598,12 +609,12 @@ namespace Mono.CSharp {
                {
                        Method move_next = new Method (
                                this, TypeManager.system_boolean_expr,
-                               Modifiers.PUBLIC, false, "MoveNext",
+                               Modifiers.PUBLIC, false, new MemberName ("MoveNext"),
                                Parameters.EmptyReadOnlyParameters, null,
                                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);
@@ -611,15 +622,18 @@ namespace Mono.CSharp {
 
                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),
-                               Modifiers.PUBLIC, false, "GetEnumerator",
+                               0, false, name,
                                Parameters.EmptyReadOnlyParameters, null,
                                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),
@@ -675,11 +689,30 @@ namespace Mono.CSharp {
                        }
 
                        public override void Emit (EmitContext ec)
+                       {
+                               DoEmit (ec);
+                       }
+
+                       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)
+                       { }
+
+                       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;
@@ -689,6 +722,11 @@ namespace Mono.CSharp {
                                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);
@@ -723,6 +761,8 @@ namespace Mono.CSharp {
                                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);
@@ -813,11 +853,11 @@ namespace Mono.CSharp {
                {
                        Method reset = new Method (
                                this, TypeManager.system_void_expr, Modifiers.PUBLIC,
-                               false, "Reset", Parameters.EmptyReadOnlyParameters,
-                               null, Location);
+                               false, new MemberName ("Reset"),
+                               Parameters.EmptyReadOnlyParameters, null, Location);
                        AddMethod (reset);
 
-                       reset.Block = new Block (null);
+                       reset.Block = new ToplevelBlock (Location);
                        reset.Block.AddStatement (Create_ThrowNotSupported ());
                }
 
@@ -825,15 +865,15 @@ namespace Mono.CSharp {
                {
                        dispose = new Method (
                                this, TypeManager.system_void_expr, Modifiers.PUBLIC,
-                               false, "Dispose", Parameters.EmptyReadOnlyParameters,
-                               null, Location);
+                               false, new MemberName ("Dispose"),
+                               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; }
                }