From 09bd3e2e0235a62c1205f8d8cfbfa1fb8061babd Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Wed, 12 Feb 2025 00:25:58 -0800 Subject: [PATCH 1/3] Process `ReadOnlySpan` case (appears with `.NET 9.0.200`) --- Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs b/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs index 3c0483e52..2ce5f7c23 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs @@ -1849,11 +1849,10 @@ private static IReadOnlySet GetNullableGroupingExpressions(IReadOnlyList<(C return nullableFields; } - private bool IsKeyCollection(Type localCollectionType) - { - return (localCollectionType.IsArray && localCollectionType.GetElementType() == WellKnownOrmTypes.Key) - || IEnumerableOfKeyType.IsAssignableFrom(localCollectionType); - } + private bool IsKeyCollection(Type localCollectionType) => + (localCollectionType.IsArray && localCollectionType.GetElementType() == WellKnownOrmTypes.Key) + || IEnumerableOfKeyType.IsAssignableFrom(localCollectionType) + || localCollectionType.IsOfGenericType(WellKnownTypes.ReadOnlySpanOfT) && localCollectionType.GetGenericArguments()[0] == WellKnownOrmTypes.Key; internal void RestoreState(in TranslatorState previousState) => State = previousState; From 54f5774991a813044a0a3539462ded3fbe0427a2 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Wed, 12 Feb 2025 00:29:03 -0800 Subject: [PATCH 2/3] Update global.json --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index f721ea586..34dc88acd 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { "allowPrerelease": true, - "version": "9.0.102", + "version": "9.0.200", "rollForward": "latestMajor" } } From 01c20e7b96a908356a2a4696cf7e3098b49c02a8 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Wed, 12 Feb 2025 02:01:54 -0800 Subject: [PATCH 3/3] Substitute `IEnumerable<>.Contains()` instead of `ReadOnlySpan<>`.Contains() --- Orm/Xtensive.Orm/Orm/Linq/WellKnownMembers.cs | 6 ++++++ .../Providers/Expressions/ExpressionProcessor.cs | 13 ++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm/Orm/Linq/WellKnownMembers.cs b/Orm/Xtensive.Orm/Orm/Linq/WellKnownMembers.cs index 37951de9e..d07fd5de1 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/WellKnownMembers.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/WellKnownMembers.cs @@ -249,6 +249,12 @@ public static class Enumerable public static readonly MethodInfo Cast = GetMethod(typeof(System.Linq.Enumerable), nameof(System.Linq.Enumerable.Cast), 1, 1); } + public static class MemoryExtensions + { + public static readonly MethodInfo ContainsInReadOnlySpan = typeof(System.MemoryExtensions).GetMethods() + .Where(m => m.Name == "Contains" && m.GetParameterTypes()[0].GetGenericTypeDefinition() == WellKnownTypes.ReadOnlySpanOfT).First(); + } + // IEntity public static readonly PropertyInfo IEntityKey = WellKnownOrmInterfaces.Entity.GetProperty(WellKnown.KeyFieldName); public static readonly PropertyInfo TypeId = WellKnownOrmInterfaces.Entity.GetProperty(WellKnown.TypeIdFieldName); diff --git a/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.cs b/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.cs index ace437894..5addb7b6c 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.cs @@ -90,6 +90,13 @@ private SqlExpression Visit(Expression e, bool smartNull) if (evaluator.CanBeEvaluated(e)) { if (parameterExtractor.IsParameter(e)) return VisitParameterAccess(e, smartNull); + if (e.NodeType == ExpressionType.Call) { + var mc = (MethodCallExpression) e; + var methodDeclaringType = mc.Method.DeclaringType; + if (methodDeclaringType.IsGenericType && methodDeclaringType.GetGenericTypeDefinition() == WellKnownTypes.ReadOnlySpanOfT) { + e = mc.Arguments[0]; + } + } return VisitConstant(ExpressionEvaluator.Evaluate(e)); } return base.Visit(e); @@ -410,8 +417,12 @@ protected override SqlExpression VisitMethodCall(MethodCallExpression mc) var arguments = mc.Arguments.SelectToArray(a => Visit(a)); var mi = mc.Method; - if (mc.Object!=null && mc.Object.Type!=mi.ReflectedType) + if (mc.Object!=null && mc.Object.Type!=mi.ReflectedType) { mi = mc.Object.Type.GetMethod(mi.Name, mi.GetParameterTypes()); + } + else if (mi.IsGenericMethod && mi.GetGenericMethodDefinition() == WellKnownMembers.MemoryExtensions.ContainsInReadOnlySpan) { + mi = WellKnownMembers.Enumerable.Contains.CachedMakeGenericMethod(mi.GetGenericArguments()[0]); + } return CompileMember(mi, Visit(mc.Object), arguments); }