Added few unsafe tests.
[mono.git] / mcs / mcs / expression.cs
index a5659dcb1ed6d86ac08c514af201cf01bf11bc9a..90d72ecf3ece0079f028bb466b27c4a3442ea17d 100644 (file)
@@ -143,6 +143,7 @@ namespace Mono.CSharp {
 
                public readonly Operator Oper;
                public Expression Expr;
+               Expression enum_conversion;
 
                public Unary (Operator op, Expression expr, Location loc)
                {
@@ -321,6 +322,8 @@ namespace Mono.CSharp {
 
                protected Expression ResolveOperator (EmitContext ec, Expression expr)
                {
+                       eclass = ExprClass.Value;
+
                        if (predefined_operators == null)
                                CreatePredefinedOperatorsTable ();
 
@@ -343,19 +346,25 @@ namespace Mono.CSharp {
                        //
                        // E operator ~(E x);
                        //
-                       if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type)) {
-                               best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, TypeManager.GetEnumUnderlyingType (expr_type)));
-                               if (best_expr == null)
-                                       return null;
-
-                               Expr = EmptyCast.Create (best_expr, expr_type);
-                               type = Expr.Type;
-                               return this;
-                       }
+                       if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
+                               return ResolveEnumOperator (ec, expr);
 
                        return ResolveUserType (ec, expr);
                }
 
