-// CS1003: Syntax error, `.' expected
+// CS1525: Unexpected symbol `::', expecting `.' or `{'
// Line: 4
namespace a::b
switch (oper){
case Binary.Operator.BitwiseOr:
+ //
+ // bool? operator &(bool? x, bool? y);
+ //
+ if ((lt == TypeManager.bool_type && right is NullLiteral) ||
+ (rt == TypeManager.bool_type && left is NullLiteral)) {
+ var b = new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
+
+ // false | null => null
+ // null | false => null
+ if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
+ return Nullable.LiftedNull.CreateFromExpression (ec, b);
+
+ // true | null => true
+ // null | true => true
+ return ReducedExpression.Create (new BoolConstant (true, loc).Resolve (ec), b);
+ }
+
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
return null;
break;
case Binary.Operator.BitwiseAnd:
+ //
+ // bool? operator &(bool? x, bool? y);
+ //
+ if ((lt == TypeManager.bool_type && right is NullLiteral) ||
+ (rt == TypeManager.bool_type && left is NullLiteral)) {
+ var b = new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
+
+ // false & null => false
+ // null & false => false
+ if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
+ return ReducedExpression.Create (new BoolConstant (false, loc).Resolve (ec), b);
+
+ // true & null => null
+ // null & true => null
+ return Nullable.LiftedNull.CreateFromExpression (ec, b);
+ }
+
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
return null;
break;
case Binary.Operator.Equality:
- if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (lt)) {
+ if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (rt) ||
+ (left is Nullable.LiftedNull && right.IsNull) ||
+ (right is Nullable.LiftedNull && left.IsNull)) {
if (left.IsNull || right.IsNull) {
return ReducedExpression.Create (
new BoolConstant (left.IsNull == right.IsNull, left.Location).Resolve (ec),
return new BoolConstant (bool_res, left.Location);
case Binary.Operator.Inequality:
- if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (lt)) {
+ if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (rt) ||
+ (left is Nullable.LiftedNull && right.IsNull) ||
+ (right is Nullable.LiftedNull && left.IsNull)) {
if (left.IsNull || right.IsNull) {
return ReducedExpression.Create (
new BoolConstant (left.IsNull != right.IsNull, left.Location).Resolve (ec),
var c = b.right as Constant;
if (c != null) {
- if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr || b.oper == Operator.Subtraction))
+ if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
return ReducedExpression.Create (b.left, b).Resolve (ec);
if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
return ReducedExpression.Create (b.left, b).Resolve (ec);
c = b.left as Constant;
if (c != null) {
- if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr))
+ if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
return ReducedExpression.Create (b.right, b).Resolve (ec);
if (b.oper == Operator.Multiply && c.IsOneInteger)
return ReducedExpression.Create (b.right, b).Resolve (ec);
if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
Constant rc = right as Constant;
Constant lc = left as Constant;
- if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
+ if (((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) && !(this is Nullable.LiftedBinaryOperator)) {
//
// The result is a constant with side-effect
//
return new LiftedNull (nullable, loc);
}
- public static Expression CreateFromExpression (ResolveContext ec, Expression e)
+ public static Constant CreateFromExpression (ResolveContext ec, Expression e)
{
ec.Report.Warning (458, 2, e.Location, "The result of the expression is always `null' of type `{0}'",
TypeManager.CSharpName (e.Type));
bool IsBitwiseBoolean {
get {
- return (Oper & Operator.BitwiseMask) != 0 && left_unwrap != null && right_unwrap != null &&
- left_unwrap.Type == TypeManager.bool_type && right_unwrap.Type == TypeManager.bool_type;
+ return (Oper & Operator.BitwiseMask) != 0 &&
+ ((left_unwrap != null && left_unwrap.Type == TypeManager.bool_type) ||
+ (right_unwrap != null && right_unwrap.Type == TypeManager.bool_type));
}
}
// with the null literal *outside* of a generics context and
// inlines that as true or false.
//
- Expression CreateNullConstant (ResolveContext ec, Expression expr)
+ Constant CreateNullConstant (ResolveContext ec, Expression expr)
{
// FIXME: Handle side effect constants
Constant c = new BoolConstant (Oper == Operator.Inequality, loc).Resolve (ec);
Label load_right = ec.DefineLabel ();
Label end_label = ec.DefineLabel ();
+ // null & value, null | value
+ if (left_unwrap == null) {
+ left_unwrap = right_unwrap;
+ right_unwrap = null;
+ right = left;
+ }
+
left_unwrap.Emit (ec);
ec.Emit (OpCodes.Brtrue_S, load_right);
- right_unwrap.Emit (ec);
- ec.Emit (OpCodes.Brtrue_S, load_left);
+ // value & null, value | null
+ if (right_unwrap != null) {
+ right_unwrap.Emit (ec);
+ ec.Emit (OpCodes.Brtrue_S, load_left);
+ }
left_unwrap.EmitCheck (ec);
ec.Emit (OpCodes.Brfalse_S, load_right);
if (Oper == Operator.BitwiseAnd) {
left_unwrap.Load (ec);
} else {
- right_unwrap.Load (ec);
- right_unwrap = left_unwrap;
+ if (right_unwrap == null) {
+ right.Emit (ec);
+ if (right is EmptyConstantCast)
+ ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
+ } else {
+ right_unwrap.Load (ec);
+ right_unwrap = left_unwrap;
+ }
}
ec.Emit (OpCodes.Br_S, end_label);
// load right
ec.MarkLabel (load_right);
- right_unwrap.Load (ec);
+ if (right_unwrap == null) {
+ if (Oper == Operator.BitwiseAnd) {
+ right.Emit (ec);
+ if (right is EmptyConstantCast)
+ ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
+ } else {
+ left_unwrap.Load (ec);
+ }
+ } else {
+ right_unwrap.Load (ec);
+ }
ec.MarkLabel (end_label);
}
if (IsLeftNullLifted) {
left = LiftedNull.Create (right.Type, left.Location);
+ //
+ // Special case for bool?, the result depends on both null right side and left side value
+ //
+ if ((Oper == Operator.BitwiseAnd || Oper == Operator.BitwiseOr) && NullableInfo.GetUnderlyingType (type) == TypeManager.bool_type) {
+ return res_expr;
+ }
+
if ((Oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0)
return LiftedNull.CreateFromExpression (ec, res_expr);
if (IsRightNullLifted) {
right = LiftedNull.Create (left.Type, right.Location);
+ //
+ // Special case for bool?, the result depends on both null right side and left side value
+ //
+ if ((Oper == Operator.BitwiseAnd || Oper == Operator.BitwiseOr) && NullableInfo.GetUnderlyingType (type) == TypeManager.bool_type) {
+ return res_expr;
+ }
+
if ((Oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0)
return LiftedNull.CreateFromExpression (ec, res_expr);
--- /dev/null
+// lifted null binary operators
+
+using System;
+
+class C
+{
+ public static int Main ()
+ {
+ bool v;
+ v = (true & null) == null;
+ if (!v)
+ return 1;
+
+ v = (false & null) != null;
+ if (!v)
+ return 2;
+
+ v = (null & true) == null;
+ if (!v)
+ return 3;
+
+ v = (null & false) != null;
+ if (!v)
+ return 4;
+
+ v = (true | null) == null;
+ if (v != false)
+ return 11;
+
+ v = (false | null) != null;
+ if (v != false)
+ return 12;
+
+ v = (null | true) == null;
+ if (v != false)
+ return 13;
+
+ v = (null | false) != null;
+ if (v != false)
+ return 14;
+
+ v = (null & 1) == null;
+ if (v != true)
+ return 20;
+
+ v = (null & 0) != null;
+ if (v != false)
+ return 21;
+
+ bool? a = false;
+ bool? b = true;
+
+ if ((a & null) != false)
+ return 50;
+
+ if ((b & null) != null)
+ return 51;
+
+ if ((null & a) != false)
+ return 52;
+
+ if ((null & b) != null)
+ return 53;
+
+ if ((a & true) != false)
+ return 54;
+
+ if ((true & a) != false)
+ return 55;
+
+ if ((a | null) != null)
+ return 60;
+
+ if ((b | null) != true)
+ return 61;
+
+ if ((null | a) != null)
+ return 62;
+
+ if ((null | b) != true)
+ return 63;
+
+ if ((a | true) != true)
+ return 64;
+
+ if ((true | a) != true)
+ return 65;
+
+ return 0;
+ }
+}
\ No newline at end of file
<size>7</size>
</method>
<method name="Int32 Main()">
- <size>94</size>
+ <size>74</size>
</method>
</type>
<type name="D">
<size>26</size>
</method>
<method name="Void Main()">
- <size>98</size>
+ <size>88</size>
</method>
</type>
</test>
</method>
</type>
</test>
+ <test name="gtest-540.cs">
+ <type name="C">
+ <method name="Int32 Main()">
+ <size>809</size>
+ </method>
+ <method name="Void .ctor()">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
<test name="gtest-anon-1.cs">
<type name="X">
<method name="Void .ctor()">
<size>7</size>
</method>
<method name="Void ZeroBasedReductions()">
- <size>18</size>
+ <size>17</size>
</method>
<method name="Void Main()">
<size>11</size>