Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "9.0.110",
"version": "10.0.100",
"allowPrerelease": true,
"rollForward": "latestMajor"
},
Expand Down
58 changes: 48 additions & 10 deletions src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ public class ExpressionTreeFuncletizer : ExpressionVisitor
private static readonly bool UseOldBehavior35100 =
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue35100", out var enabled35100) && enabled35100;

private static readonly bool UseOldBehavior37176 =
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue37176", out var enabled37176) && enabled37176;

private static readonly MethodInfo ReadOnlyCollectionIndexerGetter = typeof(ReadOnlyCollection<Expression>).GetProperties()
.Single(p => p.GetIndexParameters() is { Length: 1 } indexParameters && indexParameters[0].ParameterType == typeof(int)).GetMethod!;

Expand Down Expand Up @@ -985,14 +988,32 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCall)
switch (method.Name)
{
case nameof(MemoryExtensions.Contains)
when methodCall.Arguments is [var arg0, var arg1] && TryUnwrapSpanImplicitCast(arg0, out var unwrappedArg0):
when UseOldBehavior37176
&& methodCall.Arguments is [var arg0, var arg1]
&& TryUnwrapSpanImplicitCast(arg0, out var unwrappedArg0):
{
return Visit(
Call(
EnumerableMethods.Contains.MakeGenericMethod(methodCall.Method.GetGenericArguments()[0]),
unwrappedArg0, arg1));
}

// In .NET 10, MemoryExtensions.Contains has an overload that accepts a third, optional comparer, in addition to the older
// overload that accepts two parameters only.
case nameof(MemoryExtensions.Contains)
when !UseOldBehavior37176
&& methodCall.Arguments is [var spanArg, var valueArg, ..]
&& (methodCall.Arguments.Count is 2
|| methodCall.Arguments.Count is 3
&& methodCall.Arguments[2] is ConstantExpression { Value: null })
&& TryUnwrapSpanImplicitCast(spanArg, out var unwrappedSpanArg):
{
return Visit(
Call(
EnumerableMethods.Contains.MakeGenericMethod(method.GetGenericArguments()[0]),
unwrappedSpanArg, valueArg));
}

case nameof(MemoryExtensions.SequenceEqual)
when methodCall.Arguments is [var arg0, var arg1]
&& TryUnwrapSpanImplicitCast(arg0, out var unwrappedArg0)
Expand All @@ -1005,20 +1026,37 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCall)

static bool TryUnwrapSpanImplicitCast(Expression expression, [NotNullWhen(true)] out Expression? result)
{
if (expression is MethodCallExpression
switch (expression)
{
// With newer versions of the SDK, the implicit cast is represented as a MethodCallExpression;
// with older versions, it's a Convert node.
case MethodCallExpression
{
Method: { Name: "op_Implicit", DeclaringType: { IsGenericType: true } implicitCastDeclaringType },
Arguments: [var unwrapped]
} when implicitCastDeclaringType.GetGenericTypeDefinition() is var genericTypeDefinition
&& (genericTypeDefinition == typeof(Span<>) || genericTypeDefinition == typeof(ReadOnlySpan<>)):
{
result = unwrapped;
return true;
}
&& implicitCastDeclaringType.GetGenericTypeDefinition() is var genericTypeDefinition
&& (genericTypeDefinition == typeof(Span<>) || genericTypeDefinition == typeof(ReadOnlySpan<>)))
{
result = unwrapped;
return true;
}

result = null;
return false;
case UnaryExpression
{
NodeType: ExpressionType.Convert,
Operand: var unwrapped,
Type: { IsGenericType: true } convertType
} when !UseOldBehavior37176 && convertType.GetGenericTypeDefinition() is var genericTypeDefinition
&& (genericTypeDefinition == typeof(Span<>) || genericTypeDefinition == typeof(ReadOnlySpan<>)):
{
result = unwrapped;
return true;
}

default:
result = null;
return false;
}
}
}

Expand Down
24 changes: 12 additions & 12 deletions src/Shared/EnumerableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,18 +125,18 @@ public static bool Any(this IEnumerable source)
return false;
}

public static async Task<List<TSource>> ToListAsync<TSource>(
this IAsyncEnumerable<TSource> source,
CancellationToken cancellationToken = default)
{
var list = new List<TSource>();
await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
{
list.Add(element);
}

return list;
}
// public static async Task<List<TSource>> ToListAsync<TSource>(
// this IAsyncEnumerable<TSource> source,
// CancellationToken cancellationToken = default)
// {
// var list = new List<TSource>();
// await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
// {
// list.Add(element);
// }

// return list;
// }

