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
5 changes: 3 additions & 2 deletions src/FastExpressionCompiler/FastExpressionCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3242,7 +3242,8 @@ public static bool TryEmitParameter(ParameterExpression paramExpr, ILGenerator i
var paramExprCount = paramExprs.GetParamCount();
var paramType = paramExpr.Type;
var isValueType = paramType.IsValueType;
var isParamOrVarByRef = paramExpr.IsByRef && !paramType.IsNullable(); // for the nullable part check the #461 cases with nullable
var isParamOrVarByRef = paramExpr.IsByRef &&
(!paramType.IsNullable() || (parent & (ParentFlags.Arithmetic | ParentFlags.AssignmentRightValue)) != 0); // #461 member access uses the nullable address; value operations dereference it
var isPassedRef = byRefIndex != -1;

// Parameter may represent a variable, so first look if this is the case,
Expand Down Expand Up @@ -3717,7 +3718,7 @@ private static bool TryEmitConvert(UnaryExpression expr, ILGenerator il, ref Com
return TryEmit(opExpr, il, ref context, parent & ~ParentFlags.InstanceAccess);

// Emit the operand before going to the fast checks below
if (!TryEmit(opExpr, il, ref context, parent & ~ParentFlags.IgnoreResult & ~ParentFlags.InstanceAccess))
if (!TryEmit(opExpr, il, ref context, (parent & ~ParentFlags.IgnoreResult & ~ParentFlags.InstanceAccess) | ParentFlags.AssignmentRightValue))
return false;

if (sourceType == targetType)
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 @@ -43,6 +43,7 @@ static void RunLightExpressionTests(object state)
t.Run(new LightExpression.IssueTests.Issue476_System_ExecutionEngineException_with_nullables_on_repeated_calls_to_ConcurrentDictionary());
t.Run(new LightExpression.IssueTests.Issue498_InvalidProgramException_when_using_loop());
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.ParityTests());

Expand All @@ -65,6 +66,7 @@ static void RunLightExpressionTests(object state)
fecTests.Run(new Issue498_InvalidProgramException_when_using_loop());
fecTests.Run(new Issue499_InvalidProgramException_for_Sorting_and_comparison_function());
fecTests.Run(new ReductionProgressRegressionTests());
fecTests.Run(new ByRefConversionRegressionTests());
fecTests.Run(new RuntimeTypeConstantRegressionTests());
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 @@ -75,6 +75,7 @@ public static void Main(string[] args)
lt.Run(new LightExpression.IssueTests.Issue476_System_ExecutionEngineException_with_nullables_on_repeated_calls_to_ConcurrentDictionary());
lt.Run(new LightExpression.IssueTests.Issue499_InvalidProgramException_for_Sorting_and_comparison_function());
lt.Run(new LightExpression.IssueTests.Issue561_NonBooleanEqualityOperator());
lt.Run(new LightExpression.UnitTests.ByRefConversionRegressionTests());
lt.Run(new LightExpression.UnitTests.RuntimeTypeConstantRegressionTests());
lt.Run(new LightExpression.UnitTests.ParityTests());
ltTime = ltStopwatch.ElapsedMilliseconds;
Expand All @@ -84,6 +85,7 @@ public static void Main(string[] args)
st.Run(new Issue499_InvalidProgramException_for_Sorting_and_comparison_function());
st.Run(new Issue561_NonBooleanEqualityOperator());
st.Run(new ReductionProgressRegressionTests());
st.Run(new ByRefConversionRegressionTests());
st.Run(new RuntimeTypeConstantRegressionTests());
st.Run(new ParityTests());
st.Run(new Issue498_InvalidProgramException_when_using_loop());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using System.Reflection;
using SysExpr = System.Linq.Expressions.Expression;

#if LIGHT_EXPRESSION
using Expr = FastExpressionCompiler.LightExpression.Expression;
namespace FastExpressionCompiler.LightExpression.UnitTests;
#else
using Expr = System.Linq.Expressions.Expression;
namespace FastExpressionCompiler.UnitTests;
#endif

public struct ByRefConversionRegressionTests : ITestX
{
public void Run(TestRun t)
{
By_ref_values_box_inside_array_initializers(t);
By_ref_nullable_values_box_inside_array_initializers(t);
}

public void By_ref_values_box_inside_array_initializers(TestContext t) => Check(t, false);
public void By_ref_nullable_values_box_inside_array_initializers(TestContext t) => Check(t, true);

private static void Check(TestContext t, bool nullable)
{
Type[] types = { typeof(short), typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal), typeof(Tagged) };
object[] values = { (short)42, 42, 42L, 42f, 42d, 42m, new Tagged { Text = "value" } };
for (var i = 0; i < types.Length; ++i)
{
var type = nullable ? typeof(Nullable<>).MakeGenericType(types[i]) : types[i];
var delegateType = typeof(Read<>).MakeGenericType(type);
var parameter = SysExpr.Parameter(type.MakeByRefType());
var system = SysExpr.Lambda(delegateType, SysExpr.NewArrayInit(typeof(object),
SysExpr.Convert(parameter, typeof(object)), SysExpr.Convert(parameter, typeof(object))), parameter).Compile();
var fastParameter = Expr.Parameter(type.MakeByRefType());
var fast = Expr.Lambda(delegateType, Expr.NewArrayInit(typeof(object),
Expr.Convert(fastParameter, typeof(object)), Expr.Convert(fastParameter, typeof(object))), fastParameter).CompileFast(true);
if (!t.IsNotNull(fast)) return;
Compare(t, system, fast, values[i]);
if (nullable) Compare(t, system, fast, null);
}
}

private static void Compare(TestContext t, Delegate system, Delegate fast, object value)
{
var expected = (object[])system.DynamicInvoke(new[] { value });
var actual = (object[])fast.DynamicInvoke(new[] { value });
t.AreEqual(expected[0], actual[0]);
t.AreEqual(expected[1], actual[1]);
}

public delegate object[] Read<T>(ref T value);
public struct Tagged { public string Text; }
}
Loading