Skip to content

Exception System.IndexOutOfRangeException with value objects implicit conversions starting from v5.0.3 #536

@kseitz10

Description

@kseitz10

I am experiencing exceptions when using value objects with implicit conversions within LINQ Where lambdas that are executed by the Marten document store.

I discovered this issue in this repository that fixes an exception around implicit/explicit conversion operators that was released in version 5.0.3. That particular version introduces a new exception in the code when implicit conversion operators are used (apparently) within a closure.

The example may be able to be distilled down a bit more, but this closely matches our production code while being. This test reproduces the issue on 5.0.3 and latest, but not 5.0.2 or latest 4.x.

public abstract class PrimitiveValueObject<TInput, TOutput>
{
    public TInput Value { get; protected set; } = default!;

    public static implicit operator
        TInput(PrimitiveValueObject<TInput, TOutput>? primitiveValueObject) => primitiveValueObject == null
        ? default!
        : primitiveValueObject.Value;
}

public class MyPrimitive : PrimitiveValueObject<string, MyPrimitive>
{
    public MyPrimitive(string val) => Value = val;
}

[Fact]
public void Test()
{
    var captured = new MyPrimitive("Hello world");

    // Expression with implicit conversion on closure-captured variable
    Expression<Func<string>> expr = () => captured;

    // Wrap in Convert to object (common pattern in LINQ providers)
    var toObject = Expression.Convert(expr.Body, typeof(object));
    var lambda = Expression.Lambda<Func<object>>(toObject);

    _testOutputHelper.WriteLine($"Expression: {lambda}");

    // Standard Compile works
    var standard = lambda.Compile();
    _testOutputHelper.WriteLine($"Compile(): '{standard()}'");

    // CompileFast throws
    var fast = lambda.CompileFast();
    _testOutputHelper.WriteLine($"CompileFast(): '{fast()}'");
}

System.IndexOutOfRangeException
Index was outside the bounds of the array.
at FastExpressionCompiler.ExpressionCompiler.EmittingVisitor.TryEmitConvert(UnaryExpression expr, IReadOnlyList1 paramExprs, ILGenerator il, ClosureInfo& closure, CompilerFlags setup, ParentFlags parent) at FastExpressionCompiler.ExpressionCompiler.EmittingVisitor.TryEmit(Expression expr, IReadOnlyList1 paramExprs, ILGenerator il, ClosureInfo& closure, CompilerFlags setup, ParentFlags parent, Int32 byRefIndex)
at FastExpressionCompiler.ExpressionCompiler.EmittingVisitor.TryEmitConvert(UnaryExpression expr, IReadOnlyList1 paramExprs, ILGenerator il, ClosureInfo& closure, CompilerFlags setup, ParentFlags parent) at FastExpressionCompiler.ExpressionCompiler.EmittingVisitor.TryEmit(Expression expr, IReadOnlyList1 paramExprs, ILGenerator il, ClosureInfo& closure, CompilerFlags setup, ParentFlags parent, Int32 byRefIndex)
at FastExpressionCompiler.ExpressionCompiler.TryCompileBoundToFirstClosureParam(Type delegateType, Expression bodyExpr, IReadOnlyList1 paramExprs, Type returnType, CompilerFlags flags) at FastExpressionCompiler.ExpressionCompiler.CompileFast[R](Expression1 lambdaExpr, Boolean ifFastFailedReturnNull, CompilerFlags flags)
at TestProject1.UnitTest1.Test() in /Users/kevin/source/server/src/TestProject1/UnitTest1.cs:line 41
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

I will note that if I don't have the abstract class be abstract, I get InvalidProgramException instead. Not sure what makes that invalid.

I'm not familiar with this project or a lot of the nuance of expressions, but if I can be of help, let me know. Thank you for your help!

Metadata

Metadata

Assignees

Labels

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions