ig.MarkLabel (done);
}
+ MethodInfo GetFalseOperator ()
+ {
+ return GetFalseOperator (left.Type.GetNotNullableType ());
+ }
+
+ MethodInfo GetTrueOperator ()
+ {
+ return GetTrueOperator (left.Type.GetNotNullableType ());
+ }
+
+ void EmitUserDefinedLogicalShortCircuit (EmitContext ec)
+ {
+ var ig = ec.ig;
+ var and = NodeType == ExpressionType.AndAlso;
+
+ var done = ig.DefineLabel ();
+
+ var left = ec.EmitStored (this.left);
+
+ ec.EmitLoad (left);
+ ig.Emit (OpCodes.Dup);
+ ec.EmitCall (and ? GetFalseOperator () : GetTrueOperator ());
+ ig.Emit (OpCodes.Brtrue, done);
+
+ ec.Emit (this.right);
+ ec.EmitCall (method);
+
+ ig.MarkLabel (done);
+ }
+
void EmitLiftedLogicalShortCircuit (EmitContext ec)
{
var ig = ec.ig;
ig.Emit (and ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1);
ig.MarkLabel (ret_new);
- ec.EmitNullableNew (typeof (bool?));
+ ec.EmitNullableNew (Type);
ig.Emit (OpCodes.Br, done);
ig.MarkLabel (ret_null);
- var ret = ig.DeclareLocal (typeof (bool?));
+ var ret = ig.DeclareLocal (Type);
ec.EmitNullableInitialize (ret);
ig.MarkLabel (done);
ig.MarkLabel (done);
}
+ void EmitConvertedCoalesce (EmitContext ec)
+ {
+ var ig = ec.ig;
+ var done = ig.DefineLabel ();
+ var load_right = ig.DefineLabel ();
+
+ var left = ec.EmitStored (this.left);
+
+ if (left.LocalType.IsNullable ())
+ ec.EmitNullableHasValue (left);
+ else
+ ec.EmitLoad (left);
+
+ ig.Emit (OpCodes.Brfalse, load_right);
+
+ ec.Emit (conversion);
+ ec.EmitLoad (left);
+ ig.Emit (OpCodes.Callvirt, conversion.Type.GetInvokeMethod ());
+
+ ig.Emit (OpCodes.Br, done);
+
+ ig.MarkLabel (load_right);
+ ec.Emit (this.right);
+
+ ig.MarkLabel (done);
+ }
+
static bool IsInt32OrInt64 (Type type)
{
return type == typeof (int) || type == typeof (long);
ig.Emit (is_unsigned ? OpCodes.Rem_Un : OpCodes.Rem);
break;
case ExpressionType.RightShift:
- ig.Emit (is_unsigned ? OpCodes.Shr_Un : OpCodes.Shr);
- break;
case ExpressionType.LeftShift:
- ig.Emit (OpCodes.Shl);
+ ig.Emit (OpCodes.Ldc_I4, left.Type == typeof (int) ? 0x1f : 0x3f);
+ ig.Emit (OpCodes.And);
+ if (NodeType == ExpressionType.RightShift)
+ ig.Emit (is_unsigned ? OpCodes.Shr_Un : OpCodes.Shr);
+ else
+ ig.Emit (OpCodes.Shl);
break;
case ExpressionType.And:
ig.Emit (OpCodes.And);
}
}
+ bool IsLeftLiftedBinary ()
+ {
+ return left.Type.IsNullable () && !right.Type.IsNullable ();
+ }
+
+ void EmitLeftLiftedToNullBinary (EmitContext ec)
+ {
+ var ig = ec.ig;
+
+ var ret = ig.DefineLabel ();
+ var done = ig.DefineLabel ();
+
+ var left = ec.EmitStored (this.left);
+
+ ec.EmitNullableHasValue (left);
+ ig.Emit (OpCodes.Brfalse, ret);
+
+ ec.EmitNullableGetValueOrDefault (left);
+ ec.Emit (right);
+
+ EmitBinaryOperator (ec);
+
+ ec.EmitNullableNew (Type);
+
+ ig.Emit (OpCodes.Br, done);
+
+ ig.MarkLabel (ret);
+
+ var temp = ig.DeclareLocal (Type);
+ ec.EmitNullableInitialize (temp);
+
+ ig.MarkLabel (done);
+ }
+
void EmitLiftedArithmeticBinary (EmitContext ec)
{
- EmitLiftedToNullBinary (ec);
+ if (IsLeftLiftedBinary ())
+ EmitLeftLiftedToNullBinary (ec);
+ else
+ EmitLiftedToNullBinary (ec);
}
void EmitLiftedToNullBinary (EmitContext ec)
void EmitLiftedUserDefinedOperator (EmitContext ec)
{
var ig = ec.ig;
- var eq = NodeType == ExpressionType.Equal;
var ret_true = ig.DefineLabel ();
var ret_false = ig.DefineLabel ();
ec.EmitNullableHasValue (left);
ec.EmitNullableHasValue (right);
- ig.Emit (OpCodes.Bne_Un, eq ? ret_false : ret_true);
-
- ec.EmitNullableHasValue (left);
- ig.Emit (OpCodes.Brfalse, eq ? ret_true : ret_false);
+ switch (NodeType) {
+ case ExpressionType.Equal:
+ ig.Emit (OpCodes.Bne_Un, ret_false);
+ ec.EmitNullableHasValue (left);
+ ig.Emit (OpCodes.Brfalse, ret_true);
+ break;
+ case ExpressionType.NotEqual:
+ ig.Emit (OpCodes.Bne_Un, ret_true);
+ ec.EmitNullableHasValue (left);
+ ig.Emit (OpCodes.Brfalse, ret_false);
+ break;
+ default:
+ ig.Emit (OpCodes.And);
+ ig.Emit (OpCodes.Brfalse, ret_false);
+ break;
+ }
ec.EmitNullableGetValueOrDefault (left);
ec.EmitNullableGetValueOrDefault (right);
ig.MarkLabel (done);
}
+ void EmitUserDefinedLiftedLogicalShortCircuit (EmitContext ec)
+ {
+ var ig = ec.ig;
+ var and = NodeType == ExpressionType.AndAlso;
+
+ var left_is_null = ig.DefineLabel ();
+ var ret_left = ig.DefineLabel ();
+ var ret_null = ig.DefineLabel ();
+ var done = ig.DefineLabel ();
+
+ var left = ec.EmitStored (this.left);
+
+ ec.EmitNullableHasValue (left);
+ ig.Emit (OpCodes.Brfalse, and ? ret_null : left_is_null);
+
+ ec.EmitNullableGetValueOrDefault (left);
+ ec.EmitCall (and ? GetFalseOperator () : GetTrueOperator ());
+ ig.Emit (OpCodes.Brtrue, ret_left);
+
+ ig.MarkLabel (left_is_null);
+ var right = ec.EmitStored (this.right);
+ ec.EmitNullableHasValue (right);
+ ig.Emit (OpCodes.Brfalse, ret_null);
+
+ ec.EmitNullableGetValueOrDefault (left);
+ ec.EmitNullableGetValueOrDefault (right);
+ ec.EmitCall (method);
+
+ ec.EmitNullableNew (Type);
+ ig.Emit (OpCodes.Br, done);
+
+ ig.MarkLabel (ret_left);
+ ec.EmitLoad (left);
+ ig.Emit (OpCodes.Br, done);
+
+ ig.MarkLabel (ret_null);
+ var ret = ig.DeclareLocal (Type);
+ ec.EmitNullableInitialize (ret);
+
+ ig.MarkLabel (done);
+ }
+
void EmitUserDefinedOperator (EmitContext ec)
{
if (!IsLifted) {
- left.Emit (ec);
- right.Emit (ec);
- ec.EmitCall (method);
- } else if (IsLiftedToNull)
- EmitLiftedToNullUserDefinedOperator (ec);
- else
+ switch (NodeType) {
+ case ExpressionType.AndAlso:
+ case ExpressionType.OrElse:
+ EmitUserDefinedLogicalShortCircuit (ec);
+ break;
+ default:
+ left.Emit (ec);
+ right.Emit (ec);
+ ec.EmitCall (method);
+ break;
+ }
+ } else if (IsLiftedToNull) {
+ switch (NodeType) {
+ case ExpressionType.AndAlso:
+ case ExpressionType.OrElse:
+ EmitUserDefinedLiftedLogicalShortCircuit (ec);
+ break;
+ default:
+ EmitLiftedToNullUserDefinedOperator (ec);
+ break;
+ }
+ } else
EmitLiftedUserDefinedOperator (ec);
}
internal override void Emit (EmitContext ec)
{
- if (method != null){
+ if (method != null) {
EmitUserDefinedOperator (ec);
return;
}
EmitArrayAccess (ec);
return;
case ExpressionType.Coalesce:
- EmitCoalesce (ec);
+ if (conversion != null)
+ EmitConvertedCoalesce (ec);
+ else
+ EmitCoalesce (ec);
return;
case ExpressionType.Power:
case ExpressionType.Add: