Skip to content

Commit a39eed7

Browse files
committed
fixed: #309
1 parent be17c10 commit a39eed7

File tree

4 files changed

+71
-41
lines changed

4 files changed

+71
-41
lines changed

src/FastExpressionCompiler/FastExpressionCompiler.cs

Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,7 +1856,7 @@ public static bool TryEmit(Expression expr, IReadOnlyList<PE> paramExprs,
18561856
case ExpressionType.Equal:
18571857
case ExpressionType.NotEqual:
18581858
var binaryExpr = (BinaryExpression)expr;
1859-
return TryEmitComparison(binaryExpr.Left, binaryExpr.Right, binaryExpr.NodeType, paramExprs, il, ref closure, setup, parent);
1859+
return TryEmitComparison(binaryExpr.Left, binaryExpr.Right, binaryExpr.NodeType, expr.Type, paramExprs, il, ref closure, setup, parent);
18601860

18611861
case ExpressionType.Add:
18621862
case ExpressionType.AddChecked:
@@ -2716,7 +2716,7 @@ private static bool TryEmitNot(UnaryExpression expr, IReadOnlyList<PE> paramExpr
27162716
if (expr.Operand.NodeType == ExpressionType.Equal)
27172717
{
27182718
var equalExpr = (BinaryExpression)expr.Operand;
2719-
return TryEmitComparison(equalExpr.Left, equalExpr.Right, ExpressionType.NotEqual, paramExprs, il, ref closure, setup, parent);
2719+
return TryEmitComparison(equalExpr.Left, equalExpr.Right, ExpressionType.NotEqual, equalExpr.Type, paramExprs, il, ref closure, setup, parent);
27202720
}
27212721

27222722
if (!TryEmit(expr.Operand, paramExprs, il, ref closure, setup, parent))
@@ -4374,7 +4374,7 @@ private static bool TryEmitSwitch(SwitchExpression expr, IReadOnlyList<PE> param
43744374

43754375
foreach (var caseTestValue in cs.TestValues)
43764376
{
4377-
if (!TryEmitComparison(expr.SwitchValue, caseTestValue, ExpressionType.Equal, paramExprs, il, ref closure, setup, dontIgnoreTestResult))
4377+
if (!TryEmitComparison(expr.SwitchValue, caseTestValue, ExpressionType.Equal, typeof(bool), paramExprs, il, ref closure, setup, dontIgnoreTestResult))
43784378
return false;
43794379
il.Emit(OpCodes.Brtrue, labels[caseIndex]);
43804380
}
@@ -4402,7 +4402,7 @@ private static bool TryEmitSwitch(SwitchExpression expr, IReadOnlyList<PE> param
44024402
return true;
44034403
}
44044404

4405-
private static bool TryEmitComparison(Expression exprLeft, Expression exprRight, ExpressionType expressionType,
4405+
private static bool TryEmitComparison(Expression exprLeft, Expression exprRight, ExpressionType expressionType, Type exprType,
44064406
#if LIGHT_EXPRESSION
44074407
IParameterProvider paramExprs,
44084408
#else
@@ -4562,10 +4562,19 @@ var methodName
45624562
EmitLoadLocalVariableAddress(il, lVarIndex);
45634563
EmitMethodCall(il, leftNullableHasValueGetterMethod);
45644564

4565+
var isLiftedToNull = exprType == typeof(bool?);
4566+
var leftHasValueVar = -1;
4567+
if (isLiftedToNull)
4568+
EmitStoreAndLoadLocalVariable(il, leftHasValueVar = il.GetNextLocalVarIndex(typeof(bool)));
4569+
45654570
// ReSharper disable once AssignNullToNotNullAttribute
45664571
EmitLoadLocalVariableAddress(il, rVarIndex);
45674572
EmitMethodCall(il, leftNullableHasValueGetterMethod);
45684573

4574+
var rightHasValueVar = -1;
4575+
if (isLiftedToNull)
4576+
EmitStoreAndLoadLocalVariable(il, rightHasValueVar = il.GetNextLocalVarIndex(typeof(bool)));
4577+
45694578
switch (expressionType)
45704579
{
45714580
case ExpressionType.Equal:
@@ -4593,6 +4602,20 @@ var methodName
45934602
default:
45944603
return false;
45954604
}
4605+
4606+
if (isLiftedToNull)
4607+
{
4608+
var resultLabel = il.DefineLabel();
4609+
var isNullLabel = il.DefineLabel();
4610+
EmitLoadLocalVariable(il, leftHasValueVar);
4611+
il.Emit(OpCodes.Brfalse, isNullLabel);
4612+
EmitLoadLocalVariable(il, rightHasValueVar);
4613+
il.Emit(OpCodes.Brtrue, resultLabel);
4614+
il.MarkLabel(isNullLabel);
4615+
il.Emit(OpCodes.Pop);
4616+
il.Emit(OpCodes.Ldnull);
4617+
il.MarkLabel(resultLabel);
4618+
}
45964619
}
45974620

45984621
return il.EmitPopIfIgnoreResult(parent);
@@ -6616,27 +6639,28 @@ void PrintPart(Expression part)
66166639

66176640
if (e is BinaryExpression b)
66186641
{
6619-
if (e.NodeType == ExpressionType.ArrayIndex)
6642+
var nodeType = e.NodeType;
6643+
if (nodeType == ExpressionType.ArrayIndex)
66206644
{
66216645
b.Left.ToCSharpString(sb.Append('('), lineIdent, stripNamespace, printType, identSpaces, tryPrintConstant).Append(')');
66226646
return b.Right.ToCSharpString(sb.Append("["), lineIdent, stripNamespace, printType, identSpaces, tryPrintConstant).Append("]");
66236647
}
66246648

6625-
if (e.NodeType == ExpressionType.Assign ||
6626-
e.NodeType == ExpressionType.PowerAssign ||
6627-
e.NodeType == ExpressionType.AndAssign ||
6628-
e.NodeType == ExpressionType.OrAssign ||
6629-
e.NodeType == ExpressionType.AddAssign ||
6630-
e.NodeType == ExpressionType.ExclusiveOrAssign ||
6631-
e.NodeType == ExpressionType.AddAssignChecked ||
6632-
e.NodeType == ExpressionType.SubtractAssign ||
6633-
e.NodeType == ExpressionType.SubtractAssignChecked ||
6634-
e.NodeType == ExpressionType.MultiplyAssign ||
6635-
e.NodeType == ExpressionType.MultiplyAssignChecked ||
6636-
e.NodeType == ExpressionType.DivideAssign ||
6637-
e.NodeType == ExpressionType.LeftShiftAssign ||
6638-
e.NodeType == ExpressionType.RightShiftAssign ||
6639-
e.NodeType == ExpressionType.ModuloAssign
6649+
if (nodeType == ExpressionType.Assign ||
6650+
nodeType == ExpressionType.PowerAssign ||
6651+
nodeType == ExpressionType.AndAssign ||
6652+
nodeType == ExpressionType.OrAssign ||
6653+
nodeType == ExpressionType.AddAssign ||
6654+
nodeType == ExpressionType.ExclusiveOrAssign ||
6655+
nodeType == ExpressionType.AddAssignChecked ||
6656+
nodeType == ExpressionType.SubtractAssign ||
6657+
nodeType == ExpressionType.SubtractAssignChecked ||
6658+
nodeType == ExpressionType.MultiplyAssign ||
6659+
nodeType == ExpressionType.MultiplyAssignChecked ||
6660+
nodeType == ExpressionType.DivideAssign ||
6661+
nodeType == ExpressionType.LeftShiftAssign ||
6662+
nodeType == ExpressionType.RightShiftAssign ||
6663+
nodeType == ExpressionType.ModuloAssign
66406664
)
66416665
{
66426666
// todo: @perf handle the right part is condition with the blocks for If and/or Else, e.g. see #261 test `Serialize_the_nullable_struct_array`
@@ -6650,39 +6674,37 @@ void PrintPart(Expression part)
66506674
}
66516675

66526676
b.Left.ToCSharpString(sb, lineIdent, stripNamespace, printType, identSpaces, tryPrintConstant);
6653-
if (e.NodeType == ExpressionType.PowerAssign)
6677+
if (nodeType == ExpressionType.PowerAssign)
66546678
{
66556679
sb.Append(" = System.Math.Pow(");
66566680
b.Left.ToCSharpString(sb, lineIdent, stripNamespace, printType, identSpaces, tryPrintConstant).Append(", ");
66576681
return b.Right.ToCSharpString(sb, lineIdent, stripNamespace, printType, identSpaces, tryPrintConstant).Append(")");
66586682
}
66596683

6660-
sb.Append(OperatorToCSharpString(e.NodeType));
6684+
sb.Append(OperatorToCSharpString(nodeType));
66616685

66626686
return b.Right.ToCSharpString(sb, lineIdent, stripNamespace, printType, identSpaces, tryPrintConstant);
66636687
}
66646688

6665-
6666-
b.Left.ToCSharpString(sb, lineIdent, stripNamespace, printType, identSpaces, tryPrintConstant);
6689+
b.Left.ToCSharpString(sb.Append('('), lineIdent, stripNamespace, printType, identSpaces, tryPrintConstant);
66676690

6668-
if (e.NodeType == ExpressionType.Equal)
6691+
if (nodeType == ExpressionType.Equal)
66696692
{
66706693
if (b.Right is ConstantExpression r && r.Value is bool rb && rb)
66716694
return sb;
66726695
sb.Append(" == ");
66736696
}
6674-
else if (e.NodeType == ExpressionType.NotEqual)
6697+
else if (nodeType == ExpressionType.NotEqual)
66756698
{
66766699
if (b.Right is ConstantExpression r && r.Value is bool rb)
66776700
return rb ? sb.Append(" == false") : sb;
66786701
sb.Append(" != ");
66796702
}
66806703
else
6681-
{
6682-
sb.Append(OperatorToCSharpString(e.NodeType));
6683-
}
6704+
sb.Append(OperatorToCSharpString(nodeType));
66846705

6685-
return b.Right.ToCSharpString(sb, lineIdent, stripNamespace, printType, identSpaces, tryPrintConstant);
6706+
return b.Right.ToCSharpString(sb, lineIdent, stripNamespace, printType, identSpaces, tryPrintConstant)
6707+
.Append(')');
66866708
}
66876709

66886710
return sb.Append(e.ToString()); // falling back ToString and hoping for the best
@@ -7047,23 +7069,23 @@ public static string ToCode(this Type type,
70477069
string buildInTypeString = null;
70487070
if (type == typeof(void))
70497071
buildInTypeString = "void";
7050-
if (type == typeof(object))
7072+
else if (type == typeof(object))
70517073
buildInTypeString = "object";
7052-
if (type == typeof(bool))
7074+
else if (type == typeof(bool))
70537075
buildInTypeString = "bool";
7054-
if (type == typeof(int))
7076+
else if (type == typeof(int))
70557077
buildInTypeString = "int";
7056-
if (type == typeof(short))
7078+
else if (type == typeof(short))
70577079
buildInTypeString = "short";
7058-
if (type == typeof(byte))
7080+
else if (type == typeof(byte))
70597081
buildInTypeString = "byte";
7060-
if (type == typeof(double))
7082+
else if (type == typeof(double))
70617083
buildInTypeString = "double";
7062-
if (type == typeof(float))
7084+
else if (type == typeof(float))
70637085
buildInTypeString = "float";
7064-
if (type == typeof(char))
7086+
else if (type == typeof(char))
70657087
buildInTypeString = "char";
7066-
if (type == typeof(string))
7088+
else if (type == typeof(string))
70677089
buildInTypeString = "string";
70687090

70697091
if (buildInTypeString != null)

test/FastExpressionCompiler.IssueTests/Issue309_InvalidProgramException_with_MakeBinary_liftToNull_true.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public int Run()
1818
return 1;
1919
}
2020

21-
// [Test]
21+
[Test]
2222
public void Test1()
2323
{
2424
var expr = Lambda<Func<object>>(

test/FastExpressionCompiler.TestsRunner.Net472/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ void Run(Func<int> run, string name = null)
201201
Run(new Issue308_Wrong_delegate_type_returned_with_closure().Run);
202202
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue308_Wrong_delegate_type_returned_with_closure().Run);
203203

204+
Run(new Issue309_InvalidProgramException_with_MakeBinary_liftToNull_true().Run);
205+
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue309_InvalidProgramException_with_MakeBinary_liftToNull_true().Run);
206+
204207
Console.WriteLine($"============={Environment.NewLine}IssueTests are passing in {sw.ElapsedMilliseconds} ms.");
205208
});
206209

test/FastExpressionCompiler.TestsRunner/Program.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ public class Program
99
{
1010
public static void Main()
1111
{
12-
RunAllTests();
12+
// RunAllTests();
1313

14+
// new Issue309_InvalidProgramException_with_MakeBinary_liftToNull_true().Run();
15+
new FastExpressionCompiler.LightExpression.IssueTests.Issue309_InvalidProgramException_with_MakeBinary_liftToNull_true().Run();
1416
// new FastExpressionCompiler.LightExpression.IssueTests.Issue308_Wrong_delegate_type_returned_with_closure().Run();
1517

1618
// new FastExpressionCompiler.LightExpression.IssueTests.Issue307_Switch_with_fall_through_throws_InvalidProgramException().Run();
@@ -226,6 +228,9 @@ void Run(Func<int> run, string name = null)
226228
Run(new Issue308_Wrong_delegate_type_returned_with_closure().Run);
227229
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue308_Wrong_delegate_type_returned_with_closure().Run);
228230

231+
Run(new Issue309_InvalidProgramException_with_MakeBinary_liftToNull_true().Run);
232+
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue309_InvalidProgramException_with_MakeBinary_liftToNull_true().Run);
233+
229234
Console.WriteLine($"============={Environment.NewLine}IssueTests are passing in {sw.ElapsedMilliseconds} ms.");
230235
});
231236

0 commit comments

Comments
 (0)