Skip to content

Commit 0227bdf

Browse files
committed
more things from #558: nullable LeftShift and more doc comments
1 parent 391e548 commit 0227bdf

3 files changed

Lines changed: 76 additions & 12 deletions

File tree

‎src/FastExpressionCompiler.LightExpression/Expression.cs‎

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,17 +1409,12 @@ public static BinaryExpression GetArithmeticBinary(ExpressionType nodeType, Expr
14091409
return GetMethodBasedBinaryOperator(nodeType, left, right, method, liftToNull: true);
14101410
}
14111411

1412-
[RequiresUnreferencedCode(Trimming.Message)]
1413-
public static BinaryExpression GetLeftTypedBinary(ExpressionType nodeType, Expression left, Expression right, MethodInfo method = null) =>
1414-
method == null
1415-
? new LeftTypedBinaryExpression(nodeType, left, right)
1416-
: GetMethodBasedBinaryOperator(nodeType, left, right, method, liftToNull: true);
1417-
14181412
/// <summary>Creates a BinaryExpression that represents an arithmetic addition operation that does not have overflow checking.</summary>
14191413
[RequiresUnreferencedCode(Trimming.Message)]
14201414
public static BinaryExpression Add(Expression left, Expression right) =>
14211415
GetArithmeticBinary(ExpressionType.Add, left, right, null);
14221416

