Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/FastExpressionCompiler/FastExpressionCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8562,6 +8562,8 @@ internal static bool TryInterpretBool(ref bool resultBool, Expression expr, Expr
// not: negate, arithmetic, convert to bool
if (nodeType == ExpressionType.Not)
{
if (((UnaryExpression)expr).Method != null)
return false;
var operandExpr = ((UnaryExpression)expr).Operand;
if (operandExpr.NodeType == ExpressionType.Conditional)
operandExpr = Tools.TryReduceConditional((ConditionalExpression)operandExpr);
Expand Down Expand Up @@ -9583,7 +9585,7 @@ public static T GetFirst<T>(this IEnumerable<T> source)
public static Expression TryReduceConditionalTest(Expression testExpr)
{
// removing Not by turning Equal -> NotEqual, NotEqual -> Equal
if (testExpr.NodeType == ExpressionType.Not)
if (testExpr.NodeType == ExpressionType.Not && ((UnaryExpression)testExpr).Method == null)
{
// simplify the not `==` -> `!=`, `!=` -> `==`
var op = TryReduceConditionalTest(((UnaryExpression)testExpr).Operand);
Expand Down
2 changes: 2 additions & 0 deletions test/FastExpressionCompiler.TestsRunner.Net472/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ static void RunLightExpressionTests(object state)
t.Run(new LightExpression.IssueTests.Issue499_InvalidProgramException_for_Sorting_and_comparison_function());
t.Run(new LightExpression.UnitTests.ByRefConversionRegressionTests());
t.Run(new LightExpression.UnitTests.RuntimeTypeConstantRegressionTests());
t.Run(new LightExpression.UnitTests.MethodBasedNotRegressionTests());
t.Run(new LightExpression.UnitTests.ExtensionReductionIdentityRegressionTests());
t.Run(new LightExpression.UnitTests.ParityTests());

Expand All @@ -69,6 +70,7 @@ static void RunLightExpressionTests(object state)
fecTests.Run(new ReductionProgressRegressionTests());
fecTests.Run(new ByRefConversionRegressionTests());
fecTests.Run(new RuntimeTypeConstantRegressionTests());
fecTests.Run(new MethodBasedNotRegressionTests());
fecTests.Run(new CustomReducibleNodeRegressionTests());
fecTests.Run(new ExtensionReductionIdentityRegressionTests());
fecTests.Run(new ParityTests());
Expand Down
2 changes: 2 additions & 0 deletions test/FastExpressionCompiler.TestsRunner/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public static void Main(string[] args)
lt.Run(new LightExpression.IssueTests.Issue561_NonBooleanEqualityOperator());
lt.Run(new LightExpression.UnitTests.ByRefConversionRegressionTests());
lt.Run(new LightExpression.UnitTests.RuntimeTypeConstantRegressionTests());
lt.Run(new LightExpression.UnitTests.MethodBasedNotRegressionTests());
lt.Run(new LightExpression.UnitTests.ExtensionReductionIdentityRegressionTests());
lt.Run(new LightExpression.UnitTests.ParityTests());
ltTime = ltStopwatch.ElapsedMilliseconds;
Expand All @@ -88,6 +89,7 @@ public static void Main(string[] args)
st.Run(new ReductionProgressRegressionTests());
st.Run(new ByRefConversionRegressionTests());
st.Run(new RuntimeTypeConstantRegressionTests());
st.Run(new MethodBasedNotRegressionTests());
st.Run(new CustomReducibleNodeRegressionTests());
st.Run(new ExtensionReductionIdentityRegressionTests());
st.Run(new ParityTests());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;
using SysExpr = System.Linq.Expressions.Expression;

#if LIGHT_EXPRESSION
namespace FastExpressionCompiler.LightExpression.UnitTests;
#else
namespace FastExpressionCompiler.UnitTests;
#endif

public struct MethodBasedNotRegressionTests : ITestX
{
public void Run(TestRun t)
{
Explicit_not_method_controls_result(t);
Conditional_preserves_custom_not_semantics(t);
Ignored_result_preserves_custom_not_effects(t);
Nullable_method_receives_null(t);
}

public void Explicit_not_method_controls_result(TestContext t)
{
var parameter = SysExpr.Parameter(typeof(bool));
var method = typeof(MethodBasedNotRegressionTests).GetMethod(nameof(Identity));
foreach (var flags in new[] { CompilerFlags.Default, CompilerFlags.DisableInterpreter })
foreach (var value in new[] { false, true })
{
var constant = SysExpr.Lambda<Func<bool>>(SysExpr.Not(SysExpr.Constant(value), method));
var fastConstant = constant.FromSysExpression().CompileFast(true, flags);
if (!t.IsNotNull(fastConstant)) return;
t.AreEqual(value, fastConstant());
var expression = SysExpr.Lambda<Func<bool, bool>>(SysExpr.Not(parameter, method), parameter);
var fast = expression.FromSysExpression().CompileFast(true, flags);
if (!t.IsNotNull(fast)) return;
t.AreEqual(value, fast(value));
}
}

public void Conditional_preserves_custom_not_semantics(TestContext t)
{
var parameter = SysExpr.Parameter(typeof(bool));
var method = typeof(MethodBasedNotRegressionTests).GetMethod(nameof(Identity));
foreach (var flags in new[] { CompilerFlags.Default, CompilerFlags.DisableInterpreter })
foreach (var value in new[] { false, true })
foreach (var shape in new[] { 0, 1, 2 })
{
System.Linq.Expressions.Expression operand = shape == 0 ? SysExpr.Constant(value)
: shape == 1 ? parameter : SysExpr.Equal(parameter, SysExpr.Constant(true));
var body = SysExpr.Condition(SysExpr.Not(operand, method), SysExpr.Constant(42), SysExpr.Constant(7));
var expression = SysExpr.Lambda<Func<bool, int>>(body, parameter);
var fast = expression.FromSysExpression().CompileFast(true, flags);
if (!t.IsNotNull(fast)) return;
Calls = 0;
t.AreEqual(expression.Compile()(value), fast(value));
t.AreEqual(2, Calls);
}
}

public void Ignored_result_preserves_custom_not_effects(TestContext t)
{
var method = typeof(MethodBasedNotRegressionTests).GetMethod(nameof(Identity));
var expression = SysExpr.Lambda<Func<int>>(SysExpr.Block(
SysExpr.Not(SysExpr.Constant(true), method), SysExpr.Constant(7)));
foreach (var flags in new[] { CompilerFlags.Default, CompilerFlags.DisableInterpreter })
{
var fast = expression.FromSysExpression().CompileFast(true, flags);
if (!t.IsNotNull(fast)) return;
Calls = 0;
t.AreEqual(7, fast());
t.AreEqual(1, Calls);
}
}

public void Nullable_method_receives_null(TestContext t)
{
var parameter = SysExpr.Parameter(typeof(bool?));
var method = typeof(MethodBasedNotRegressionTests).GetMethod(nameof(NullableIdentity));
var expression = SysExpr.Lambda<Func<bool?, bool?>>(SysExpr.Not(parameter, method), parameter);
var fast = expression.FromSysExpression().CompileFast(true);
if (!t.IsNotNull(fast)) return;
foreach (var value in new bool?[] { null, false, true })
t.AreEqual(expression.Compile()(value), fast(value));
}

public static int Calls;
public static bool Identity(bool value) { ++Calls; return value; }
public static bool? NullableIdentity(bool? value) { ++Calls; return value ?? true; }
}
Loading