public static List<TSource> ToList<TSource>(this IEnumerable source)
=> source.OfType<TSource>().ToList();
Expand Down
2 changes: 1 addition & 1 deletion test/EFCore.Analyzers.Tests/EFCore.Analyzers.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.Analyzers.Tests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<PreserveCompilationContext>true</PreserveCompilationContext>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.AspNet.InMemory.FunctionalTests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<Nullable>disable</Nullable>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<Description>Shared ASP.NET test suite for Entity Framework Core database providers.</Description>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.AspNet.Specification.Tests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<Nullable>disable</Nullable>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.AspNet.SqlServer.FunctionalTests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<SkipTests Condition="'$(OS)' != 'Windows_NT' AND '$(Test__SqlServer__DefaultConnection)' == ''">True</SkipTests>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.AspNet.Sqlite.FunctionalTests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<ImplicitUsings>true</ImplicitUsings>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.Cosmos.FunctionalTests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<ImplicitUsings>true</ImplicitUsings>
Expand Down
2 changes: 1 addition & 1 deletion test/EFCore.Cosmos.Tests/EFCore.Cosmos.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.Cosmos.Tests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore.Cosmos</RootNamespace>
<Nullable>disable</Nullable>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.CrossStore.FunctionalTests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<Nullable>disable</Nullable>
Expand Down
2 changes: 1 addition & 1 deletion test/EFCore.Design.Tests/EFCore.Design.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<PreserveCompilationContext>true</PreserveCompilationContext>
<AssemblyName>Microsoft.EntityFrameworkCore.Design.Tests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.InMemory.FunctionalTests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<Nullable>disable</Nullable>
Expand Down
2 changes: 1 addition & 1 deletion test/EFCore.InMemory.Tests/EFCore.InMemory.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.InMemory.Tests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<ImplicitUsings>true</ImplicitUsings>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.OData.FunctionalTests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<Nullable>disable</Nullable>
Expand Down
2 changes: 1 addition & 1 deletion test/EFCore.Proxies.Tests/EFCore.Proxies.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.Proxies.Tests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<Nullable>disable</Nullable>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<Description>Shared test suite for Entity Framework Core relational database providers.</Description>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.Relational.Specification.Tests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.Relational.Tests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<Nullable>disable</Nullable>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<Description>Shared test suite for Entity Framework Core database providers.</Description>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.Specification.Tests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,34 @@ public virtual Task Column_collection_of_bools_Contains(bool async)
async,
ss => ss.Set<PrimitiveCollectionsEntity>().Where(c => c.Bools.Contains(true)));

// C# 14 first-class spans caused MemoryExtensions.Contains to get resolved instead of Enumerable.Contains.
// The following tests that the various overloads are all supported.
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Contains_on_Enumerable(bool async)
=> AssertQuery(
async,
ss => ss.Set<PrimitiveCollectionsEntity>().Where(c => Enumerable.Contains(new[] { 10, 999 }, c.Int)));

// C# 14 first-class spans caused MemoryExtensions.Contains to get resolved instead of Enumerable.Contains.
// The following tests that the various overloads are all supported.
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Contains_on_MemoryExtensions(bool async)
=> AssertQuery(
async,
ss => ss.Set<PrimitiveCollectionsEntity>().Where(c => MemoryExtensions.Contains(new[] { 10, 999 }, c.Int)));

// Note that we don't test EF 8/9 with .NET 10; this test is here for completeness/documentation purposes.
#if NET10_0_OR_GREATER
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Contains_with_MemoryExtensions_with_null_comparer(bool async)
=> AssertQuery(
async,
ss => ss.Set<PrimitiveCollectionsEntity>().Where(c => MemoryExtensions.Contains(new[] { 10, 999 }, c.Int, comparer: null)));
#endif

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Column_collection_Count_method(bool async)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<PreserveCompilationContext>true</PreserveCompilationContext>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,45 @@ await context.Database.SqlQuery<string>($"SELECT [Bools] AS [Value] FROM [Primit
.SingleAsync());
}

public override async Task Contains_on_Enumerable(bool async)
{
await base.Contains_on_Enumerable(async);

AssertSql(
"""
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
WHERE [p].[Int] IN (10, 999)
""");
}


public override async Task Contains_on_MemoryExtensions(bool async)
{
await base.Contains_on_MemoryExtensions(async);

AssertSql(
"""
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
WHERE [p].[Int] IN (10, 999)
""");
}

#if NET10_0_OR_GREATER
public override async Task Contains_with_MemoryExtensions_with_null_comparer(bool async)
{
await base.Contains_with_MemoryExtensions_with_null_comparer(async);

AssertSql(
"""
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
WHERE [p].[Int] IN (10, 999)
""");
}
#endif

public override Task Column_collection_Count_method(bool async)
=> AssertCompatibilityLevelTooLow(() => base.Column_collection_Count_method(async));

Expand Down
Loading
Loading