Skip to content

When compiling a delegate from a System.Linq.Expressions expression tree, if the tree is too complex, compilation fails when hoisted variables are used #56262

@nike4613

Description

@nike4613

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

//
// 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()

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-System.Linq.Expressionsin-prThere is an active PR which will close this issue when it is merged

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions