diff --git a/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs b/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs index cfca01c439..7878adc629 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Alexis Kochetov @@ -124,8 +124,7 @@ protected override Expression VisitUnary(UnaryExpression u) protected override Expression VisitLambda(LambdaExpression le) { - using (state.CreateLambdaScope(le)) { - state.AllowCalculableColumnCombine = false; + using (CreateLambdaScope(le, allowCalculableColumnCombine: false)) { Expression body = le.Body; if (!state.IsTailMethod) body = NullComparsionRewriter.Rewrite(body); @@ -147,8 +146,7 @@ protected override Expression VisitLambda(LambdaExpression le) protected override MemberAssignment VisitMemberAssignment(MemberAssignment ma) { Expression expression; - using (state.CreateScope()) { - state.CalculateExpressions = false; + using (CreateScope(new TranslatorState(state) { CalculateExpressions = false })) { expression = Visit(ma.Expression); } @@ -314,8 +312,7 @@ protected override Expression VisitMemberAccess(MemberExpression ma) throw new NotSupportedException(String.Format(Strings.ExFieldMustBePersistent, ma.ToString(true))); } Expression source; - using (state.CreateScope()) { -// state.BuildingProjection = false; + using (CreateScope(new TranslatorState(state) { /* BuildingProjection = false */ })) { source = Visit(ma.Expression); } @@ -325,8 +322,7 @@ protected override Expression VisitMemberAccess(MemberExpression ma) protected override Expression VisitMethodCall(MethodCallExpression mc) { - using (state.CreateScope()) { - state.IsTailMethod = mc==context.Query && mc.IsQuery(); + using (CreateScope(new TranslatorState(state) { IsTailMethod = mc == context.Query && mc.IsQuery() })) { var method = mc.Method; var customCompiler = context.CustomCompilerProvider.GetCompiler(method); if (customCompiler != null) { @@ -1134,7 +1130,7 @@ private ColumnExpression AddCalculatedColumn(ParameterExpression sourceParameter context.Bindings.ReplaceBound(sourceParameter, newResult); var result = ColumnExpression.Create(originalColumnType, dataSource.Header.Length - 1); - state.AllowCalculableColumnCombine = true; + ModifyStateAllowCalculableColumnCombine(true); return result; } @@ -1398,7 +1394,7 @@ private Expression VisitTypeAs(Expression source, Type targetType) return Visit(Expression.Convert(source, targetType)); // Cast to subclass or interface. - using (state.CreateScope()) { + using (CreateScope(new TranslatorState(state))) { //!!! why to create State Scope without modifying the state? var targetTypeInfo = context.Model.Types[targetType]; // Using of state.Parameter[0] is a very weak approach. // `as` operator could be applied on expression that has no relation with current parameter diff --git a/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs b/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs index 485e1872f7..2851c9620f 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs @@ -145,8 +145,7 @@ private List VisitNewExpressionArguments(NewExpression n) var arguments = new List(); foreach (var argument in n.Arguments) { Expression body; - using (state.CreateScope()) { - state.CalculateExpressions = false; + using (CreateScope(new TranslatorState(state) { CalculateExpressions = false })) { body = Visit(argument); } body = body.IsProjection() @@ -203,7 +202,6 @@ internal Translator(TranslatorContext context, CompiledQueryProcessingScope comp { this.compiledQueryScope = compiledQueryScope; this.context = context; - state = new TranslatorState(this); } static Translator() diff --git a/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs b/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs index b47a71c399..5b16fb2ce3 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Alexis Kochetov @@ -28,9 +28,35 @@ internal sealed partial class Translator : QueryableVisitor { private static readonly Type IEnumerableOfKeyType = typeof(IEnumerable); - public TranslatorState state; + internal TranslatorState state { get; private set; } = TranslatorState.InitState; private readonly TranslatorContext context; + internal void RestoreState(in TranslatorState previousState) => + state = previousState; + + public TranslatorState.TranslatorScope CreateScope(in TranslatorState newState) + { + var scope = new TranslatorState.TranslatorScope(this); + state = newState; + return scope; + } + + public TranslatorState.TranslatorScope CreateLambdaScope(LambdaExpression le, bool allowCalculableColumnCombine) + { + var newOuterParameters = new ParameterExpression[state.OuterParameters.Length + state.Parameters.Length]; + state.OuterParameters.CopyTo(newOuterParameters, 0); + state.Parameters.CopyTo(newOuterParameters, state.OuterParameters.Length); + return CreateScope(new TranslatorState(state) { + OuterParameters = newOuterParameters, + Parameters = le.Parameters.ToArray(le.Parameters.Count), + CurrentLambda = le, + AllowCalculableColumnCombine = allowCalculableColumnCombine + }); + } + + private void ModifyStateAllowCalculableColumnCombine(bool b) => + state = new TranslatorState(state) { AllowCalculableColumnCombine = b }; + protected override Expression VisitConstant(ConstantExpression c) { if (c.Value == null) { @@ -46,7 +72,7 @@ protected override Expression VisitConstant(ConstantExpression c) protected override Expression VisitQueryableMethod(MethodCallExpression mc, QueryableMethodKind methodKind) { - using (state.CreateScope()) { + using (CreateScope(new TranslatorState(state))) { switch (methodKind) { case QueryableMethodKind.Cast: return VisitCast(mc.Arguments[0], mc.Method.GetGenericArguments()[0], @@ -73,8 +99,9 @@ protected override Expression VisitQueryableMethod(MethodCallExpression mc, Quer case QueryableMethodKind.Intersect: case QueryableMethodKind.Concat: case QueryableMethodKind.Union: - state.BuildingProjection = false; - return VisitSetOperations(mc.Arguments[0], mc.Arguments[1], methodKind, mc.Method.GetGenericArguments()[0]); + using (CreateScope(new TranslatorState(state) { BuildingProjection = false })) { + return VisitSetOperations(mc.Arguments[0], mc.Arguments[1], methodKind, mc.Method.GetGenericArguments()[0]); + } case QueryableMethodKind.Reverse: break; case QueryableMethodKind.SequenceEqual: @@ -142,34 +169,39 @@ protected override Expression VisitQueryableMethod(MethodCallExpression mc, Quer break; case QueryableMethodKind.GroupBy: - state.BuildingProjection = false; - var groupBy = QueryParser.ParseGroupBy(mc); - return VisitGroupBy(mc.Method.ReturnType, - groupBy.Source, - groupBy.KeySelector, - groupBy.ElementSelector, - groupBy.ResultSelector); + using (CreateScope(new TranslatorState(state) { BuildingProjection = false })) { + var groupBy = QueryParser.ParseGroupBy(mc); + return VisitGroupBy(mc.Method.ReturnType, + groupBy.Source, + groupBy.KeySelector, + groupBy.ElementSelector, + groupBy.ResultSelector); + } case QueryableMethodKind.GroupJoin: - state.BuildingProjection = false; - return VisitGroupJoin(mc.Arguments[0], - mc.Arguments[1], - mc.Arguments[2].StripQuotes(), - mc.Arguments[3].StripQuotes(), - mc.Arguments[4].StripQuotes(), - mc.Arguments.Count > 5 ? mc.Arguments[5] : null, - mc); + using (CreateScope(new TranslatorState(state) { BuildingProjection = false })) { + return VisitGroupJoin(mc.Arguments[0], + mc.Arguments[1], + mc.Arguments[2].StripQuotes(), + mc.Arguments[3].StripQuotes(), + mc.Arguments[4].StripQuotes(), + mc.Arguments.Count > 5 ? mc.Arguments[5] : null, + mc); + } case QueryableMethodKind.Join: - state.BuildingProjection = false; - return VisitJoin(mc.Arguments[0], - mc.Arguments[1], - mc.Arguments[2].StripQuotes(), - mc.Arguments[3].StripQuotes(), - mc.Arguments[4].StripQuotes(), - false, - mc); + using (CreateScope(new TranslatorState(state) { BuildingProjection = false })) { + return VisitJoin(mc.Arguments[0], + mc.Arguments[1], + mc.Arguments[2].StripQuotes(), + mc.Arguments[3].StripQuotes(), + mc.Arguments[4].StripQuotes(), + false, + mc); + } case QueryableMethodKind.OrderBy: case QueryableMethodKind.OrderByDescending: - return VisitSort(mc); + using (CreateScope(new TranslatorState(state) { BuildingProjection = false })) { + return VisitSort(mc); + } case QueryableMethodKind.Select: return VisitSelect(mc.Arguments[0], mc.Arguments[1].StripQuotes()); case QueryableMethodKind.SelectMany: @@ -217,10 +249,13 @@ protected override Expression VisitQueryableMethod(MethodCallExpression mc, Quer break; case QueryableMethodKind.ThenBy: case QueryableMethodKind.ThenByDescending: - return VisitSort(mc); + using (CreateScope(new TranslatorState(state) { BuildingProjection = false })) { + return VisitSort(mc); + } case QueryableMethodKind.Where: - state.BuildingProjection = false; - return VisitWhere(mc.Arguments[0], mc.Arguments[1].StripQuotes()); + using (CreateScope(new TranslatorState(state) { BuildingProjection = false })) { + return VisitWhere(mc.Arguments[0], mc.Arguments[1].StripQuotes()); + } default: throw new ArgumentOutOfRangeException(nameof(methodKind)); } @@ -432,10 +467,9 @@ private Expression VisitFirstSingle(Expression source, LambdaExpression predicat var applySequenceType = ApplySequenceType.All; ProjectionExpression projection; - using (state.CreateScope()) { - var isPrimitiveType = context.ProviderInfo.SupportedTypes.Contains(method.ReturnType); - state.RequestCalculateExpressions = state.RequestCalculateExpressions - || !isRoot && isPrimitiveType; + using (CreateScope(new TranslatorState(state) { + RequestCalculateExpressions = state.RequestCalculateExpressions || !isRoot && context.ProviderInfo.SupportedTypes.Contains(method.ReturnType) + })) { projection = predicate != null ? VisitWhere(source, predicate) : VisitSequence(source); } @@ -655,8 +689,7 @@ private ProjectionExpression VisitSkip(Expression source, Expression skip) private ProjectionExpression VisitDistinct(Expression expression) { ProjectionExpression result; - using (state.CreateScope()) { - state.RequestCalculateExpressionsOnce = true; + using (CreateScope(new TranslatorState(state) { RequestCalculateExpressionsOnce = true })) { result = VisitSequence(expression); } @@ -842,8 +875,7 @@ private Pair VisitAggregateSource(Expression source, if (aggregateParameter != null) { using (context.Bindings.Add(aggregateParameter.Parameters[0], sourceProjection)) - using (state.CreateScope()) { - state.CalculateExpressions = true; + using (CreateScope(new TranslatorState(state) { CalculateExpressions = true })) { var result = (ItemProjectorExpression) VisitLambda(aggregateParameter); if (!result.IsPrimitive) { throw new NotSupportedException( @@ -921,9 +953,7 @@ private ProjectionExpression VisitGroupBy(Type returnType, Expression source, La ProjectionExpression groupingSourceProjection; context.Bindings.PermanentAdd(keySelector.Parameters[0], sequence); - using (state.CreateScope()) { - state.CalculateExpressions = true; - state.GroupingKey = true; + using (CreateScope(new TranslatorState(state) { CalculateExpressions = true, GroupingKey = true })) { var itemProjector = (ItemProjectorExpression) VisitLambda(keySelector); groupingSourceProjection = new ProjectionExpression( WellKnownInterfaces.QueryableOfT.MakeGenericType(keySelector.Body.Type), @@ -1027,8 +1057,7 @@ private ProjectionExpression VisitGroupBy(Type returnType, Expression source, La // var groupingParameter = Expression.Parameter(groupingProjection.ItemProjector.Item.Type, "groupingParameter"); // var applyParameter = context.GetApplyParameter(groupingProjection); // using (context.Bindings.Add(groupingParameter, groupingProjection)) - // using (state.CreateScope()) { - // state.Parameters = state.Parameters.AddOne(groupingParameter).ToArray(); + // using (CreateScope(new TranslatorState(state) { Parameters = state.Parameters.AddOne(groupingParameter).ToArray() })) { // var lambda = FastExpression.Lambda(Expression.Equal(groupingParameter, keySelector.Body), keySelector.Parameters); // subqueryProjection = VisitWhere(VisitSequence(source), lambda); // } @@ -1080,10 +1109,8 @@ private Expression VisitSort(Expression expression) throw new InvalidOperationException(string.Format(Strings.ExInvalidSortExpressionX, expression)); } - state.BuildingProjection = false; ProjectionExpression projection; - using (state.CreateScope()) { - state.CalculateExpressions = false; + using (CreateScope(new TranslatorState(state) { CalculateExpressions = false })) { projection = VisitSequence(extractor.BaseExpression); } @@ -1094,9 +1121,7 @@ private Expression VisitSort(Expression expression) var direction = item.Value; var sortParameter = sortExpression.Parameters[0]; using (context.Bindings.Add(sortParameter, projection)) - using (state.CreateScope()) { - state.ShouldOmitConvertToObject = true; - state.CalculateExpressions = true; + using (CreateScope(new TranslatorState(state) { ShouldOmitConvertToObject = true, CalculateExpressions = true })) { var orderByProjector = (ItemProjectorExpression) VisitLambda(sortExpression); var columns = orderByProjector .GetColumns(ColumnExtractionModes.TreatEntityAsKey | ColumnExtractionModes.Distinct); @@ -1126,8 +1151,7 @@ private ProjectionExpression VisitJoin(Expression outerSource, Expression innerS using (context.Bindings.Add(innerParameter, innerSequence)) { ItemProjectorExpression outerKeyProjector; ItemProjectorExpression innerKeyProjector; - using (state.CreateScope()) { - state.CalculateExpressions = true; + using (CreateScope(new TranslatorState(state) { CalculateExpressions = true })) { outerKeyProjector = (ItemProjectorExpression) VisitLambda(outerKey); innerKeyProjector = (ItemProjectorExpression) VisitLambda(innerKey); } @@ -1194,8 +1218,7 @@ private Expression VisitGroupJoin(Expression outerSource, Expression innerSource var groupingResultType = WellKnownInterfaces.QueryableOfT.MakeGenericType(enumerableType); ProjectionExpression innerGrouping; - using (state.CreateScope()) { - state.SkipNullableColumnsDetectionInGroupBy = true; + using (CreateScope(new TranslatorState(state) { SkipNullableColumnsDetectionInGroupBy = true })) { innerGrouping = VisitGroupBy(groupingResultType, visitedInnerSource, innerKey, null, null); } @@ -1260,13 +1283,14 @@ private ProjectionExpression VisitSelectMany(Expression source, LambdaExpression } ProjectionExpression innerProjection; - using (state.CreateScope()) { - state.OuterParameters = state.OuterParameters - .Concat(state.Parameters) - .Concat(collectionSelector.Parameters) - .Append(outerParameter).ToArray(); - state.Parameters = Array.Empty(); - state.RequestCalculateExpressionsOnce = true; + using (CreateScope(new TranslatorState(state) { + OuterParameters = state.OuterParameters + .Concat(state.Parameters) + .Concat(collectionSelector.Parameters) + .Append(outerParameter).ToArray(), + Parameters = Array.Empty(), + RequestCalculateExpressionsOnce = true + })) { var visitedCollectionSelector = Visit(collectionSelector.Body); if (visitedCollectionSelector.IsGroupingExpression()) { @@ -1346,18 +1370,17 @@ private ProjectionExpression VisitSelect(Expression expression, LambdaExpression } context.Bindings.PermanentAdd(le.Parameters[0], sequence); - using (state.CreateScope()) { - state.CalculateExpressions = state.RequestCalculateExpressions || state.RequestCalculateExpressionsOnce; - state.RequestCalculateExpressionsOnce = false; - + using (CreateScope(new TranslatorState(state) { + CalculateExpressions = state.RequestCalculateExpressions || state.RequestCalculateExpressionsOnce, + RequestCalculateExpressionsOnce = false + })) { return BuildProjection(le); } } private ProjectionExpression BuildProjection(LambdaExpression le) { - using (state.CreateScope()) { - state.BuildingProjection = true; + using (CreateScope(new TranslatorState(state) { BuildingProjection = true })) { var itemProjector = (ItemProjectorExpression) VisitLambda(le); return new ProjectionExpression( WellKnownInterfaces.QueryableOfT.MakeGenericType(le.Body.Type), @@ -1378,9 +1401,7 @@ private ProjectionExpression VisitWhere(Expression expression, LambdaExpression using (indexBinding) using (context.Bindings.Add(parameter, visitedSource)) - using (state.CreateScope()) { - state.CalculateExpressions = false; - state.CurrentLambda = le; + using (CreateScope(new TranslatorState(state) { CalculateExpressions = false, CurrentLambda = le })) { var predicateExpression = (ItemProjectorExpression) VisitLambda(le); var predicate = predicateExpression.ToLambda(context); var source = context.Bindings[parameter]; @@ -1419,8 +1440,7 @@ private Expression VisitExists(Expression source, LambdaExpression predicate, bo } ProjectionExpression subquery; - using (state.CreateScope()) { - state.CalculateExpressions = false; + using (CreateScope(new TranslatorState(state) { CalculateExpressions = false })) { subquery = predicate == null ? VisitSequence(source) : VisitWhere(source, predicate); @@ -1445,25 +1465,20 @@ private Expression VisitExistsAsInclude(Expression source, LambdaExpression pred var parameter = predicate.Parameters[0]; ProjectionExpression visitedSource; - using (state.CreateScope()) { - if (source.IsLocalCollection(context) && IsKeyCollection(source.Type)) { - var localCollectionKeyType = LocalCollectionKeyTypeExtractor.Extract((BinaryExpression) predicate.Body); - state.TypeOfEntityStoredInKey = localCollectionKeyType; - } - - state.IncludeAlgorithm = IncludeAlgorithm.Auto; + using (CreateScope(new TranslatorState(state) { + TypeOfEntityStoredInKey = source.IsLocalCollection(context) && IsKeyCollection(source.Type) + ? LocalCollectionKeyTypeExtractor.Extract((BinaryExpression) predicate.Body) + : state.TypeOfEntityStoredInKey, + IncludeAlgorithm = IncludeAlgorithm.Auto + })) { visitedSource = VisitSequence(source); } var outerParameter = state.Parameters[0]; using (context.Bindings.Add(parameter, visitedSource)) - using (state.CreateScope()) { - state.CalculateExpressions = false; - state.CurrentLambda = predicate; - + using (CreateScope(new TranslatorState(state) { CalculateExpressions = false, CurrentLambda = predicate })) { ItemProjectorExpression predicateExpression; - using (state.CreateScope()) { - state.IncludeAlgorithm = IncludeAlgorithm.Auto; + using (CreateScope(new TranslatorState(state) { IncludeAlgorithm = IncludeAlgorithm.Auto })) { predicateExpression = (ItemProjectorExpression) VisitLambda(predicate); } @@ -1540,8 +1555,7 @@ private Expression VisitIn(MethodCallExpression mc) break; } - using (state.CreateScope()) { - state.IncludeAlgorithm = algorithm; + using (CreateScope(new TranslatorState(state) { IncludeAlgorithm = algorithm })) { return VisitContains(source, match, false); } } @@ -1555,10 +1569,7 @@ private Expression VisitSetOperations(Expression outerSource, Expression innerSo QueryHelper.TryAddConvarianceCast(ref outerSource, elementType); QueryHelper.TryAddConvarianceCast(ref innerSource, elementType); - using (state.CreateScope()) { - state.JoinLocalCollectionEntity = true; - state.CalculateExpressions = true; - state.RequestCalculateExpressions = true; + using (CreateScope(new TranslatorState(state) { JoinLocalCollectionEntity = true, CalculateExpressions = true, RequestCalculateExpressions = true })) { outer = VisitSequence(outerSource); inner = VisitSequence(innerSource); } diff --git a/Orm/Xtensive.Orm/Orm/Linq/TranslatorState.cs b/Orm/Xtensive.Orm/Orm/Linq/TranslatorState.cs index 1799f27b6f..81269f5ff0 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/TranslatorState.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/TranslatorState.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2010-2020 Xtensive LLC. +// Copyright (C) 2010-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Alexey Gamzov @@ -6,11 +6,11 @@ using System; using System.Linq.Expressions; -using Xtensive.Core; +using System.Runtime.CompilerServices; namespace Xtensive.Orm.Linq { - internal sealed class TranslatorState + internal readonly struct TranslatorState { [Flags] private enum TranslatorStateFlags @@ -27,155 +27,118 @@ private enum TranslatorStateFlags SkipNullableColumnsDetectionInGroupBy = 1 << 9 } - internal readonly ref struct TranslatorScope + internal readonly struct TranslatorScope : IDisposable { private readonly TranslatorState previousState; private readonly Translator translator; - public void Dispose() => translator.state = previousState; + public void Dispose() => translator.RestoreState(previousState); - public TranslatorScope(Translator translator, TranslatorState previousState) + public TranslatorScope(Translator translator) { this.translator = translator; - this.previousState = previousState; + previousState = translator.state; } } - private readonly Translator translator; + public static readonly TranslatorState InitState = new TranslatorState { + BuildingProjection = true, + IsTailMethod = true, + OuterParameters = Array.Empty(), + Parameters = Array.Empty(), + CurrentLambda = null, + IncludeAlgorithm = IncludeAlgorithm.Auto, + TypeOfEntityStoredInKey = null, + }; - private TranslatorStateFlags flags; + private readonly TranslatorStateFlags flags; - public ParameterExpression[] Parameters { get; set; } + public ParameterExpression[] Parameters { get; init; } - public ParameterExpression[] OuterParameters { get; set; } + public ParameterExpression[] OuterParameters { get; init; } - public LambdaExpression CurrentLambda { get; set; } + public LambdaExpression CurrentLambda { get; init; } - public IncludeAlgorithm IncludeAlgorithm { get; set; } + public IncludeAlgorithm IncludeAlgorithm { get; init; } - public Type TypeOfEntityStoredInKey { get; set; } + public Type TypeOfEntityStoredInKey { get; init; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool GetFlag(TranslatorStateFlags f) => (flags & f) != 0; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ModifyFlag(ref TranslatorStateFlags flags, TranslatorStateFlags f, bool value) => + flags = value ? flags | f : flags & ~f; public bool JoinLocalCollectionEntity { - get => (flags & TranslatorStateFlags.JoinLocalCollectionEntity) != 0; - set => flags = value - ? flags | TranslatorStateFlags.JoinLocalCollectionEntity - : flags & ~TranslatorStateFlags.JoinLocalCollectionEntity; + get => GetFlag(TranslatorStateFlags.JoinLocalCollectionEntity); + init => ModifyFlag(ref flags, TranslatorStateFlags.JoinLocalCollectionEntity, value); } - public bool AllowCalculableColumnCombine { - get => (flags & TranslatorStateFlags.AllowCalculableColumnCombine) != 0; - set => flags = value - ? flags | TranslatorStateFlags.AllowCalculableColumnCombine - : flags & ~TranslatorStateFlags.AllowCalculableColumnCombine; + public bool AllowCalculableColumnCombine + { + get => GetFlag(TranslatorStateFlags.AllowCalculableColumnCombine); + init => ModifyFlag(ref flags, TranslatorStateFlags.AllowCalculableColumnCombine, value); } public bool BuildingProjection { - get => (flags & TranslatorStateFlags.IsBuildingProjection) != 0; - set => flags = value - ? flags | TranslatorStateFlags.IsBuildingProjection - : flags & ~TranslatorStateFlags.IsBuildingProjection; + get => GetFlag(TranslatorStateFlags.IsBuildingProjection); + init => ModifyFlag(ref flags, TranslatorStateFlags.IsBuildingProjection, value); } public bool CalculateExpressions { - get => (flags & TranslatorStateFlags.CalculateExpressions) != 0; - set => flags = value - ? flags | TranslatorStateFlags.CalculateExpressions - : flags & ~TranslatorStateFlags.CalculateExpressions; + get => GetFlag(TranslatorStateFlags.CalculateExpressions); + init => ModifyFlag(ref flags, TranslatorStateFlags.CalculateExpressions, value); } public bool GroupingKey { - get => (flags & TranslatorStateFlags.IsGroupingKey) != 0; - set => flags = value - ? flags | TranslatorStateFlags.IsGroupingKey - : flags & ~TranslatorStateFlags.IsGroupingKey; + get => GetFlag(TranslatorStateFlags.IsGroupingKey); + init => ModifyFlag(ref flags, TranslatorStateFlags.IsGroupingKey, value); } public bool IsTailMethod { - get => (flags & TranslatorStateFlags.IsTailMethod) != 0; - set => flags = value - ? flags | TranslatorStateFlags.IsTailMethod - : flags & ~TranslatorStateFlags.IsTailMethod; + get => GetFlag(TranslatorStateFlags.IsTailMethod); + init => ModifyFlag(ref flags, TranslatorStateFlags.IsTailMethod, value); } public bool ShouldOmitConvertToObject { - get => (flags & TranslatorStateFlags.ShouldOmitConvertToObject) != 0; - set => flags = value - ? flags | TranslatorStateFlags.ShouldOmitConvertToObject - : flags & ~TranslatorStateFlags.ShouldOmitConvertToObject; + get => GetFlag(TranslatorStateFlags.ShouldOmitConvertToObject); + init => ModifyFlag(ref flags, TranslatorStateFlags.ShouldOmitConvertToObject, value); } public bool RequestCalculateExpressions { - get => (flags & TranslatorStateFlags.RequestCalculateExpressions) != 0; - set => flags = value - ? flags | TranslatorStateFlags.RequestCalculateExpressions - : flags & ~TranslatorStateFlags.RequestCalculateExpressions; + get => GetFlag(TranslatorStateFlags.RequestCalculateExpressions); + init => ModifyFlag(ref flags, TranslatorStateFlags.RequestCalculateExpressions, value); } public bool RequestCalculateExpressionsOnce { - get => (flags & TranslatorStateFlags.RequestCalculateExpressionsOnce) != 0; - set => flags = value - ? flags | TranslatorStateFlags.RequestCalculateExpressionsOnce - : flags & ~TranslatorStateFlags.RequestCalculateExpressionsOnce; - } - - public bool SkipNullableColumnsDetectionInGroupBy - { - get => (flags & TranslatorStateFlags.SkipNullableColumnsDetectionInGroupBy) != 0; - set => flags = value - ? flags | TranslatorStateFlags.SkipNullableColumnsDetectionInGroupBy - : flags & ~TranslatorStateFlags.SkipNullableColumnsDetectionInGroupBy; - } - - public TranslatorScope CreateScope() - { - var currentState = translator.state; - translator.state = new TranslatorState(currentState); - return new TranslatorScope(translator, currentState); + get => GetFlag(TranslatorStateFlags.RequestCalculateExpressionsOnce); + init => ModifyFlag(ref flags, TranslatorStateFlags.RequestCalculateExpressionsOnce, value); } - public TranslatorScope CreateLambdaScope(LambdaExpression le) + public bool SkipNullableColumnsDetectionInGroupBy { - var currentState = translator.state; - var newState = new TranslatorState(currentState); - var newOuterParameters = new ParameterExpression[newState.OuterParameters.Length + newState.Parameters.Length]; - newState.OuterParameters.CopyTo(newOuterParameters, 0); - newState.Parameters.CopyTo(newOuterParameters, newState.OuterParameters.Length); - newState.OuterParameters = newOuterParameters; - newState.Parameters = le.Parameters.ToArray(le.Parameters.Count); - newState.CurrentLambda = le; - translator.state = newState; - return new TranslatorScope(translator, currentState); + get => GetFlag(TranslatorStateFlags.SkipNullableColumnsDetectionInGroupBy); + init => ModifyFlag(ref flags, TranslatorStateFlags.SkipNullableColumnsDetectionInGroupBy, value); } - - // Constructors - - public TranslatorState(Translator translator) - { - this.translator = translator; - flags = TranslatorStateFlags.IsBuildingProjection | TranslatorStateFlags.IsTailMethod; - OuterParameters = Parameters = Array.Empty(); - IncludeAlgorithm = IncludeAlgorithm.Auto; - TypeOfEntityStoredInKey = null; - } - - private TranslatorState(TranslatorState currentState) - { - translator = currentState.translator; - flags = currentState.flags; - Parameters = currentState.Parameters; - OuterParameters = currentState.OuterParameters; - CurrentLambda = currentState.CurrentLambda; - IncludeAlgorithm = currentState.IncludeAlgorithm; - TypeOfEntityStoredInKey = currentState.TypeOfEntityStoredInKey; - } + public TranslatorState(in TranslatorState currentState) => + this = currentState; } -} \ No newline at end of file +} + +#if !NET5_0_OR_GREATER +// Workaround of error CS0518: Predefined type 'System.Runtime.CompilerServices.IsExternalInit' is not defined or imported +namespace System.Runtime.CompilerServices +{ + internal static class IsExternalInit { } +} +#endif