1417+
/// <summary>Creates a BinaryExpression that represents an arithmetic addition operation that does not have overflow checking.</summary>
14231418
[RequiresUnreferencedCode(Trimming.Message)]
14241419
public static BinaryExpression Add(Expression left, Expression right, MethodInfo method) =>
14251420
GetArithmeticBinary(ExpressionType.Add, left, right, method);
@@ -1429,6 +1424,7 @@ public static BinaryExpression Add(Expression left, Expression right, MethodInfo
14291424
public static BinaryExpression AddChecked(Expression left, Expression right) =>
14301425
GetArithmeticBinary(ExpressionType.AddChecked, left, right);
14311426

1427+
/// <summary>Creates a BinaryExpression that represents an arithmetic addition operation that has overflow checking.</summary>
14321428
[RequiresUnreferencedCode(Trimming.Message)]
14331429
public static BinaryExpression AddChecked(Expression left, Expression right, MethodInfo method) =>
14341430
GetArithmeticBinary(ExpressionType.AddChecked, left, right, method);
@@ -1437,15 +1433,34 @@ public static BinaryExpression AddChecked(Expression left, Expression right, Met
14371433
public static BinaryExpression ExclusiveOr(Expression left, Expression right) =>
14381434
new LeftTypedBinaryExpression(ExpressionType.ExclusiveOr, left, right);
14391435

1436+
[RequiresUnreferencedCode(Trimming.Message)]
1437+
public static BinaryExpression GetLeftTypedBinary(ExpressionType nodeType, Expression left, Expression right, MethodInfo method = null) =>
1438+
method == null
1439+
? new LeftTypedBinaryExpression(nodeType, left, right)
1440+
: GetMethodBasedBinaryOperator(nodeType, left, right, method, liftToNull: true);
1441+
1442+
/// <summary>Creates a BinaryExpression that represents a bitwise XOR operation.</summary>
14401443
[RequiresUnreferencedCode(Trimming.Message)]
14411444
public static BinaryExpression ExclusiveOr(Expression left, Expression right, MethodInfo method) => GetLeftTypedBinary(ExpressionType.ExclusiveOr, left, right, method);
14421445

1446+
[RequiresUnreferencedCode(Trimming.Message)]
1447+
private static BinaryExpression GetShiftBinary(ExpressionType nodeType, Expression left, Expression right, MethodInfo method = null)
1448+
{
1449+
var leftType = left.Type;
1450+
return method == null
1451+
? leftType.IsNumeric() && !leftType.IsNullable() && right.Type.IsNullable()
1452+
? new TypedBinaryExpression(nodeType, left, right, leftType.GetNullable())
1453+
: new LeftTypedBinaryExpression(nodeType, left, right)
1454+
: GetMethodBasedBinaryOperator(nodeType, left, right, method, liftToNull: true);
1455+
}
1456+
14431457
/// <summary>Creates a BinaryExpression that represents a bitwise left-shift operation.</summary>
1444-
public static BinaryExpression LeftShift(Expression left, Expression right) =>
1445-
new LeftTypedBinaryExpression(ExpressionType.LeftShift, left, right);
1458+
[RequiresUnreferencedCode(Trimming.Message)]
1459+
public static BinaryExpression LeftShift(Expression left, Expression right) => GetShiftBinary(ExpressionType.LeftShift, left, right);
14461460

1461+
/// <summary>Creates a BinaryExpression that represents a bitwise left-shift operation.</summary>
14471462
[RequiresUnreferencedCode(Trimming.Message)]
1448-
public static BinaryExpression LeftShift(Expression left, Expression right, MethodInfo method) => GetLeftTypedBinary(ExpressionType.LeftShift, left, right, method);
1463+
public static BinaryExpression LeftShift(Expression left, Expression right, MethodInfo method) => GetShiftBinary(ExpressionType.LeftShift, left, right, method);
14491464

14501465
/// <summary>Creates a BinaryExpression that represents an arithmetic remainder operation.</summary>
14511466
[RequiresUnreferencedCode(Trimming.Message)]
@@ -1460,6 +1475,7 @@ public static BinaryExpression Modulo(Expression left, Expression right, MethodI
14601475
public static BinaryExpression RightShift(Expression left, Expression right) =>
14611476
new LeftTypedBinaryExpression(ExpressionType.RightShift, left, right);
14621477

1478+
/// <summary>Creates a BinaryExpression that represents a bitwise right-shift operation.</summary>
14631479
[RequiresUnreferencedCode(Trimming.Message)]
14641480
public static BinaryExpression RightShift(Expression left, Expression right, MethodInfo method) => GetLeftTypedBinary(ExpressionType.RightShift, left, right, method);
14651481

@@ -1468,6 +1484,7 @@ public static BinaryExpression RightShift(Expression left, Expression right) =>
14681484
public static BinaryExpression Subtract(Expression left, Expression right) =>
14691485
GetArithmeticBinary(ExpressionType.Subtract, left, right);
14701486

1487+
/// <summary>Creates a BinaryExpression that represents an arithmetic subtraction operation that does not have overflow checking.</summary>
14711488
[RequiresUnreferencedCode(Trimming.Message)]
14721489
public static BinaryExpression Subtract(Expression left, Expression right, MethodInfo method) =>
14731490
GetArithmeticBinary(ExpressionType.Subtract, left, right, method);
@@ -1477,6 +1494,7 @@ public static BinaryExpression Subtract(Expression left, Expression right, Metho
14771494
public static BinaryExpression SubtractChecked(Expression left, Expression right) =>
14781495
GetArithmeticBinary(ExpressionType.SubtractChecked, left, right);
14791496

1497+
/// <summary>Creates a BinaryExpression that represents an arithmetic subtraction operation that has overflow checking.</summary>
14801498
[RequiresUnreferencedCode(Trimming.Message)]
14811499
public static BinaryExpression SubtractChecked(Expression left, Expression right, MethodInfo method) =>
14821500
GetArithmeticBinary(ExpressionType.SubtractChecked, left, right, method);
@@ -1486,6 +1504,7 @@ public static BinaryExpression SubtractChecked(Expression left, Expression right
14861504
public static BinaryExpression Multiply(Expression left, Expression right) =>
14871505
GetArithmeticBinary(ExpressionType.Multiply, left, right);
14881506

1507+
/// <summary>Creates a BinaryExpression that represents an arithmetic multiplication operation that does not have overflow checking.</summary>
14891508
[RequiresUnreferencedCode(Trimming.Message)]
14901509
public static BinaryExpression Multiply(Expression left, Expression right, MethodInfo method) =>
14911510
GetArithmeticBinary(ExpressionType.Multiply, left, right, method);
@@ -1495,6 +1514,7 @@ public static BinaryExpression Multiply(Expression left, Expression right, Metho
14951514
public static BinaryExpression MultiplyChecked(Expression left, Expression right) =>
14961515
GetArithmeticBinary(ExpressionType.MultiplyChecked, left, right);
14971516

1517+
/// <summary>Creates a BinaryExpression that represents an arithmetic multiplication operation that has overflow checking.</summary>
14981518
[RequiresUnreferencedCode(Trimming.Message)]
14991519
public static BinaryExpression MultiplyChecked(Expression left, Expression right, MethodInfo method) =>
15001520
GetArithmeticBinary(ExpressionType.MultiplyChecked, left, right, method);
@@ -1504,6 +1524,7 @@ public static BinaryExpression MultiplyChecked(Expression left, Expression right
15041524
public static BinaryExpression Divide(Expression left, Expression right) =>
15051525
GetArithmeticBinary(ExpressionType.Divide, left, right);
15061526

1527+
/// <summary>Creates a BinaryExpression that represents an arithmetic division operation.</summary>
15071528
[RequiresUnreferencedCode(Trimming.Message)]
15081529
public static BinaryExpression Divide(Expression left, Expression right, MethodInfo method) =>
15091530
GetArithmeticBinary(ExpressionType.Divide, left, right, method);
@@ -1512,20 +1533,23 @@ public static BinaryExpression Divide(Expression left, Expression right, MethodI
15121533
public static BinaryExpression Power(Expression left, Expression right) =>
15131534
new LeftTypedBinaryExpression(ExpressionType.Power, left, right);
15141535

1536+
/// <summary>Creates a BinaryExpression that represents raising a number to a power.</summary>
15151537
[RequiresUnreferencedCode(Trimming.Message)]
15161538
public static BinaryExpression Power(Expression left, Expression right, MethodInfo method) => GetLeftTypedBinary(ExpressionType.Power, left, right, method);
15171539

15181540
/// <summary>Creates a BinaryExpression that represents a bitwise AND operation.</summary>
15191541
public static BinaryExpression And(Expression left, Expression right) =>
15201542
new LogicalBinaryExpression(ExpressionType.And, left, right);
15211543

1544+
/// <summary>Creates a BinaryExpression that represents a bitwise AND operation.</summary>
15221545
[RequiresUnreferencedCode(Trimming.Message)]
15231546
public static BinaryExpression And(Expression left, Expression right, MethodInfo method) => GetLeftTypedBinary(ExpressionType.And, left, right, method);
15241547

15251548
/// <summary>Creates a BinaryExpression that represents a conditional AND operation that evaluates the second operand only if the first operand evaluates to true.</summary>
15261549
public static BinaryExpression AndAlso(Expression left, Expression right) =>
15271550
new LogicalBinaryExpression(ExpressionType.AndAlso, left, right);
15281551

1552+
/// <summary>Creates a BinaryExpression that represents a conditional AND operation that evaluates the second operand only if the first operand evaluates to true.</summary>
15291553
[RequiresUnreferencedCode(Trimming.Message)]
15301554
public static BinaryExpression AndAlso(Expression left, Expression right, MethodInfo method) => GetLeftTypedBinary(ExpressionType.AndAlso, left, right, method);
15311555

@@ -1534,26 +1558,30 @@ public static BinaryExpression AndAlso(Expression left, Expression right) =>
15341558
public static BinaryExpression Or(Expression left, Expression right) =>
15351559
new LeftTypedBinaryExpression(ExpressionType.Or, left, right);
15361560

1561+
/// <summary>Creates a BinaryExpression that represents a bitwise OR operation.</summary>
15371562
[RequiresUnreferencedCode(Trimming.Message)]
15381563
public static BinaryExpression Or(Expression left, Expression right, MethodInfo method) => GetLeftTypedBinary(ExpressionType.Or, left, right, method);
15391564

1565+
/// <summary>Creates a BinaryExpression that represents a logical binary operation.</summary>
15401566
[RequiresUnreferencedCode(Trimming.Message)]
15411567
public static BinaryExpression GetLogicalBinary(ExpressionType nodeType, Expression left, Expression right, bool liftToNull, MethodInfo method) =>
1542-
!liftToNull && method == null
1568+
!liftToNull & method == null
15431569
? new LogicalBinaryExpression(nodeType, left, right)
15441570
: GetMethodBasedBinaryOperator(nodeType, left, right, method, liftToNull);
15451571

15461572
/// <summary>Creates a BinaryExpression that represents a conditional OR operation that evaluates the second operand only if the first operand evaluates to false.</summary>
15471573
public static BinaryExpression OrElse(Expression left, Expression right) =>
15481574
new LogicalBinaryExpression(ExpressionType.OrElse, left, right);
15491575

1576+
/// <summary>Creates a BinaryExpression that represents a conditional OR operation that evaluates the second operand only if the first operand evaluates to false.</summary>
15501577
[RequiresUnreferencedCode(Trimming.Message)]
15511578
public static BinaryExpression OrElse(Expression left, Expression right, MethodInfo method) => GetLeftTypedBinary(ExpressionType.OrElse, left, right, method);
15521579

15531580
/// <summary>Creates a BinaryExpression that represents an equality comparison.</summary>
15541581
public static BinaryExpression Equal(Expression left, Expression right) =>
15551582
new LogicalBinaryExpression(ExpressionType.Equal, left, right);
15561583

1584+
/// <summary>Creates a BinaryExpression that represents an equality comparison.</summary>
15571585
[RequiresUnreferencedCode(Trimming.Message)]
15581586
public static BinaryExpression Equal(Expression left, Expression right, bool liftToNull, MethodInfo method) =>
15591587
GetLogicalBinary(ExpressionType.Equal, left, right, liftToNull, method);
@@ -1562,6 +1590,7 @@ public static BinaryExpression Equal(Expression left, Expression right, bool lif
15621590
public static BinaryExpression NotEqual(Expression left, Expression right) =>
15631591
new LogicalBinaryExpression(ExpressionType.NotEqual, left, right);
15641592

1593+
/// <summary>Creates a BinaryExpression that represents an inequality comparison.</summary>
15651594
[RequiresUnreferencedCode(Trimming.Message)]
15661595
public static BinaryExpression NotEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) =>
15671596
GetLogicalBinary(ExpressionType.NotEqual, left, right, liftToNull, method);
@@ -1570,6 +1599,7 @@ public static BinaryExpression NotEqual(Expression left, Expression right, bool
15701599
public static BinaryExpression GreaterThan(Expression left, Expression right) =>
15711600
new LogicalBinaryExpression(ExpressionType.GreaterThan, left, right);
15721601

1602+
/// <summary>Creates a BinaryExpression that represents a "greater than" numeric comparison.</summary>
15731603
[RequiresUnreferencedCode(Trimming.Message)]
15741604
public static BinaryExpression GreaterThan(Expression left, Expression right, bool liftToNull, MethodInfo method) =>
15751605
GetLogicalBinary(ExpressionType.GreaterThan, left, right, liftToNull, method);
@@ -1578,6 +1608,7 @@ public static BinaryExpression GreaterThan(Expression left, Expression right, bo
15781608
public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right) =>
15791609
new LogicalBinaryExpression(ExpressionType.GreaterThanOrEqual, left, right);
15801610

1611+
/// <summary>Creates a BinaryExpression that represents a "greater than or equal" numeric comparison.</summary>
15811612
[RequiresUnreferencedCode(Trimming.Message)]
15821613
public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) =>
15831614
GetLogicalBinary(ExpressionType.GreaterThanOrEqual, left, right, liftToNull, method);
@@ -1586,14 +1617,16 @@ public static BinaryExpression GreaterThanOrEqual(Expression left, Expression ri
15861617
public static BinaryExpression LessThan(Expression left, Expression right) =>
15871618
new LogicalBinaryExpression(ExpressionType.LessThan, left, right);
15881619

1620+
/// <summary>Creates a BinaryExpression that represents a "less than" numeric comparison.</summary>
15891621
[RequiresUnreferencedCode(Trimming.Message)]
15901622
public static BinaryExpression LessThan(Expression left, Expression right, bool liftToNull, MethodInfo method) =>
15911623
GetLogicalBinary(ExpressionType.LessThan, left, right, liftToNull, method);
15921624

1593-
/// <summary>Creates a BinaryExpression that represents a " less than or equal" numeric comparison.</summary>
1625+
/// <summary>Creates a BinaryExpression that represents a "less than or equal" numeric comparison.</summary>
15941626
public static BinaryExpression LessThanOrEqual(Expression left, Expression right) =>
15951627
new LogicalBinaryExpression(ExpressionType.LessThanOrEqual, left, right);
15961628

1629+
/// <summary>Creates a BinaryExpression that represents a "less than or equal" numeric comparison.</summary>
15971630
[RequiresUnreferencedCode(Trimming.Message)]
15981631
public static BinaryExpression LessThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) =>
15991632
GetLogicalBinary(ExpressionType.LessThanOrEqual, left, right, liftToNull, method);
@@ -3549,6 +3582,17 @@ internal LeftTypedBinaryExpression(ExpressionType nodeType, Expression left, Exp
35493582
NodeType = nodeType;
35503583
}
35513584

3585+
internal sealed class TypedBinaryExpression : BinaryExpression
3586+
{
3587+
public override ExpressionType NodeType { get; }
3588+
public override Type Type { get; }
3589+
internal TypedBinaryExpression(ExpressionType nodeType, Expression left, Expression right, Type type) : base(left, right)
3590+
{
3591+
NodeType = nodeType;
3592+
Type = type;
3593+
}
3594+
}
3595+
35523596
internal sealed class LiftedToNullBinaryExpression : BinaryExpression
35533597
{
35543598
public override ExpressionType NodeType { get; }

‎src/FastExpressionCompiler/FastExpressionCompiler.cs‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5928,6 +5928,13 @@ private static bool TryEmitArithmetic(Expression left, Expression right, Express
59285928
rightIsNullable = rightType.IsNullable();
59295929
if (rightIsNullable)
59305930
{
5931+
if (!leftIsNullable)
5932+
{
5933+
noNullableValueLabel = il.DefineLabel();
5934+
if (leftValueVar == -1)
5935+
leftValueVar = EmitStoreLocalVariable(il, leftType);
5936+
}
5937+
59315938
if (!TryEmit(right, il, ref context, flags | ParentFlags.InstanceCall))
59325939
return false;
59335940

‎test/FastExpressionCompiler.LightExpression.UnitTests/LightExpressionTests.cs‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,21 @@ public int Run()
6161
Flat_equal_nested_lambdas_with_captures_are_structurally_equal_and_hash_equal();
6262
Flat_standalone_parameters_use_name_in_structural_equality();
6363
Flat_structural_hash_supports_dictionary_lookup();
64+
Can_compile_shifts_with_nullable_shift_count();
6465

65-
return 44;
66+
return 45;
67+
}
68+
69+
public void Can_compile_shifts_with_nullable_shift_count()
70+
{
71+
var shift = Parameter(typeof(int?), "shift");
72+
73+
var leftShift = LeftShift(Constant(16), shift);
74+
Asserts.AreEqual(typeof(int?), leftShift.Type);
75+
var leftShiftFunc = Lambda<Func<int?, int?>>(leftShift, shift).CompileFast(true);
76+
Asserts.IsNotNull(leftShiftFunc);
77+
Asserts.AreEqual(64, leftShiftFunc(2));
78+
Asserts.AreEqual(null, leftShiftFunc(null));
6679
}
6780

6881
public void Can_compile_lambda_without_converting_to_expression()

0 commit comments

Comments
 (0)