Skip to content
Draft
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
2 changes: 2 additions & 0 deletions src/FastExpressionCompiler.LightExpression/Expression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1353,6 +1353,8 @@ expression is LambdaExpression lambda
? lambda.ReturnType
: expression is UnaryExpression unExpr && unExpr.NodeType == ExpressionType.Quote && unExpr.Operand is LambdaExpression quotedLambda
? quotedLambda.ReturnType
: expression is ConstantExpression constantExpr && constantExpr.Value is System.Linq.Expressions.LambdaExpression sysLambda
? sysLambda.ReturnType
: expression.Type.FindDelegateInvokeMethod().ReturnType;

[RequiresUnreferencedCode(Trimming.Message)]
Expand Down
24 changes: 22 additions & 2 deletions src/FastExpressionCompiler/FastExpressionCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1343,7 +1343,7 @@ public static Result TryCollectInfo(ref CompilerContext context, Expression expr
var invokeExpr = (InvocationExpression)expr;
var invokeArgs = invokeExpr.GetArgExprs();
var invokeArgCount = invokeArgs.GetArgCount();
var invokedExpr = invokeExpr.Expression;
var invokedExpr = GetInvokedExpression(invokeExpr, ref context);
if ((context.CompilerFlags & CompilerFlags.NoInvocationLambdaInlining) == 0 && invokedExpr is LambdaExpression lambdaExpr)
{
var oldIndex = context.CurrentInlinedLambdaInvokeIndex;
Expand Down Expand Up @@ -1617,6 +1617,26 @@ private static Expression CreateInlinedLambdaInvocationExpression(ArgExprs invok
return inlinedBlock;
}

private static Expression GetInvokedExpression(InvocationExpression invokeExpr, ref CompilerContext context)
{
var invokedExpr = invokeExpr.Expression;
#if LIGHT_EXPRESSION
if (invokedExpr is ConstantExpression constantExpr &&
constantExpr.Value is System.Linq.Expressions.LambdaExpression sysLambda)
{
if ((context.CompilerFlags & CompilerFlags.NoInvocationLambdaInlining) != 0)
{
ref var cachedLambda = ref context.InlinedLambdaInvocation.Map.AddOrGetValueRef(invokeExpr, out var found);
if (!found)
cachedLambda = sysLambda.ToLightExpression();
return cachedLambda;
}
return sysLambda.ToLightExpression();
}
#endif
return invokedExpr;
}

private static bool PropagateNonPassedParamsToOuterLambda(ref CompilerContext context, NestedLambdaInfo lambda,
ParamExprs nestedLambdaParamExprs, ref SmallList<ParameterExpression> nestedNonPassedParams)
{
Expand Down Expand Up @@ -5375,7 +5395,7 @@ private static bool TryEmitInvoke(InvocationExpression expr, ILGenerator il, ref

var argExprs = expr.GetArgExprs();
var argCount = argExprs.GetArgCount();
var invokedExpr = expr.Expression;
var invokedExpr = GetInvokedExpression(expr, ref context);
if ((context.CompilerFlags & CompilerFlags.NoInvocationLambdaInlining) == 0 && invokedExpr is LambdaExpression lambdaExpr)
{
parent |= ParentFlags.InlinedLambdaInvoke;
Expand Down
34 changes: 33 additions & 1 deletion test/FastExpressionCompiler.UnitTests/NestedLambdaTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,17 @@ public int Run()
Given_composed_expr_with_closure_over_2_parameters_used_in_2_levels_of_nested_lambda();
Given_composed_expr_with_closure_over_2_same_parameters_used_in_2_levels_of_nested_lambda();
Two_same_nested_lambdas_should_compile_once();
#if LIGHT_EXPRESSION
Invoke_constant_System_lambda();
#endif

Nested_Hoisted_Func_using_outer_parameter();
Nested_Hoisted_Func_using_outer_parameter_and_closed_value();
Nested_Hoisted_Action_using_outer_parameter_and_closed_value();
Nested_Hoisted_lambda_using_outer_parameter_and_closed_value_deeply_nested_lambda();
Given_hoisted_expr_with_closure_over_parameters_in_nested_lambda_should_work();

return 17;
return 18;
}


Expand Down Expand Up @@ -388,6 +391,35 @@ public void Two_same_nested_lambdas_should_compile_once()
Asserts.AreEqual(50, f());
}

#if LIGHT_EXPRESSION
public void Invoke_constant_System_lambda()
{
System.Linq.Expressions.LambdaExpression lambda =
System.Linq.Expressions.Expression.Lambda<Func<int>>(
System.Linq.Expressions.Expression.Constant(42));
var zeroArgExpr = Lambda<Func<int>>(Invoke(Constant(lambda)));

var zeroArgFunc = zeroArgExpr.CompileFast(true);
Asserts.IsNotNull(zeroArgFunc);
Asserts.AreEqual(42, zeroArgFunc());

var value = System.Linq.Expressions.Expression.Parameter(typeof(int), "value");
lambda = System.Linq.Expressions.Expression.Lambda<Func<int, int>>(
System.Linq.Expressions.Expression.Add(value, System.Linq.Expressions.Expression.Constant(2)),
value);
var arg = Parameter(typeof(int), "arg");
var oneArgExpr = Lambda<Func<int, int>>(Invoke(Constant(lambda), arg), arg);

var oneArgFunc = oneArgExpr.CompileFast(true);
Asserts.IsNotNull(oneArgFunc);
Asserts.AreEqual(42, oneArgFunc(40));

oneArgFunc = oneArgExpr.CompileFast(true, CompilerFlags.NoInvocationLambdaInlining);
Asserts.IsNotNull(oneArgFunc);
Asserts.AreEqual(42, oneArgFunc(40));
}
#endif


public void Hmm_I_can_use_the_same_parameter_for_outer_and_nested_lambda()
{
Expand Down
Loading