2008-04-25 Marek Safar <marek.safar@gmail.com>
authorMarek Safar <marek.safar@gmail.com>
Fri, 25 Apr 2008 19:47:09 +0000 (19:47 -0000)
committerMarek Safar <marek.safar@gmail.com>
Fri, 25 Apr 2008 19:47:09 +0000 (19:47 -0000)
* ecore.cs, expression.cs, nullable.cs: Implemeted enum binary add operation
for incompatible underlying types, more to come, uff.

svn path=/trunk/mcs/; revision=101870

mcs/mcs/ChangeLog
mcs/mcs/ecore.cs
mcs/mcs/expression.cs
mcs/mcs/nullable.cs

index 66ba5ae326eefec555332a73fda3badc57fc3b33..b21682e0b6c89e9e0cb4083fdcf8d30d5e035348 100644 (file)
@@ -1,9 +1,14 @@
+2008-04-25  Marek Safar  <marek.safar@gmail.com>
+
+       * ecore.cs, expression.cs, nullable.cs: Implemeted enum binary add operation
+       for incompatible underlying types, more to come, uff.
+
 2008-04-26  Raja R Harinath  <harinath@hurrynot.org>
 
        Fix gtest-388.cs
        * expression.cs (VariableReference.EmitAssign) <source is NewInstance>:
        Handle 'leave_copy'.
-
+       
 2008-04-25  Marek Safar  <marek.safar@gmail.com>
 
        * expression.cs, nullable.cs: Implemented UnaryPlus expression.
index e6df05200f6cf290fb65725404f82fd2e7320074..0cde0c9aa7c1b0191751de0f8ff04c279c2bae29 100644 (file)
@@ -1379,14 +1379,32 @@ namespace Mono.CSharp {
 
                        target.child = child.Clone (clonectx);
                }
