@@ -155,7 +155,8 @@ private BsonDocument TranslateNot(UnaryExpression not)
155155 }
156156
157157 private BsonDocument TranslateMethodCall ( MethodCallExpression methodCall )
158- => methodCall switch
158+ {
159+ return methodCall switch
159160 {
160161 // Enumerable.Contains()
161162 { Method . Name : nameof ( Enumerable . Contains ) , Arguments : [ var source , var item ] } contains
@@ -171,11 +172,44 @@ private BsonDocument TranslateMethodCall(MethodCallExpression methodCall)
171172 } ,
172173 Object : Expression source ,
173174 Arguments : [ var item ]
174- } when declaringType . GetGenericTypeDefinition ( ) == typeof ( List < > ) => this . TranslateContains ( source , item ) ,
175+ } when declaringType . GetGenericTypeDefinition ( ) == typeof ( List < > )
176+ => this . TranslateContains ( source , item ) ,
177+
178+ // C# 14 made changes to overload resolution to prefer Span-based overloads when those exist ("first-class spans");
179+ // this makes MemoryExtensions.Contains() be resolved rather than Enumerable.Contains() (see above).
180+ // MemoryExtensions.Contains() also accepts a Span argument for the source, adding an implicit cast we need to remove.
181+ // See https://github.com/dotnet/runtime/issues/109757 for more context.
182+ // Note that MemoryExtensions.Contains has an optional 3rd ComparisonType parameter; we only match when
183+ // it's null.
184+ { Method . Name : nameof ( MemoryExtensions . Contains ) , Arguments : [ var spanArg , var item , ..] } contains
185+ when contains . Method . DeclaringType == typeof ( MemoryExtensions )
186+ && ( contains . Arguments . Count is 2
187+ || ( contains . Arguments . Count is 3 && contains . Arguments [ 2 ] is ConstantExpression { Value : null } ) )
188+ && TryUnwrapSpanImplicitCast ( spanArg , out var source )
189+ => this . TranslateContains ( source , item ) ,
175190
176191 _ => throw new NotSupportedException ( $ "Unsupported method call: { methodCall . Method . DeclaringType ? . Name } .{ methodCall . Method . Name } ")
177192 } ;
178193
194+ static bool TryUnwrapSpanImplicitCast ( Expression expression , [ NotNullWhen ( true ) ] out Expression ? result )
195+ {
196+ if ( expression is MethodCallExpression
197+ {
198+ Method : { Name : "op_Implicit" , DeclaringType : { IsGenericType : true } implicitCastDeclaringType } ,
199+ Arguments : [ var unwrapped ]
200+ }
201+ && implicitCastDeclaringType . GetGenericTypeDefinition ( ) is var genericTypeDefinition
202+ && ( genericTypeDefinition == typeof ( Span < > ) || genericTypeDefinition == typeof ( ReadOnlySpan < > ) ) )
203+ {
204+ result = unwrapped ;
205+ return true ;
206+ }
207+
208+ result = null ;
209+ return false ;
210+ }
211+ }
212+
179213 private BsonDocument TranslateContains ( Expression source , Expression item )
180214 {
181215 switch ( source )
0 commit comments