+               protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
+               {
+                       Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
+                       Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
+                       if (best_expr == null)
+                               return null;
+
+                       Expr = best_expr;
+                       enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
+                       type = expr.Type;
+                       return EmptyCast.Create (this, type);
+               }
+
                public override Expression CreateExpressionTree (EmitContext ec)
                {
                        return CreateExpressionTree (ec, null);
@@ -365,6 +374,9 @@ namespace Mono.CSharp {
                {
                        string method_name;
                        switch (Oper) {
+                       case Operator.AddressOf:
+                               Error_PointerInsideExpressionTree ();
+                               return null;
                        case Operator.UnaryNegation:
                                if (ec.CheckState && user_op == null && !IsFloat (type))
                                        method_name = "NegateChecked";
@@ -449,8 +461,6 @@ namespace Mono.CSharp {
 
                public override Expression DoResolve (EmitContext ec)
                {
-                       eclass = ExprClass.Value;
-
                        if (Oper == Operator.AddressOf) {
                                Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
 
@@ -544,6 +554,12 @@ namespace Mono.CSharp {
                                throw new Exception ("This should not happen: Operator = "
                                                     + Oper.ToString ());
                        }
+
+                       //
+                       // Same trick as in Binary expression
+                       //
+                       if (enum_conversion != null)
+                               enum_conversion.Emit (ec);
                }
 
                public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
@@ -639,6 +655,7 @@ namespace Mono.CSharp {
                        }
 
                        type = TypeManager.GetPointerType (Expr.Type);
+                       eclass = ExprClass.Value;
                        return this;
                }
 
@@ -754,6 +771,12 @@ namespace Mono.CSharp {
                        this.expr = expr;
                        loc = l;
                }
+
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Error_PointerInsideExpressionTree ();
+                       return null;
+               }
                
                public override void Emit (EmitContext ec)
                {
@@ -2469,94 +2492,112 @@ namespace Mono.CSharp {
                //
                Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
                {
-                       Expression temp;
+                       //
+                       // bool operator == (E x, E y);
+                       // bool operator != (E x, E y);
+                       // bool operator < (E x, E y);
+                       // bool operator > (E x, E y);
+                       // bool operator <= (E x, E y);
+                       // bool operator >= (E x, E y);
+                       //
+                       // E operator & (E x, E y);
+                       // E operator | (E x, E y);
+                       // E operator ^ (E x, E y);
+                       //
+                       // U operator - (E e, E f)
+                       // E operator - (E e, U x)
+                       //
+                       // E operator + (U x, E e)
+                       // E operator + (E e, U x)
+                       //
+                       if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
+                               (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
+                               return null;
 
-                       if (lenum || renum) {
-                               //
-                               // bool operator == (E x, E y);
-                               // bool operator != (E x, E y);
-                               // bool operator < (E x, E y);
-                               // bool operator > (E x, E y);
-                               // bool operator <= (E x, E y);
-                               // bool operator >= (E x, E y);
-                               //
-                               if ((oper & Operator.ComparisonMask) != 0) {
-                                       type = TypeManager.bool_type;
-                               } else if ((oper & Operator.BitwiseMask) != 0) {
-                                       type = ltype;
-                               }
+                       Expression ltemp = left;
+                       Expression rtemp = right;
+                       Type underlying_type;
 
-                               if (type != null) {
-                                       if (!TypeManager.IsEqual (ltype, rtype)) {
-                                               if (!lenum) {
-                                                       temp = Convert.ImplicitConversion (ec, left, rtype, loc);
-                                                       if (temp == null)
-                                                               return null;
-                                                       left = temp;
-                                               } else {
-                                                       temp = Convert.ImplicitConversion (ec, right, ltype, loc);
-                                                       if (temp == null)
-                                                               return null;
-                                                       right = temp;
-                                               }
-                                       }
+                       if (TypeManager.IsEqual (ltype, rtype)) {
+                               underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
 
-                                       return this;
-                               }
-                       }
+                               if (left is Constant)
+                                       left = ((Constant) left).ConvertExplicitly (false, underlying_type);
+                               else
+                                       left = EmptyCast.Create (left, underlying_type);
 
-                       Type underlying_type;
-                       if (lenum && !renum) {
-                               //
-                               // E operator + (E e, U x)
-                               // E operator - (E e, U x)
-                               //
-                               if (oper == Operator.Addition || oper == Operator.Subtraction) {
-                                       underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
-                                       temp = left;
-                                       left = EmptyCast.Create (left, underlying_type, true);
-                                       if (!DoBinaryOperatorPromotion (ec)) {
-                                               left = temp;
+                               if (right is Constant)
+                                       right = ((Constant) right).ConvertExplicitly (false, underlying_type);
+                               else
+                                       right = EmptyCast.Create (right, underlying_type);
+                       } else if (lenum) {
+                               if (oper != Operator.Subtraction && oper != Operator.Addition) {
+                                       Constant c = right as Constant;
+                                       if (c == null || !c.IsDefaultValue)
                                                return null;
-                                       }
-
-                                       enum_conversion = Convert.ExplicitNumericConversion (
-                                               new EmptyExpression (left.Type), underlying_type);
+                               }
 
-                                       return ResolveOperatorPredefined (ec, standard_operators, true, ltype);
+                               underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
+                               if (left is Constant)
+                                       left = ((Constant) left).ConvertExplicitly (false, underlying_type);
+                               else
+                                       left = EmptyCast.Create (left, underlying_type);
+                       } else if (renum) {
+                               if (oper != Operator.Addition) {
+                                       Constant c = left as Constant;
+                                       if (c == null || !c.IsDefaultValue)
+                                               return null;
                                }
 
+                               underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
+                               if (right is Constant)
+                                       right = ((Constant) right).ConvertExplicitly (false, underlying_type);
+                               else
+                                       right = EmptyCast.Create (right, underlying_type);
+                       } else {
                                return null;
                        }
 
-                       if (renum) {
-                               //
-                               // E operator + (U x, E e)
-                               //
-                               if (oper == Operator.Addition) {
-                                       underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
-                                       temp = Convert.ImplicitConversion (ec, left, underlying_type, loc);
-                                       if (temp == null)
-                                               return null;
+                       //
+                       // C# specification uses explicit cast syntax which means binary promotion
+                       // should happen, however it seems that csc does not do that
+                       //
+                       if (!DoBinaryOperatorPromotion (ec)) {
+                               left = ltemp;
+                               right = rtemp;
+                               return null;
+                       }
 
-                                       left = temp;
-                                       type = rtype;
-                                       return this;
-                               }
+                       Type res_type = null;
+                       if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
+                               Type promoted_type = lenum ? left.Type : right.Type;
+                               enum_conversion = Convert.ExplicitNumericConversion (
+                                       new EmptyExpression (promoted_type), underlying_type);
+
+                               if (oper == Operator.Subtraction && renum && lenum)
+                                       res_type = underlying_type;
+                               else if (oper == Operator.Addition && renum)
+                                       res_type = rtype;
+                               else
+                                       res_type = ltype;
                        }
+                       
+                       Expression expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
+                       if (!is_compound || expr == null)
+                               return expr;
 
                        //
-                       // U operator - (E e, E f)
+                       // TODO: Need to corectly implemented Coumpound Assigment for all operators
+                       // Section: 7.16.2
                        //
-                       if (oper == Operator.Subtraction) {
-                               if (!TypeManager.IsEqual (ltype, rtype))
-                                       return null;
+                       if (Convert.ImplicitConversionExists (ec, left, rtype))
+                               return expr;
 
-                               type = TypeManager.GetEnumUnderlyingType (ltype);
-                               return this;
-                       }
+                       if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
+                               return null;
 
-                       return null;
+                       expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
+                       return expr;
                }
 
                //
@@ -2639,6 +2680,8 @@ namespace Mono.CSharp {
                                        return null;
                        } else if (l.IsInterface) {
                                l = TypeManager.object_type;
+                       } else if (l.IsValueType) {
+                               return null;
                        }
 
                        if (rgen) {
@@ -2647,8 +2690,11 @@ namespace Mono.CSharp {
                                        return null;
                        } else if (r.IsInterface) {
                                r = TypeManager.object_type;
+                       } else if (r.IsValueType) {
+                               return null;
                        }
 
+
                        const string ref_comparison = "Possible unintended reference comparison. " +
                                "Consider casting the {0} side of the expression to `string' to compare the values";
 
@@ -3656,6 +3702,12 @@ namespace Mono.CSharp {
                        is_add = is_addition;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Error_PointerInsideExpressionTree ();
+                       return null;
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        eclass = ExprClass.Variable;
@@ -4471,6 +4523,9 @@ namespace Mono.CSharp {
 
                public bool Resolve (EmitContext ec, Location loc)
                {
+                       if (Expr == null)
+                               return false;
+
                        using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
                                // Verify that the argument is readable
                                if (ArgType != AType.Out)
@@ -6580,6 +6635,11 @@ namespace Mono.CSharp {
                        this.loc = loc;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        eclass = ExprClass.Variable;
@@ -6668,29 +6728,6 @@ namespace Mono.CSharp {
                }
        }
 
-       //
-       // This produces the value that renders an instance, used by the iterators code
-       //
-       public class ProxyInstance : Expression, IMemoryLocation  {
-               public override Expression DoResolve (EmitContext ec)
-               {
-                       eclass = ExprClass.Variable;
-                       type = ec.ContainerType;
-                       return this;
-               }
-               
-               public override void Emit (EmitContext ec)
-               {
-                       ec.ig.Emit (OpCodes.Ldarg_0);
-
-               }
-               
-               public void AddressOf (EmitContext ec, AddressOp mode)
-               {
-                       ec.ig.Emit (OpCodes.Ldarg_0);
-               }
-       }
-
        /// <summary>
        ///   Implements the typeof operator
        /// </summary>
@@ -6960,6 +6997,12 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Error_PointerInsideExpressionTree ();
+                       return null;
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
@@ -8758,6 +8801,12 @@ namespace Mono.CSharp {
                        eclass = ExprClass.Value;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Error_PointerInsideExpressionTree ();
+                       return null;
+               }
+
                public override void Emit(EmitContext ec)
                {
                        array.Emit (ec);
@@ -8800,34 +8849,24 @@ namespace Mono.CSharp {
        //
        // Encapsulates a conversion rules required for array indexes
        //
-       public class ArrayIndexCast : Expression
+       public class ArrayIndexCast : TypeCast
        {
-               Expression expr;
-
                public ArrayIndexCast (Expression expr)
+                       : base (expr, expr.Type)
                {
-                       this.expr = expr;
-                       this.loc = expr.Location;
                }
 
                public override Expression CreateExpressionTree (EmitContext ec)
                {
                        ArrayList args = new ArrayList (2);
-                       args.Add (new Argument (expr.CreateExpressionTree (ec)));
+                       args.Add (new Argument (child.CreateExpressionTree (ec)));
                        args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
                        return CreateExpressionFactoryCall ("ConvertChecked", args);
                }
 
-               public override Expression DoResolve (EmitContext ec)
-               {
-                       type = expr.Type;
-                       eclass = expr.eclass;
-                       return this;
-               }
-
                public override void Emit (EmitContext ec)
                {
-                       expr.Emit (ec);
+                       child.Emit (ec);
                                
                        if (type == TypeManager.int32_type)
                                return;
@@ -8843,45 +8882,6 @@ namespace Mono.CSharp {
                }
        }
 
-       //
-       // Used by the fixed statement
-       //
-       public class StringPtr : Expression {
-               LocalBuilder b;
-               
-               public StringPtr (LocalBuilder b, Location l)
-               {
-                       this.b = b;
-                       eclass = ExprClass.Value;
-                       type = TypeManager.char_ptr_type;
-                       loc = l;
-               }
-
-               public override Expression DoResolve (EmitContext ec)
-               {
-                       // This should never be invoked, we are born in fully
-                       // initialized state.
-
-                       return this;
-               }
-
-               public override void Emit (EmitContext ec)
-               {
-                       if (TypeManager.int_get_offset_to_string_data == null) {
-                               // TODO: Move to resolve !!
-                               TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
-                                       TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
-                       }
-
-                       ILGenerator ig = ec.ig;
-
-                       ig.Emit (OpCodes.Ldloc, b);
-                       ig.Emit (OpCodes.Conv_I);
-                       ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
-                       ig.Emit (OpCodes.Add);
-               }
-       }
-       
        //
        // Implements the `stackalloc' keyword
        //
@@ -8897,6 +8897,11 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        count = count.Resolve (ec);
@@ -8969,6 +8974,12 @@ namespace Mono.CSharp {
                {
                        this.Name = name;
                }
+               
+               protected override void CloneTo (CloneContext clonectx, Expression t)
+               {
+                       ElementInitializer target = (ElementInitializer) t;
+                       target.source = source.Clone (clonectx);
+               }
 
                public override Expression CreateExpressionTree (EmitContext ec)
                {
@@ -9088,6 +9099,15 @@ namespace Mono.CSharp {
                        return CreateExpressionFactoryCall ("ElementInit", args);
                }
 
+               protected override void CloneTo (CloneContext clonectx, Expression t)
+               {
+                       CollectionElementInitializer target = (CollectionElementInitializer) t;
+
+                       target.Arguments = new ArrayList (Arguments.Count);
+                       foreach (Expression e in Arguments)
+                               target.Arguments.Add (e.Clone (clonectx));
+               }
+
                public override Expression DoResolve (EmitContext ec)
                {
                        if (eclass != ExprClass.Invalid)
@@ -9253,7 +9273,7 @@ namespace Mono.CSharp {
                        public override Expression CreateExpressionTree (EmitContext ec)
                        {
                                // Should not be reached
-                               throw new NotSupportedException ();
+                               throw new NotSupportedException ("ET");
                        }
 
                        public override Expression DoResolve (EmitContext ec)
@@ -9490,6 +9510,11 @@ namespace Mono.CSharp {
                        t.initializer = initializer.Clone (clonectx);
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
                public override bool Equals (object o)
                {
                        AnonymousTypeParameter other = o as AnonymousTypeParameter;