Skip to content

First class span's break EFC #109757

Closed as not planned
Closed as not planned

Description

@Suchiman

Description

When enabling LangVersion preview, that enables first class span's which then prefers MemoryExtensions.Contains over Enumerable.Contains which then breaks EFC. It seems that EFC internally calls Expression.Compile with preferInterpretation set to true which then eventually crashes.

Reproduction Steps

public class MyDbContext : DbContext
{
    public DbSet<MyTable> MyTable { get; set; }
}

public class MyTable
{
    public int Id { get; set; }
    public string Name { get; set; }
}

string[] filters = ["Test"];

var dbContext = new MyDbContext();
dbContext.MyTable.Where(x => filters.Contains(x.Name)).ToList();

Expected behavior

First class span's should not negatively affect EFC queries

Actual behavior

TypeLoadException: GenericArguments[1], 'System.Span`1[System.String]', on 'System.Linq.Expressions.Interpreter.FuncCallInstruction`2[T0,TRet]' violates the constraint of type parameter 'TRet'.
   at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception e)
   at System.RuntimeType.MakeGenericType(Type[] instantiation)
   at System.Linq.Expressions.Interpreter.CallInstruction.GetHelperType(MethodInfo info, Type[] arrTypes)
   at System.Linq.Expressions.Interpreter.CallInstruction.SlowCreate(MethodInfo info, ParameterInfo[] pis)
   at System.Linq.Expressions.Interpreter.CallInstruction.Create(MethodInfo info, ParameterInfo[] parameters)
   at System.Linq.Expressions.Interpreter.LightCompiler.CompileMethodCallExpression(Expression object, MethodInfo method, IArgumentProvider arguments)
   at System.Linq.Expressions.Interpreter.LightCompiler.Compile(Expression expr)
   at System.Linq.Expressions.Interpreter.LightCompiler.CompileConvertUnaryExpression(Expression expr)
   at System.Linq.Expressions.Interpreter.LightCompiler.Compile(Expression expr)
   at System.Linq.Expressions.Interpreter.LightCompiler.CompileTop(LambdaExpression node)
   at System.Linq.Expressions.Expression`1.Compile(Boolean preferInterpretation)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.<Evaluate>g__EvaluateCore|70_0(Expression expression, String& parameterName, Boolean& isContextAccessor) in Microsoft.EntityFrameworkCore.Query.Internal\ExpressionTreeFuncletizer.cs:line 1755

Regression?

Yes, only when enabling <LangVersion>preview</LangVersion>

Known Workarounds

set <LangVersion>preview</LangVersion> to anything but preview

Configuration

.NET 9.0.0
EFC 9.0.0

Other information

No response

Activity

  1. dotnet-policy-service commented on Nov 12, 2024

    @dotnet-policy-service
    Contributor

    Tagging subscribers to this area: @cston
    See info in area-owners.md if you want to be subscribed.

  2. jkotas commented on Nov 13, 2024

    @jkotas
    Member
  3. ChrisJollyAU commented on Nov 14, 2024

    @ChrisJollyAU

    @Suchiman Which version of VS are you on? 17.13 Preview 1?

    I've just come across this when building the tests on efcore (same problem with MemoryExtesions.* vs IEnumerable.*) To me it only happened on 17.13 preview 1 AND LangVersion is preview. Using 17.12 even with LangVersion on preview it was fine to build

  4. Suchiman commented on Nov 14, 2024

    @Suchiman
    ContributorAuthor

    @Suchiman Which version of VS are you on? 17.13 Preview 1?

    yes

  5. ilGianfri commented on Nov 16, 2024

    @ilGianfri

    I've attached a simple repro application ConsoleApp2.zip

    On Visual Studio 17.12 it works, in 17.13p1 I get this issue with both .NET 8 and .NET 9 if LangVersion is set to preview

  6. ChrisJollyAU commented on Nov 17, 2024

    @ChrisJollyAU

    Any relation to #96160 ?

  7. jjonescz commented on Dec 9, 2024

    @jjonescz
    Member

    This was discussed at LDM with no change in the C# language planned. LINQ-to-DB should be probably updated to recognize MemoryExtensions.Contains (and perhaps other similar methods) or users will need to update the calls (e.g., calling Enumerable.Contains explicitly, or casting the array to IEnumerable<T>).

  8. GerardSmit commented on Dec 9, 2024

    @GerardSmit
    Contributor

    Does this mean libraries need to fix this issue?

    In that case it would mean .NET 9 (or lower) can never use the new C# LangVersion together with EF Core when First class span's get released?
    You will either need to lower the C# LangVersion or upgrade .NET.

    I know using newer C# LangVersions in older .NET versions isn't official supported, but I do this together with PolySharp a lot.

    When I upgraded my .NET SDK locally, I got hit by this issue; since I had <LangVersion>preview</LangVersion> in my project during the .NET 7 to .NET 8 transition, I forgot I had the preview version still configured 😄.

  9. jjonescz commented on Dec 9, 2024

    @jjonescz
    Member

    In that case it would mean .NET 9 (or lower) can never use the new C# LangVersion together with EF Core when First class span's get released?

    You can use .NET 9, just make sure you call Enumerable methods (e.g., by calling them in their non-extension static forms) instead of MemoryExtensions ones. As you said, older .NETs are not supported with newer LangVersions, so workarounds like that are expected.

  10. jkotas commented on Dec 9, 2024

    @jkotas
    Member

    This problem is not specific to EF Core. You can hit it with plain vanilla System.Linq.Expressions. It can be fixed in System.Linq.Expressions by adding support for byref-like types to the Interpreter, but that is in conflict with the effectively archived status of System.Linq.Expressions.

    @jjonescz This needs a breaking change notice to be filled.

    cc @jaredpar

  11. added
    breaking-changeIssue or PR that represents a breaking API or functional change over a previous release.
    on Dec 9, 2024
  12. dotnet-policy-service commented on Dec 9, 2024

    @dotnet-policy-service
    Contributor

    Added needs-breaking-change-doc-created label because this issue has the breaking-change label.

    1. Create and link to this issue a matching issue in the dotnet/docs repo using the breaking change documentation template, then remove this needs-breaking-change-doc-created label.

    Tagging @dotnet/compat for awareness of the breaking change.

  13. 26 remaining items

  14. ChrisJollyAU commented on Nov 13, 2025

    @ChrisJollyAU

    Thank you for the tip. I don't think it is a proper fix, but a workaround for now.

    Its about the best at the moment. It works because first class spans were introduced in c# 14. So setting it to 13 is before that. The only downside is you can't use any new c# 14 (and future version) features

  15. jjonescz commented on Nov 13, 2025

    @jjonescz
    Member

    If the error is caused by using a ReadOnlySpan during evaluation of the expression (which seems to be the case from the exception trace), a workaround can be defining your own Contains extension method which C# will bind to instead of MemoryExtensions.Contains, for example, (assuming your receiver is an T[]):

    static class Extensions
    {
        public static bool Contains(this T[] array, T item) => Enumerable.Contains(array, item);
    }

    And you can continue using C# 14 with this.

  16. CypherPotato commented on Nov 13, 2025

    @CypherPotato

    If the error is caused by using a ReadOnlySpan during evaluation of the expression (which seems to be the case from the exception trace), a workaround can be defining your own Contains extension method which C# will bind to instead of MemoryExtensions.Contains, for example, (assuming your receiver is an T[]):

    static class Extensions
    {
    public static bool Contains(this T[] array, T item) => Enumerable.Contains(array, item);
    }
    And you can continue using C# 14 with this.

    Tried this, but doens't work on EF. It claims that cannot translate the user-defined Contains method.

  17. jjonescz commented on Nov 13, 2025

    @jjonescz
    Member

    Tried this, but doens't work on EF. It claims that cannot translate the user-defined Contains method.

    But EF Core was updated to be able to handle MemoryExtensions.Contains afaik. You've mentioned that you are using another library, so likely that one is the culprit.

    We would need a minimal reproducible example to investigate further I think.

  18. CypherPotato commented on Nov 13, 2025

    @CypherPotato

    Tried this, but doens't work on EF. It claims that cannot translate the user-defined Contains method.

    But EF Core was updated to be able to handle MemoryExtensions.Contains afaik. You've mentioned that you are using another library, so likely that one is the culprit.

    We would need a minimal reproducible example to investigate further I think.

    There you go.

  19. jjonescz commented on Nov 14, 2025

    @jjonescz
    Member

    Thanks. You are using EFCore v9, that does not seem to have the fix; if you update to v10, there is no crash.

  20. ChrisJollyAU commented on Nov 14, 2025

    @ChrisJollyAU

    @jjonescz Actually it was ported back to v9 and v8 dotnet/efcore#35719 and dotnet/efcore#35720

    I was having a look and whats happened is there is a specific case that gets overlooked.

    Normally efcore only can manage a Contains when there is no EqualityComparer. But for some reason .Contains(bp.State) in your code gets to using the MemoryExtensions.Contains overload that does take an EqualityComparer even though you didnt specify one. The value in this case is null That is why it is jumping over that and doesnt switch it back to the Enumerable.Contains

  21. jjonescz commented on Nov 14, 2025

    @jjonescz
    Member

    ^ @roji

    (still, using EFCore v10 works, so I guess just the backports are incomplete?)

  22. ChrisJollyAU commented on Nov 14, 2025

    @ChrisJollyAU

    @jjonescz @roji

    See dotnet/efcore#35547 and its resulting PR dotnet/efcore#36057

    The changes of that weren't backported

  23. CypherPotato commented on Nov 14, 2025

    @CypherPotato

    Thanks. You are using EFCore v9, that does not seem to have the fix; if you update to v10, there is no crash.

    I'm using Pomelo MySQL, which doens't runs on EFCore v10, so I will just sit down here and wait for Pomelo update their lib to v10.

  24. gurustron commented on Nov 15, 2025

    @gurustron

    I'm using Pomelo MySQL, which doens't runs on EFCore v10, so I will just sit down here and wait for Pomelo update their lib to v10.

    @CypherPotato

    Please see https://stackoverflow.com/a/79820634/2501279

    1. Have you tried downgrading language version as suggested before? I.e.:

      <PropertyGroup>
          <TargetFramework>net10.0</TargetFramework>
          <LangVersion>13</LangVersion>
      </PropertyGroup>
      
    2. Also you can try explicitly using Enumerable.Contains:

      dbContext.MyTable.Where(x => Enumerable.Contains(filters, x.Name)).ToList();
    3. Finally you can try using another type for the variable:

      IReadOnlyCollection<string> filters = ["Test"];
      
      var dbContext = new MyDbContext();
      dbContext.MyTable.Where(x => filters.Contains(x.Name)).ToList();
  25. removed
    untriagedNew issue has not been triaged by the area owner
    on Nov 16, 2025
  26. roji commented on Nov 16, 2025

    @roji
    Member

    @ChrisJollyAU thanks for looking into this, and @CypherPotato thanks for reporting. I've opened dotnet/efcore#37176 to backport the fix to EF 8 and 9, and will try to do this ASAP for the upcoming patch releases. In the meantime, you can either upgrade to EF 10 (which already has the fix) or stay on C# 13 as suggested above.

    As I don't think there's anything actionable remaining with this issue, I'll go ahead and close it. But feel free to continue posting and we can reopen if needed.

  27. locked and limited conversation to collaborators on Dec 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-System.Linq.Expressionsbreaking-changeIssue or PR that represents a breaking API or functional change over a previous release.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions