Better check for instance equality of generic types. Fixes #15100
[mono.git] / mcs / mcs / cfold.cs
index e2f6fbdb9102c8113fdb63c2271ad2244a0ab57a..96062f2748e744c51360f607ad2de8f492dc889d 100644 (file)
@@ -183,11 +183,11 @@ namespace Mono.CSharp {
                        switch (oper){
                        case Binary.Operator.BitwiseOr:
                                //
-                               // bool? operator &(bool? x, bool? y);
+                               // bool? operator |(bool? x, bool? y);
                                //
                                if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) ||
                                        (rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) {
-                                       var b = new Nullable.LiftedBinaryOperator (oper, left, right).Resolve (ec);
+                                       var b = new Binary (oper, left, right).ResolveOperator (ec);
 
                                        // false | null => null
                                        // null | false => null
@@ -231,7 +231,7 @@ namespace Mono.CSharp {
                                //
                                if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) ||
                                        (rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) {
-                                       var b = new Nullable.LiftedBinaryOperator (oper, left, right).Resolve (ec);
+                                       var b = new Binary (oper, left, right).ResolveOperator (ec);
 
                                        // false & null => false
                                        // null & false => false
@@ -299,25 +299,51 @@ namespace Mono.CSharp {
                                break;
 
                        case Binary.Operator.Addition:
-                               if (lt == InternalType.NullLiteral)
-                                       return right;
-
-                               if (rt == InternalType.NullLiteral)
-                                       return left;
-
                                //
-                               // If both sides are strings, then concatenate, if
-                               // one is a string, and the other is not, then defer
-                               // to runtime concatenation
+                               // If both sides are strings, then concatenate
+                               //
+                               // string operator + (string x, string y)
                                //
                                if (lt.BuiltinType == BuiltinTypeSpec.Type.String || rt.BuiltinType == BuiltinTypeSpec.Type.String){
                                        if (lt == rt)
                                                return new StringConstant (ec.BuiltinTypes, (string)left.GetValue () + (string)right.GetValue (),
                                                        left.Location);
-                                       
+
+                                       if (lt == InternalType.NullLiteral)
+                                               return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location);
+
+                                       if (rt == InternalType.NullLiteral)
+                                               return new StringConstant (ec.BuiltinTypes, left.GetValue () + "", left.Location);
+
                                        return null;
                                }
 
+                               //
+                               // string operator + (string x, object y)
+                               //
+                               if (lt == InternalType.NullLiteral) {
+                                       if (rt.BuiltinType == BuiltinTypeSpec.Type.Object)
+                                               return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location);
+
+                                       if (lt == rt) {
+                                               ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
+                                                       "+", lt.GetSignatureForError (), rt.GetSignatureForError ());
+                                               return null;
+                                       }
+
+                                       return right;
+                               }
+
+                               //
+                               // string operator + (object x, string y)
+                               //
+                               if (rt == InternalType.NullLiteral) {
+                                       if (lt.BuiltinType == BuiltinTypeSpec.Type.Object)
+                                               return new StringConstant (ec.BuiltinTypes, right.GetValue () + "", left.Location);
+       
+                                       return left;
+                               }
+
                                //
                                // handle "E operator + (E x, U y)"
                                // handle "E operator + (Y y, E x)"
@@ -469,7 +495,7 @@ namespace Mono.CSharp {
                                if (left is NullLiteral && right is NullLiteral) {
                                        var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
                                        lifted_int.ResolveAsType (ec);
-                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right).Resolve (ec);
+                                       return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
                                }
 
                                if (!DoBinaryNumericPromotions (ec, ref left, ref right))
@@ -566,7 +592,7 @@ namespace Mono.CSharp {
                                if (left is NullLiteral && right is NullLiteral) {
                                        var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
                                        lifted_int.ResolveAsType (ec);
-                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right).Resolve (ec);
+                                       return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
                                }
 
                                if (!DoBinaryNumericPromotions (ec, ref left, ref right))
@@ -662,7 +688,7 @@ namespace Mono.CSharp {
                                if (left is NullLiteral && right is NullLiteral) {
                                        var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
                                        lifted_int.ResolveAsType (ec);
-                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right).Resolve (ec);
+                                       return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
                                }
 
                                if (!DoBinaryNumericPromotions (ec, ref left, ref right))
@@ -762,7 +788,7 @@ namespace Mono.CSharp {
                                if (left is NullLiteral && right is NullLiteral) {
                                        var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
                                        lifted_int.ResolveAsType (ec);
-                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right).Resolve (ec);
+                                       return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
                                }
 
                                if (!DoBinaryNumericPromotions (ec, ref left, ref right))
@@ -852,7 +878,7 @@ namespace Mono.CSharp {
                                if (left is NullLiteral && right is NullLiteral) {
                                        var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
                                        lifted_int.ResolveAsType (ec);
-                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right).Resolve (ec);
+                                       return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
                                }
 
                                IntConstant ic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
@@ -873,7 +899,7 @@ namespace Mono.CSharp {
 
                                // null << value => null
                                if (left is NullLiteral)
-                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right).Resolve (ec);
+                                       return (Constant) new Binary (oper, left, right).ResolveOperator (ec);
 
                                left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
                                if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
@@ -889,12 +915,12 @@ namespace Mono.CSharp {
                                if (left is NullLiteral && right is NullLiteral) {
                                        var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
                                        lifted_int.ResolveAsType (ec);
-                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right).Resolve (ec);
+                                       return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
                                }
 
                                IntConstant sic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
                                if (sic == null){
-                                       Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc); ;
+                                       Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
                                        return null;
                                }
                                int rshift_val = sic.Value;
@@ -909,7 +935,7 @@ namespace Mono.CSharp {
 
                                // null >> value => null
                                if (left is NullLiteral)
-                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right).Resolve (ec);
+                                       return (Constant) new Binary (oper, left, right).ResolveOperator (ec);
 
                                left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
                                if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
@@ -1011,11 +1037,7 @@ namespace Mono.CSharp {
                                        if (left is NullLiteral) {
                                                var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
                                                lifted_int.ResolveAsType (ec);
-                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right).Resolve (ec);
-                                       }
-
-                                       if (left is Nullable.LiftedNull) {
-                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right).Resolve (ec);
+                                               return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
                                        }
                                }
 
@@ -1051,11 +1073,7 @@ namespace Mono.CSharp {
                                        if (left is NullLiteral) {
                                                var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
                                                lifted_int.ResolveAsType (ec);
-                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right).Resolve (ec);
-                                       }
-
-                                       if (left is Nullable.LiftedNull) {
-                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right).Resolve (ec);
+                                               return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
                                        }
                                }
 
@@ -1091,11 +1109,7 @@ namespace Mono.CSharp {
                                        if (left is NullLiteral) {
                                                var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
                                                lifted_int.ResolveAsType (ec);
-                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right).Resolve (ec);
-                                       }
-
-                                       if (left is Nullable.LiftedNull) {
-                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right).Resolve (ec);
+                                               return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
                                        }
                                }
 
@@ -1131,11 +1145,7 @@ namespace Mono.CSharp {
                                        if (left is NullLiteral) {
                                                var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
                                                lifted_int.ResolveAsType (ec);
-                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right).Resolve (ec);
-                                       }
-
-                                       if (left is Nullable.LiftedNull) {
-                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right).Resolve (ec);
+                                               return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
                                        }
                                }