+
+               public override bool IsNull {
+                       get     {
+                               return child.IsNull;
+                       }
+               }
        }
 
        public class EmptyCast : TypeCast {
+               bool is_implicit;
+
                EmptyCast (Expression child, Type target_type)
                        : base (child, target_type)
                {
                }
-               
+
+               //
+               // HACK: This is just temporary hack before real EmptyCast clean-up required by expression trees
+               //
+               public static Expression Create (Expression child, Type type, bool is_implicit)
+               {
+                       EmptyCast e = new EmptyCast (child, type);
+                       e.is_implicit = true;
+                       return e;
+               }
+
                public static Expression Create (Expression child, Type type)
                {
                        Constant c = child as Constant;
@@ -1396,6 +1414,14 @@ namespace Mono.CSharp {
                        return new EmptyCast (child, type);
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       if (is_implicit)
+                               return child.CreateExpressionTree (ec);
+                       else
+                               return base.CreateExpressionTree (ec);
+               }
+
                public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
                {
                        child.EmitBranchable (ec, label, on_true);
index 302d53cdaad4e9bd0865d93a12d62ab2c0beb87d..dfaba8d3d1e1b5c42c5a7a2f159573f9bf8ccfe7 100644 (file)
@@ -1848,6 +1848,7 @@ namespace Mono.CSharp {
                readonly Operator oper;
                protected Expression left, right;
                readonly bool is_compound;
+               Expression enum_conversion;
 
                // This must be kept in sync with Operator!!!
                public static readonly string [] oper_names;
@@ -2025,6 +2026,9 @@ namespace Mono.CSharp {
                        Expression expr;
                        bool primitives_only = false;
 
+                       if (standard_operators == null)
+                               CreateStandardOperatorsTable ();
+
                        //
                        // Handles predefined primitive types
                        //
@@ -2070,10 +2074,7 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       if (standard_operators == null)
-                               CreateStandardOperatorsTable ();
-
-                       return ResolveOperatorPredefined (ec, standard_operators, primitives_only);
+                       return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
                }
 
                // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
@@ -2285,7 +2286,7 @@ namespace Mono.CSharp {
                        if (ltype != int32) {
                                Constant c = left as Constant;
                                if (c != null)
-                                       temp = c.ImplicitConversionRequired (int32, loc);
+                                       temp = c.ConvertImplicitly (int32);
                                else
                                        temp = Convert.ImplicitNumericConversion (left, int32);
 
@@ -2297,7 +2298,7 @@ namespace Mono.CSharp {
                        if (rtype != int32) {
                                Constant c = right as Constant;
                                if (c != null)
-                                       temp = c.ImplicitConversionRequired (int32, loc);
+                                       temp = c.ConvertImplicitly (int32);
                                else
                                        temp = Convert.ImplicitNumericConversion (right, int32);
 
@@ -2466,7 +2467,7 @@ namespace Mono.CSharp {
                //
                // Enumeration operators
                //
-               Binary ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
+               Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
                {
                        Expression temp;
 
@@ -2512,13 +2513,17 @@ namespace Mono.CSharp {
                                //
                                if (oper == Operator.Addition || oper == Operator.Subtraction) {
                                        underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
-                                       temp = Convert.ImplicitConversion (ec, right, underlying_type, loc);
-                                       if (temp == null)
+                                       temp = left;
+                                       left = EmptyCast.Create (left, underlying_type, true);
+                                       if (!DoBinaryOperatorPromotion (ec)) {
+                                               left = temp;
                                                return null;
+                                       }
 
-                                       right = temp;
-                                       type = ltype;
-                                       return this;
+                                       enum_conversion = Convert.ExplicitNumericConversion (
+                                               new EmptyExpression (left.Type), underlying_type);
+
+                                       return ResolveOperatorPredefined (ec, standard_operators, true, ltype);
                                }
 
                                return null;
@@ -2702,13 +2707,13 @@ namespace Mono.CSharp {
                        if (pointer_operators == null)
                                CreatePointerOperatorsTable ();
 
-                       return ResolveOperatorPredefined (ec, pointer_operators, false);
+                       return ResolveOperatorPredefined (ec, pointer_operators, false, null);
                }
 
                //
                // Build-in operators method overloading
                //
-               protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only)
+               protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
                {
                        PredefinedOperator best_operator = null;
                        Type l = left.Type;
@@ -2748,7 +2753,15 @@ namespace Mono.CSharp {
                        if (best_operator == null)
                                return null;
 
-                       return best_operator.ConvertResult (ec, this);
+                       Expression expr = best_operator.ConvertResult (ec, this);
+                       if (enum_type == null)
+                               return expr;
+
+                       //
+                       // HACK: required by enum_conversion
+                       //
+                       expr.Type = enum_type;
+                       return EmptyCast.Create (expr, enum_type);
                }
 
                //
@@ -3258,6 +3271,13 @@ namespace Mono.CSharp {
                        }
 
                        ig.Emit (opcode);
+
+                       //
+                       // Nullable enum could require underlying type cast and we cannot simply wrap binary
+                       // expression because that would wrap lifted binary operation
+                       //
+                       if (enum_conversion != null)
+                               enum_conversion.Emit (ec);
                }
 
                public override void EmitSideEffect (EmitContext ec)
index 34fd13da6127ee48e4388f0e2d8632d9f0deda41..b889ca5acb3c35ddd9741959bbf0bf09b59ebb6f 100644 (file)
@@ -692,7 +692,7 @@ namespace Mono.CSharp.Nullable
                        //
                        // Either left or right is null
                        //
-                       if (left_unwrap != null && right.IsNull) {
+                       if (left_unwrap != null && (right_null_lifted || right.IsNull)) {
                                left_unwrap.EmitCheck (ec);
                                if (Oper == Binary.Operator.Equality) {
                                        ig.Emit (OpCodes.Ldc_I4_0);
@@ -701,7 +701,7 @@ namespace Mono.CSharp.Nullable
                                return true;
                        }
 
-                       if (right_unwrap != null && left.IsNull) {
+                       if (right_unwrap != null && (left_null_lifted || left.IsNull)) {
                                right_unwrap.EmitCheck (ec);
                                if (Oper == Binary.Operator.Equality) {
                                        ig.Emit (OpCodes.Ldc_I4_0);
@@ -881,7 +881,7 @@ namespace Mono.CSharp.Nullable
                                        return null;
 
                                wrap_ctor = new NullableInfo (lifted_type.Type).Constructor;
-                               res_expr.Type = lifted_type.Type;
+                               type = res_expr.Type = lifted_type.Type;
                        }
 
                        if (left_null_lifted) {
@@ -913,11 +913,11 @@ namespace Mono.CSharp.Nullable
                        return res_expr;
                }
 
-               protected override Expression ResolveOperatorPredefined (EmitContext ec, Binary.PredefinedOperator [] operators, bool primitives_only)
+               protected override Expression ResolveOperatorPredefined (EmitContext ec, Binary.PredefinedOperator [] operators, bool primitives_only, Type enum_type)
                {
-                       Expression e = base.ResolveOperatorPredefined (ec, operators, primitives_only);
+                       Expression e = base.ResolveOperatorPredefined (ec, operators, primitives_only, enum_type);
 
-                       if (e == this)
+                       if (e == this || enum_type != null)
                                return LiftResult (ec, e);
 
                        //