2008-03-27 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / statement.cs
index ab2a28b0d8ce243a1c381844942828d8a891d46c..9a3121ecae27fc9f2cd6ecef0fde5f0eaae55588 100644 (file)
@@ -103,6 +103,12 @@ namespace Mono.CSharp {
                        return s;
                }
 
+               public virtual Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree");
+                       return null;
+               }
+
                public Statement PerformClone ()
                {
                        CloneContext clonectx = new CloneContext ();
@@ -247,8 +253,8 @@ namespace Mono.CSharp {
                        //
                        // Dead code elimination
                        //
-                       if (expr is BoolConstant){
-                               bool take = ((BoolConstant) expr).Value;
+                       if (expr is Constant){
+                               bool take = !((Constant) expr).IsDefaultValue;
 
                                if (take){
                                        if (!TrueStatement.Resolve (ec))
@@ -296,15 +302,34 @@ namespace Mono.CSharp {
                        Label end;
 
                        //
-                       // If we're a boolean expression, Resolve() already
+                       // If we're a boolean constant, Resolve() already
                        // eliminated dead code for us.
                        //
-                       if (expr is BoolConstant){
-                               bool take = ((BoolConstant) expr).Value;
+                       if (expr is Constant){
+                               
+                               //
+                               // Simple bool constant
+                               //
+                               if (expr is BoolConstant) {
+                                       bool take = ((BoolConstant) expr).Value;
 
-                               if (take)
+                                       if (take)
+                                               TrueStatement.Emit (ec);
+                                       else if (FalseStatement != null)
+                                               FalseStatement.Emit (ec);
+                                       
+                                       return;
+                               }
+
+                               //
+                               // Bool constant with side-effects
+                               //
+                               expr.Emit (ec);
+                               ig.Emit (OpCodes.Pop);
+
+                               if (TrueStatement != null)
                                        TrueStatement.Emit (ec);
-                               else if (FalseStatement != null)
+                               if (FalseStatement != null)
                                        FalseStatement.Emit (ec);
 
                                return;
@@ -515,6 +540,7 @@ namespace Mono.CSharp {
                                Statement.Emit (ec);
                        
                                ig.MarkLabel (ec.LoopBegin);
+                               ec.Mark (loc, true);
 
                                expr.EmitBranchable (ec, while_loop, true);
                                
@@ -525,6 +551,11 @@ namespace Mono.CSharp {
                        ec.LoopEnd = old_end;
                }
 
+               public override void Emit (EmitContext ec)
+               {
+                       DoEmit (ec);
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        While target = (While) t;
@@ -753,6 +784,12 @@ namespace Mono.CSharp {
 
                        if (Expr.Type != ec.ReturnType) {
                                if (ec.InferReturnType) {
+                                       //
+                                       // void cannot be used in contextual return
+                                       //
+                                       if (Expr.Type == TypeManager.void_type)
+                                               return false;
+
                                        ec.ReturnType = Expr.Type;
                                } else {
                                        Expr = Convert.ImplicitConversionRequired (
@@ -1089,7 +1126,8 @@ namespace Mono.CSharp {
                {
                        Throw target = (Throw) t;
 
-                       target.expr = expr.Clone (clonectx);
+                       if (expr != null)
+                               target.expr = expr.Clone (clonectx);
                }
        }
 
@@ -1255,7 +1293,7 @@ namespace Mono.CSharp {
                public void EmitSymbolInfo (EmitContext ec, string name)
                {
                        if (builder != null)
-                               ec.DefineLocalVariable (name, builder);
+                               ec.DefineLocalVariable (Name, builder);
                }
 
                public bool IsThisAssigned (EmitContext ec)
@@ -1509,7 +1547,7 @@ namespace Mono.CSharp {
                //
                // Labels.  (label, block) pairs.
                //
-               Hashtable labels;
+               HybridDictionary labels;
 
                //
                // Keeps track of (name, type) pairs
@@ -1518,7 +1556,7 @@ namespace Mono.CSharp {
 
                //
                // Keeps track of constants
-               Hashtable constants;
+               HybridDictionary constants;
 
                //
                // Temporary variables.
@@ -1530,7 +1568,9 @@ namespace Mono.CSharp {
                //
                Block switch_block;
 
+               // TODO: merge with scope_initializers
                ExpressionStatement scope_init;
+               ArrayList scope_initializers;
 
                ArrayList anonymous_children;
 
@@ -1571,7 +1611,7 @@ namespace Mono.CSharp {
                        this.EndLocation = end;
                        this.loc = start;
                        this_id = id++;
-                       statements = new ArrayList ();
+                       statements = new ArrayList (4);
                }
 
                public Block CreateSwitchBlock (Location start)
@@ -1597,7 +1637,7 @@ namespace Mono.CSharp {
                void AddChild (Block b)
                {
                        if (children == null)
-                               children = new ArrayList ();
+                               children = new ArrayList (1);
                        
                        children.Add (b);
                }
@@ -1668,7 +1708,7 @@ namespace Mono.CSharp {
                        Toplevel.CheckError158 (name, target.loc);
 
                        if (labels == null)
-                               labels = new Hashtable ();
+                               labels = new HybridDictionary();
 
                        labels.Add (name, target);
                        return true;
@@ -1843,7 +1883,7 @@ namespace Mono.CSharp {
                                return false;
                        
                        if (constants == null)
-                               constants = new Hashtable ();
+                               constants = new HybridDictionary();
 
                        constants.Add (name, value);
 
@@ -1899,6 +1939,18 @@ namespace Mono.CSharp {
                        }
                        return null;
                }
+
+               //
+               // It should be used by expressions which require to
+               // register a statement during resolve process.
+               //
+               public void AddScopeStatement (StatementExpression s)
+               {
+                       if (scope_initializers == null)
+                               scope_initializers = new ArrayList ();
+
+                       scope_initializers.Add (s);
+               }
                
                public void AddStatement (Statement s)
                {
@@ -1973,8 +2025,12 @@ namespace Mono.CSharp {
                                LocalInfo vi = (LocalInfo) de.Value;
                                Type variable_type = vi.VariableType;
 
-                               if (variable_type == null)
+                               if (variable_type == null) {
+                                       if (vi.Type is VarExpr)
+                                               Report.Error (822, vi.Type.Location, "An implicitly typed local variable cannot be a constant");
+
                                        continue;
+                               }
 
                                Expression cv = (Expression) constants [name];
                                if (cv == null)
@@ -2064,13 +2120,13 @@ namespace Mono.CSharp {
                        }
 
                        if (temporary_variables != null) {
-                               foreach (LocalInfo vi in temporary_variables)
-                                       vi.ResolveVariable (ec);
+                               for (int i = 0; i < temporary_variables.Count; i++)
+                                       ((LocalInfo)temporary_variables[i]).ResolveVariable(ec);
                        }
 
                        if (children != null){
-                               foreach (Block b in children)
-                                       b.EmitMeta (ec);
+                               for (int i = 0; i < children.Count; i++)
+                                       ((Block)children[i]).EmitMeta(ec);
                        }
                }
 
@@ -2179,10 +2235,10 @@ namespace Mono.CSharp {
                                //
 
                                if (!s.Resolve (ec)) {
+                                       ok = false;
                                        if (ec.IsInProbingMode)
-                                               return false;
+                                               break;
 
-                                       ok = false;
                                        statements [ix] = EmptyStatement.Value;
                                        continue;
                                }
@@ -2200,9 +2256,6 @@ namespace Mono.CSharp {
                        Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation,
                                      ec.CurrentBranching, statement_count, num_statements);
 
-                       if (!ok)
-                               return false;
-
                        while (ec.CurrentBranching is FlowBranchingLabeled)
                                ec.EndFlowBranching ();
 
@@ -2263,34 +2316,58 @@ namespace Mono.CSharp {
 
                        ec.CurrentBlock = this;
 
-                       bool emit_debug_info = (CodeGen.SymbolWriter != null);
-                       bool is_lexical_block = this == Explicit && Parent != null;
+                       bool emit_debug_info = SymbolWriter.HasSymbolWriter;
+                       bool is_lexical_block = (this == Explicit) && (Parent != null) &&
+                               ((flags & Flags.IsIterator) == 0);
+
+                       bool omit_debug_info = ec.OmitDebuggingInfo;
 
                        if (emit_debug_info) {
                                if (is_lexical_block)
                                        ec.BeginScope ();
                        }
-                       ec.Mark (StartLocation, true);
-                       if (scope_init != null)
+
+                       if ((scope_init != null) || (scope_initializers != null))
+                               SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
+
+                       if (scope_init != null) {
+                               ec.OmitDebuggingInfo = true;
                                scope_init.EmitStatement (ec);
+                               ec.OmitDebuggingInfo = omit_debug_info;
+                       }
+                       if (scope_initializers != null) {
+                               ec.OmitDebuggingInfo = true;
+                               foreach (StatementExpression s in scope_initializers)
+                                       s.Emit (ec);
+                               ec.OmitDebuggingInfo = omit_debug_info;
+                       }
+
+                       if ((scope_init != null) || (scope_initializers != null))
+                               SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
+
+                       ec.Mark (StartLocation, true);
                        DoEmit (ec);
-                       ec.Mark (EndLocation, true); 
 
                        if (emit_debug_info) {
+                               EmitSymbolInfo (ec);
+
                                if (is_lexical_block)
                                        ec.EndScope ();
+                       }
 
-                               if (variables != null) {
-                                       foreach (DictionaryEntry de in variables) {
-                                               string name = (string) de.Key;
-                                               LocalInfo vi = (LocalInfo) de.Value;
+                       ec.CurrentBlock = prev_block;
+               }
 
-                                               vi.EmitSymbolInfo (ec, name);
-                                       }
+               protected virtual void EmitSymbolInfo (EmitContext ec)
+               {
+                       if (variables != null) {
+                               foreach (DictionaryEntry de in variables) {
+                                       string name = (string) de.Key;
+                                       LocalInfo vi = (LocalInfo) de.Value;
+
+                                       vi.EmitSymbolInfo (ec, name);
                                }
                        }
-
-                       ec.CurrentBlock = prev_block;
                }
 
                public override string ToString ()
@@ -2348,7 +2425,11 @@ namespace Mono.CSharp {
                        this.Explicit = this;
                }
 
-               Hashtable known_variables;
+               public bool IsIterator {
+                       get { return (flags & Flags.IsIterator) != 0; }
+               }
+
+               HybridDictionary known_variables;
 
                // <summary>
                //   Marks a variable with name @name as being used in this or a child block.
@@ -2358,7 +2439,7 @@ namespace Mono.CSharp {
                internal void AddKnownVariable (string name, IKnownVariable info)
                {
                        if (known_variables == null)
-                               known_variables = new Hashtable ();
+                               known_variables = new HybridDictionary();
 
                        known_variables [name] = info;
 
@@ -2422,10 +2503,6 @@ namespace Mono.CSharp {
                        set { flags |= Flags.HasVarargs; }
                }
 
-               public bool IsIterator {
-                       get { return (flags & Flags.IsIterator) != 0; }
-               }
-
                //
                // The parameters for the block.
                //
@@ -2605,6 +2682,11 @@ namespace Mono.CSharp {
                        return root_scope;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return ((Statement) statements [0]).CreateExpressionTree (ec);
+               }
+
                public void CreateIteratorHost (RootScopeInfo root)
                {
                        Report.Debug (64, "CREATE ITERATOR HOST", this, root, Parent, root_scope);
@@ -2765,15 +2847,27 @@ namespace Mono.CSharp {
 
                public override void EmitMeta (EmitContext ec)
                {
+                       // Avoid declaring an IL variable for this_variable since it is not accessed
+                       // from the generated IL
+                       if (this_variable != null)
+                               Variables.Remove ("this");
                        base.EmitMeta (ec);
                        parameters.ResolveVariable (this);
                }
 
+               protected override void EmitSymbolInfo (EmitContext ec)
+               {
+                       if ((AnonymousContainer != null) && (AnonymousContainer.Scope != null))
+                               SymbolWriter.DefineScopeVariable (AnonymousContainer.Scope.ID);
+
+                       base.EmitSymbolInfo (ec);
+               }
+
                public void MakeIterator (Iterator iterator)
                {
                        flags |= Flags.IsIterator;
 
-                       Block block = new ExplicitBlock (this, StartLocation, EndLocation);
+                       Block block = new ExplicitBlock (this, flags, StartLocation, EndLocation);
                        foreach (Statement stmt in statements)
                                block.AddStatement (stmt);
                        statements.Clear ();
@@ -2896,7 +2990,7 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               public void Erorr_AlreadyOccurs (Type switch_type, SwitchLabel collision_with)
+               public void Error_AlreadyOccurs (Type switch_type, SwitchLabel collision_with)
                {
                        string label;
                        if (converted == null)
@@ -3012,7 +3106,7 @@ namespace Mono.CSharp {
                //
                Expression SwitchGoverningType (EmitContext ec, Expression expr)
                {
-                       Type t = TypeManager.DropGenericTypeArguments (expr.Type);
+                       Type t = expr.Type;
 
                        if (t == TypeManager.byte_type ||
                            t == TypeManager.sbyte_type ||
@@ -3025,7 +3119,7 @@ namespace Mono.CSharp {
                            t == TypeManager.char_type ||
                            t == TypeManager.string_type ||
                            t == TypeManager.bool_type ||
-                           t.IsSubclassOf (TypeManager.enum_type))
+                           TypeManager.IsEnumType (t))
                                return expr;
 
                        if (allowed_types == null){
@@ -3096,7 +3190,7 @@ namespace Mono.CSharp {
                                foreach (SwitchLabel sl in ss.Labels){
                                        if (sl.Label == null){
                                                if (default_section != null){
-                                                       sl.Erorr_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]);
+                                                       sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]);
                                                        error = true;
                                                }
                                                default_section = ss;
@@ -3112,7 +3206,7 @@ namespace Mono.CSharp {
                                        try {
                                                Elements.Add (key, sl);
                                        } catch (ArgumentException) {
-                                               sl.Erorr_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]);
+                                               sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]);
                                                error = true;
                                        }
                                }
@@ -3283,7 +3377,7 @@ namespace Mono.CSharp {
                        Type compare_type;
                        
                        if (TypeManager.IsEnumType (SwitchType))
-                               compare_type = TypeManager.EnumToUnderlying (SwitchType);
+                               compare_type = TypeManager.GetEnumUnderlyingType (SwitchType);
                        else
                                compare_type = SwitchType;
                        
@@ -3581,6 +3675,7 @@ namespace Mono.CSharp {
                        }
 
                        bool first = true;
+                       bool ok = true;
                        foreach (SwitchSection ss in Sections){
                                if (!first)
                                        ec.CurrentBranching.CreateSibling (
@@ -3593,11 +3688,12 @@ namespace Mono.CSharp {
                                        // one single section - mark all the others as
                                        // unreachable.
                                        ec.CurrentBranching.CurrentUsageVector.Goto ();
-                                       if (!ss.Block.ResolveUnreachable (ec, true))
-                                               return false;
+                                       if (!ss.Block.ResolveUnreachable (ec, true)) {
+                                               ok = false;
+                                       }
                                } else {
                                        if (!ss.Block.Resolve (ec))
-                                               return false;
+                                               ok = false;
                                }
                        }
 
@@ -3610,7 +3706,12 @@ namespace Mono.CSharp {
 
                        Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching);
 
-                       return true;
+                       if (TypeManager.string_isinterned_string == null) {
+                               TypeManager.string_isinterned_string = TypeManager.GetPredefinedMethod (TypeManager.string_type,
+                                       "IsInterned", loc, TypeManager.string_type);
+                       }
+
+                       return ok;
                }
                
                protected override void DoEmit (EmitContext ec)
@@ -3745,6 +3846,14 @@ namespace Mono.CSharp {
                        
                        temp = new TemporaryVariable (t, loc);
                        temp.Resolve (ec);
+
+                       if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) {
+                               Type monitor_type = TypeManager.CoreLookupType ("System.Threading", "Monitor", Kind.Class, true);
+                               TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod (
+                                       monitor_type, "Enter", loc, TypeManager.object_type);
+                               TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod (
+                                       monitor_type, "Exit", loc, TypeManager.object_type);
+                       }
                        
                        return ok;
                }
@@ -3972,9 +4081,13 @@ namespace Mono.CSharp {
                                return false;
                        }
                        
-                       TypeExpr texpr = type.ResolveAsTypeTerminal (ec, false);
-                       if (texpr == null)
+                       TypeExpr texpr = type.ResolveAsContextualType (ec, false);
+                       if (texpr == null) {
+                               if (type is VarExpr)
+                                       Report.Error (821, type.Location, "A fixed statement cannot use an implicitly typed local variable");
+
                                return false;
+                       }
 
                        expr_type = texpr.Type;
 
@@ -4079,7 +4192,7 @@ namespace Mono.CSharp {
                                        // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
                                        //
                                        converted = new Conditional (new Binary (Binary.Operator.LogicalOr,
-                                               new Binary (Binary.Operator.Equality, e, new NullConstant (loc)),
+                                               new Binary (Binary.Operator.Equality, e, new NullLiteral (loc)),
                                                new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc))),
                                                        NullPointer.Null,
                                                        converted);
@@ -4238,7 +4351,7 @@ namespace Mono.CSharp {
 
                                        type = te.Type;
 
-                                       if (type != TypeManager.exception_type && !type.IsSubclassOf (TypeManager.exception_type)){
+                                       if (type != TypeManager.exception_type && !TypeManager.IsSubclassOf (type, TypeManager.exception_type)){
                                                Error (155, "The type caught or thrown must be derived from System.Exception");
                                                return false;
                                        }
@@ -4328,7 +4441,7 @@ namespace Mono.CSharp {
 
                                Type resolved_type = c.CatchType;
                                for (int ii = 0; ii < last_index; ++ii) {
-                                       if (resolved_type == prev_catches [ii] || resolved_type.IsSubclassOf (prev_catches [ii])) {
+                                       if (resolved_type == prev_catches [ii] || TypeManager.IsSubclassOf (resolved_type, prev_catches [ii])) {
                                                Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prev_catches [ii].FullName);
                                                return false;
                                        }
@@ -4700,6 +4813,11 @@ namespace Mono.CSharp {
                        // So, ensure there's some IL code after the finally block.
                        ec.NeedReturnLabel ();
 
+                       if (TypeManager.void_dispose_void == null) {
+                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
+                                       TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
+                       }
+
                        return ok;
                }
                
@@ -4723,10 +4841,22 @@ namespace Mono.CSharp {
                {
                        Using target = (Using) t;
 
-                       if (expression_or_block is Expression)
+                       if (expression_or_block is Expression) {
                                target.expression_or_block = ((Expression) expression_or_block).Clone (clonectx);
-                       else
-                               target.expression_or_block = ((Statement) expression_or_block).Clone (clonectx);
+                       } else {
+                               DictionaryEntry de = (DictionaryEntry) expression_or_block;
+                               ArrayList var_list = (ArrayList) de.Value;
+                               ArrayList target_var_list = new ArrayList (var_list.Count);
+
+                               foreach (DictionaryEntry de_variable in var_list)
+                                       target_var_list.Add (new DictionaryEntry (
+                                               ((Expression) de_variable.Key).Clone (clonectx),
+                                               ((Expression) de_variable.Value).Clone (clonectx)));
+
+                               target.expression_or_block = new DictionaryEntry (
+                                       ((Expression) de.Key).Clone (clonectx),
+                                       target_var_list);
+                       }
                        
                        target.Statement = Statement.Clone (clonectx);
                }
@@ -5027,6 +5157,16 @@ namespace Mono.CSharp {
                                        // way I could do this without a goto
                                        //
 
+                                       if (TypeManager.bool_movenext_void == null) {
+                                               TypeManager.bool_movenext_void = TypeManager.GetPredefinedMethod (
+                                                       TypeManager.ienumerator_type, "MoveNext", loc, Type.EmptyTypes);
+                                       }
+
+                                       if (TypeManager.ienumerator_getcurrent == null) {
+                                               TypeManager.ienumerator_getcurrent = TypeManager.GetPredefinedProperty (
+                                                       TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type);
+                                       }
+
 #if GMCS_SOURCE
                                        //
                                        // Prefer a generic enumerator over a non-generic one.
@@ -5328,6 +5468,11 @@ namespace Mono.CSharp {
                                if (is_disposable) {
                                        ResolveFinally (branching);
                                        ec.EndFlowBranching ();
+
+                                       if (TypeManager.void_dispose_void == null) {
+                                               TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
+                                                       TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
+                                       }
                                } else
                                        emit_finally = true;