void EmitRelationalBinary (EmitContext ec)
{
- if (!IsLifted)
+ if (!IsLifted) {
EmitNonLiftedBinary (ec);
- else if (IsLiftedToNull)
+ return;
+ }
+
+ if (IsLiftedToNull) {
EmitLiftedToNullBinary (ec);
- else
- EmitLiftedRelationalBinary (ec);
+ return;
+ }
+
+ if (ConstantExpression.IsNull (right) && !ConstantExpression.IsNull (left) && left.Type.IsNullable ()) {
+ EmitNullEquality (ec, left);
+ return;
+ }
+
+ if (ConstantExpression.IsNull (left) && !ConstantExpression.IsNull (right) && right.Type.IsNullable ()) {
+ EmitNullEquality (ec, right);
+ return;
+ }
+
+ EmitLiftedRelationalBinary (ec);
+ }
+
+ void EmitNullEquality (EmitContext ec, Expression e)
+ {
+ var ig = ec.ig;
+
+ if (IsLiftedToNull) {
+ e.Emit (ec);
+ if (e.Type != typeof (void))
+ ig.Emit (OpCodes.Pop);
+
+ ec.EmitNullableNew (typeof (bool?));
+ return;
+ }
+
+ var se = ec.EmitStored (e);
+ ec.EmitNullableHasValue (se);
+ if (NodeType == ExpressionType.Equal) {
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Ceq);
+ }
}
void EmitLiftedUserDefinedOperator (EmitContext ec)
{
this.value = value;
}
+
+ internal static bool IsNull (Expression e)
+ {
+ var c = e as ConstantExpression;
+ return c != null && c.value == null;
+ }
#if !FULL_AOT_RUNTIME
internal override void Emit (EmitContext ec)
if (ltype == rtype && ultype == typeof (bool))
return null;
+
+ if (ltype.IsNullable () && ConstantExpression.IsNull (right) && !ConstantExpression.IsNull (left))
+ return null;
+
+ if (rtype.IsNullable () && ConstantExpression.IsNull (left) && !ConstantExpression.IsNull (right))
+ return null;
}
if (oper_name == "op_LeftShift" || oper_name == "op_RightShift") {
if (!left.Type.IsNullable () && !right.Type.IsNullable ()) {
is_lifted = false;
liftToNull = false;
- type = typeof (bool);
+ type = typeof(bool);
} else if (left.Type.IsNullable () && right.Type.IsNullable ()) {
is_lifted = true;
- type = liftToNull ? typeof (bool?) : typeof (bool);
- } else
+ type = liftToNull ? typeof(bool?) : typeof(bool);
+ } else if (ConstantExpression.IsNull (left) || ConstantExpression.IsNull (right)) {
+ is_lifted = true;
+ type = typeof (bool);
+ } else {
throw new InvalidOperationException ();
+ }
} else {
var parameters = method.GetParameters ();
Assert.AreEqual (false, eq (Foo.Bar, null));
Assert.AreEqual (true, eq (null, null));
}
+
+ [Test]
+ public void NullableNullEqual ()
+ {
+ var param = Expression.Parameter (typeof (DateTime?), "x");
+
+ var node = Expression.Equal (param, Expression.Constant (null));
+
+ Assert.IsTrue (node.IsLifted);
+ Assert.IsFalse (node.IsLiftedToNull);
+ Assert.AreEqual (typeof (bool), node.Type);
+ Assert.IsNull (node.Method);
+
+ var eq = Expression.Lambda<Func<DateTime?, bool>> (node, new [] { param }).Compile ();
+
+ Assert.AreEqual (true, eq (null));
+ Assert.AreEqual (false, eq (DateTime.Now));
+ }
}
}