Runtime: Possible LINQ expression compiler bug?

Created on 21 Nov 2016  路  3Comments  路  Source: dotnet/runtime

Consider the following repro code distilled from a customer-affecting EF issue:

```c#
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace StackSpiller
{
internal class Program
{
public static void Main(string[] args)
{
var guidToStringMethodInfo
= typeof(Guid)
.GetTypeInfo().GetDeclaredMethods("ToString")
.Single(m => !m.GetParameters().Any());

        var customerCtorInfo
            = typeof(Baz)
                .GetTypeInfo().DeclaredConstructors.Single();

        var guidConstant = Expression.Constant(Guid.NewGuid());

        var goodExpressionTree
            = Expression.Lambda<Func<Baz>>(
                Expression.New(
                    customerCtorInfo,
                    Expression.Call(
                        Expression.TryCatch(
                            guidConstant,
                            Expression.Catch(typeof(Exception), guidConstant)),
                        guidToStringMethodInfo),
                    Expression.Constant("Foo")));

        var goodLambda = goodExpressionTree.Compile();

        Console.WriteLine(goodLambda());

        var badExpressionTree
            = Expression.Lambda<Func<Baz>>(
                Expression.New(
                    customerCtorInfo,
                    // ctor arguments are re-ordered
                    Expression.Constant("Foo"),
                    Expression.Call(
                        Expression.TryCatch(
                            guidConstant,
                            Expression.Catch(typeof(Exception), guidConstant)),
                        guidToStringMethodInfo)));

        var badLambda = badExpressionTree.Compile();

        Console.WriteLine(badLambda());
    }

    private class Baz
    {
        public Baz(string a, string b)
        {
        }
    }
}

}

which produces:

StackSpiller.Program+Baz

Unhandled Exception: System.NotSupportedException: TryExpression is not supported as a child expression when accessing a m
ember on type 'System.Guid' because it is a value type. Construct the tree so the TryExpression is not nested inside of th
is expression.
at System.Linq.Expressions.Compiler.StackSpiller.RequireNotRefInstance(Expression instance)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteMethodCallExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression node)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteNewExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.Rewrite[T](Expression1 lambda) at System.Linq.Expressions.Expression1.Accept(StackSpiller spiller)
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda)
at System.Linq.Expressions.Expression1.Compile(Boolean preferInterpretation) at System.Linq.Expressions.Expression1.Compile()
at StackSpiller.Program.Main(String[] args) in C:\Dev\github\StackSpiller\Program.cs:line 52
```
The only difference in the two expressions is the order in which the constructor args are passed when creating the NewExpression.

Is this a bug?

area-System.Linq blocking

Most helpful comment

The underlying limitation has also been lifted now, so future versions of .NET Standard (at this point 2.0 over in corefx) will no longer require you to work around uses of TryExpression in various places.

All 3 comments

It's a limitation being addressed in https://github.com/dotnet/corefx/pull/13126. Glad another real-world case was reported :-).

Closing 馃槃

The underlying limitation has also been lifted now, so future versions of .NET Standard (at this point 2.0 over in corefx) will no longer require you to work around uses of TryExpression in various places.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

chunseoklee picture chunseoklee  路  3Comments

jzabroski picture jzabroski  路  3Comments

omariom picture omariom  路  3Comments

EgorBo picture EgorBo  路  3Comments

Timovzl picture Timovzl  路  3Comments