-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Description
When compiling a delegate from a System.Linq.Expressions expression tree, if the tree is too complex (and has hoisted variables), compilation fails at
runtime/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/CompilerScope.cs
Lines 273 to 279 in 24fa00d
| // | |
| // If this is an unbound variable in the lambda, the error will be | |
| // thrown from VariableBinder. So an error here is generally caused | |
| // by an internal error, e.g. a scope was created but it bypassed | |
| // VariableBinder. | |
| // | |
| throw Error.UndefinedVariable(variable.Name, variable.Type, CurrentLambdaName); |
If the comment is to be believed, it should never fail here.
I unfortunately cannot pinpoint what attribute specifically causes it, however I can give a few examples of the DebugView property of expression trees which do and do not work. These examples are, unfortunately, very long and repetitive even when it does work.
This, for example, fails with System.InvalidOperationException: 'variable 'context' of type 'Sentimentality.RPC.IRpcCallContext' referenced from scope 'Dispatch for DoThing', but it is not defined'.
This, however, compiles successfully and runs as expected.
Both of these expressions are built with the same generator code, only with a subtly different input type. The former has one more method being processed than the latter, and it does not seem to make a difference what the method is, only whether it is present. This is what leads me to believe that there is some "complexity" which the former exceeds while the latter does not which causes the issue to happen.
Until this is fixed, are there any simple workarounds that don't boil down to manually hoising variables?
Configuration
.NET 5.0.7 on Windows 10 x64, though I suspect that it is architecture independent.
Other information
A full stack trace for the failing example above:
at System.Linq.Expressions.Compiler.CompilerScope.ResolveVariable(ParameterExpression variable, HoistedLocals hoistedLocals)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitParameterExpression(Expression expr)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitInstance(Expression instance, Type& type)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitMethodCall(Expression obj, MethodInfo method, IArgumentProvider methodCallExpr, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitMethodCallExpression(Expression expr, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpressionAsVoid(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.Emit(BlockExpression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpressionAsVoid(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.Emit(BlockExpression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitBlockExpression(Expression expr, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitTryExpression(Expression expr)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpressionAsVoid(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.Emit(BlockExpression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpressionAsVoid(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitLambdaBody(CompilerScope parent, Boolean inlined, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitDelegateConstruction(LambdaExpression lambda)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitArguments(MethodBase method, IArgumentProvider args, Int32 skipParameters)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitMethodCall(MethodInfo mi, IArgumentProvider args, Type objectType, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitMethodCall(Expression obj, MethodInfo method, IArgumentProvider methodCallExpr, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitMethodCallExpression(Expression expr, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpressionAsVoid(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.Emit(BlockExpression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitBlockExpression(Expression expr, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitTryExpression(Expression expr)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpressionAsVoid(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.Emit(BlockExpression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpressionAsVoid(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpressionAsType(Expression node, Type type, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitConditionalExpression(Expression expr, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpressionAsVoid(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.Emit(BlockExpression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpressionAsVoid(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpressionAsType(Expression node, Type type, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitConditionalExpression(Expression expr, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpressionAsVoid(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.Emit(BlockExpression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitBlockExpression(Expression expr, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpressionAsType(Expression node, Type type, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitSwitchCases(SwitchExpression node, Label[] labels, Boolean[] isGoto, Label default, Label end, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.TryEmitSwitchInstruction(SwitchExpression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitSwitchExpression(Expression expr, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpressionAsType(Expression node, Type type, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.Emit(BlockExpression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitBlockExpression(Expression expr, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.TryEmitHashtableSwitch(SwitchExpression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitSwitchExpression(Expression expr, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitLambdaBody(CompilerScope parent, Boolean inlined, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitLambdaBody()
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda)
at System.Linq.Expressions.Expression`1.Compile()