@@ -112,6 +112,9 @@ public class ExpressionTreeFuncletizer : ExpressionVisitor
112112 private static readonly bool UseOldBehavior35656 =
113113 AppContext . TryGetSwitch ( "Microsoft.EntityFrameworkCore.Issue35656" , out var enabled35656 ) && enabled35656 ;
114114
115+ private static readonly bool UseOldBehavior35100 =
116+ AppContext . TryGetSwitch ( "Microsoft.EntityFrameworkCore.Issue35100" , out var enabled35100 ) && enabled35100 ;
117+
115118 private static readonly MethodInfo ReadOnlyCollectionIndexerGetter = typeof ( ReadOnlyCollection < Expression > ) . GetProperties ( )
116119 . Single ( p => p . GetIndexParameters ( ) is { Length : 1 } indexParameters && indexParameters [ 0 ] . ParameterType == typeof ( int ) ) . GetMethod ! ;
117120
@@ -974,6 +977,51 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCall)
974977 }
975978 }
976979
980+ // .NET 10 made changes to overload resolution to prefer Span-based overloads when those exist ("first-class spans").
981+ // Unfortunately, the LINQ interpreter does not support ref structs, so we rewrite e.g. MemoryExtensions.Contains to
982+ // Enumerable.Contains here. See https://github.com/dotnet/runtime/issues/109757.
983+ if ( method . DeclaringType == typeof ( MemoryExtensions ) && ! UseOldBehavior35100 )
984+ {
985+ switch ( method . Name )
986+ {
987+ case nameof ( MemoryExtensions . Contains )
988+ when methodCall . Arguments is [ var arg0 , var arg1 ] && TryUnwrapSpanImplicitCast ( arg0 , out var unwrappedArg0 ) :
989+ {
990+ return Visit (
991+ Call (
992+ EnumerableMethods . Contains . MakeGenericMethod ( methodCall . Method . GetGenericArguments ( ) [ 0 ] ) ,
993+ unwrappedArg0 , arg1 ) ) ;
994+ }
995+
996+ case nameof ( MemoryExtensions . SequenceEqual )
997+ when methodCall . Arguments is [ var arg0 , var arg1 ]
998+ && TryUnwrapSpanImplicitCast ( arg0 , out var unwrappedArg0 )
999+ && TryUnwrapSpanImplicitCast ( arg1 , out var unwrappedArg1 ) :
1000+ return Visit (
1001+ Call (
1002+ EnumerableMethods . SequenceEqual . MakeGenericMethod ( methodCall . Method . GetGenericArguments ( ) [ 0 ] ) ,
1003+ unwrappedArg0 , unwrappedArg1 ) ) ;
1004+ }
1005+
1006+ static bool TryUnwrapSpanImplicitCast ( Expression expression , [ NotNullWhen ( true ) ] out Expression ? result )
1007+ {
1008+ if ( expression is MethodCallExpression
1009+ {
1010+ Method : { Name : "op_Implicit" , DeclaringType : { IsGenericType : true } implicitCastDeclaringType } ,
1011+ Arguments : [ var unwrapped ]
1012+ }
1013+ && implicitCastDeclaringType . GetGenericTypeDefinition ( ) is var genericTypeDefinition
1014+ && ( genericTypeDefinition == typeof ( Span < > ) || genericTypeDefinition == typeof ( ReadOnlySpan < > ) ) )
1015+ {
1016+ result = unwrapped ;
1017+ return true ;
1018+ }
1019+
1020+ result = null ;
1021+ return false ;
1022+ }
1023+ }
1024+
9771025 // Regular/arbitrary method handling from here on
9781026
9791027 // First, visit the object and all arguments, saving states as well
0 commit comments