@@ -109,6 +109,9 @@ public class ExpressionTreeFuncletizer : ExpressionVisitor
109109private static readonly bool UseOldBehavior35111 =
110110AppContext . TryGetSwitch ( "Microsoft.EntityFrameworkCore.Issue35111" , out var enabled35111 ) && enabled35111 ;
111111
112+ private static readonly bool UseOldBehavior35339 =
113+ AppContext . TryGetSwitch ( "Microsoft.EntityFrameworkCore.Issue35339" , out var enabled35339 ) && enabled35339 ;
114+
112115private static readonly MethodInfo ReadOnlyCollectionIndexerGetter = typeof ( ReadOnlyCollection < Expression > ) . GetProperties ( )
113116. Single ( p=> p . GetIndexParameters ( ) is { Length : 1 } indexParameters && indexParameters [ 0 ] . ParameterType == typeof ( int ) ) . GetMethod ! ;
114117
@@ -971,6 +974,51 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCall)
971974}
972975}
973976
977+ // .NET 10 made changes to overload resolution to prefer Span-based overloads when those exist ("first-class spans").
978+ // Unfortunately, the LINQ interpreter does not support ref structs, so we rewrite e.g. MemoryExtensions.Contains to
979+ // Enumerable.Contains here. See https://github.com/dotnet/runtime/issues/109757.
980+ if ( method . DeclaringType == typeof ( MemoryExtensions ) && ! UseOldBehavior35339 )
981+ {
982+ switch ( method . Name )
983+ {
984+ case nameof ( MemoryExtensions . Contains )
985+ when methodCall . Arguments is [ var arg0 , var arg1 ] && TryUnwrapSpanImplicitCast ( arg0 , out var unwrappedArg0 ) :
986+ {
987+ return Visit (
988+ Call (
989+ EnumerableMethods . Contains . MakeGenericMethod ( methodCall . Method . GetGenericArguments ( ) [ 0 ] ) ,
990+ unwrappedArg0 , arg1 ) ) ;
991+ }
992+
993+ case nameof ( MemoryExtensions . SequenceEqual )
994+ when methodCall . Arguments is [ var arg0 , var arg1 ]
995+ && TryUnwrapSpanImplicitCast ( arg0 , out var unwrappedArg0 )
996+ && TryUnwrapSpanImplicitCast ( arg1 , out var unwrappedArg1 ) :
997+ return Visit (
998+ Call (
999+ EnumerableMethods . SequenceEqual . MakeGenericMethod ( methodCall . Method . GetGenericArguments ( ) [ 0 ] ) ,
1000+ unwrappedArg0 , unwrappedArg1 ) ) ;
1001+ }
1002+
1003+ static bool TryUnwrapSpanImplicitCast ( Expression expression , [ NotNullWhen ( true ) ] out Expression ? result )
1004+ {
1005+ if ( expression is MethodCallExpression
1006+ {
1007+ Method : { Name : "op_Implicit" , DeclaringType : { IsGenericType : true } implicitCastDeclaringType } ,
1008+ Arguments : [ var unwrapped ]
1009+ }
1010+ && implicitCastDeclaringType . GetGenericTypeDefinition ( ) is var genericTypeDefinition
1011+ && ( genericTypeDefinition == typeof ( Span < > ) || genericTypeDefinition == typeof ( ReadOnlySpan < > ) ) )
1012+ {
1013+ result = unwrapped ;
1014+ return true ;
1015+ }
1016+
1017+ result = null ;
1018+ return false ;
1019+ }
1020+ }
1021+
9741022// Regular/arbitrary method handling from here on
9751023
9761024// First, visit the object and all arguments, saving states as well