Skip to content

Commit 6c0106b

Browse files
rojiAndriySvyryd
authored andcommitted
Transform Span-based overloads to Enumerable in funcletizer
Fixes dotnet#35100
1 parent 0597edf commit 6c0106b

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

Diff for: src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs

+45
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,51 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCall)
967967
}
968968
}
969969

970+
// .NET 10 made changes to overload resolution to prefer Span-based overloads when those exist ("first-class spans").
971+
// Unfortunately, the LINQ interpreter does not support ref structs, so we rewrite e.g. MemoryExtensions.Contains to
972+
// Enumerable.Contains here. See https://github.com/dotnet/runtime/issues/109757.
973+
if (method.DeclaringType == typeof(MemoryExtensions))
974+
{
975+
switch (method.Name)
976+
{
977+
case nameof(MemoryExtensions.Contains)
978+
when methodCall.Arguments is [var arg0, var arg1] && TryUnwrapSpanImplicitCast(arg0, out var unwrappedArg0):
979+
{
980+
return Visit(
981+
Call(
982+
EnumerableMethods.Contains.MakeGenericMethod(methodCall.Method.GetGenericArguments()[0]),
983+
unwrappedArg0, arg1));
984+
}
985+
986+
case nameof(MemoryExtensions.SequenceEqual)
987+
when methodCall.Arguments is [var arg0, var arg1]
988+
&& TryUnwrapSpanImplicitCast(arg0, out var unwrappedArg0)
989+
&& TryUnwrapSpanImplicitCast(arg1, out var unwrappedArg1):
990+
return Visit(
991+
Call(
992+
EnumerableMethods.SequenceEqual.MakeGenericMethod(methodCall.Method.GetGenericArguments()[0]),
993+
unwrappedArg0, unwrappedArg1));
994+
}
995+
996+
static bool TryUnwrapSpanImplicitCast(Expression expression, [NotNullWhen(true)] out Expression? result)
997+
{
998+
if (expression is MethodCallExpression
999+
{
1000+
Method: { Name: "op_Implicit", DeclaringType: { IsGenericType: true } implicitCastDeclaringType },
1001+
Arguments: [var unwrapped]
1002+
}
1003+
&& implicitCastDeclaringType.GetGenericTypeDefinition() is var genericTypeDefinition
1004+
&& (genericTypeDefinition == typeof(Span<>) || genericTypeDefinition == typeof(ReadOnlySpan<>)))
1005+
{
1006+
result = unwrapped;
1007+
return true;
1008+
}
1009+
1010+
result = null;
1011+
return false;
1012+
}
1013+
}
1014+
9701015
// Regular/arbitrary method handling from here on
9711016

9721017
// First, visit the object and all arguments, saving states as well

0 commit comments

Comments
 (0)