Skip to content

Commit

Permalink
Correct VisitUnary operand evaluation in funcletizer (dotnet#35172)
Browse files Browse the repository at this point in the history
Fixes dotnet#35152

(cherry picked from commit 3ba88c4)
  • Loading branch information
roji committed Nov 26, 2024
1 parent bd7d0aa commit 73ec049
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 2 deletions.
18 changes: 16 additions & 2 deletions src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ public class ExpressionTreeFuncletizer : ExpressionVisitor

private static readonly IReadOnlySet<string> EmptyStringSet = new HashSet<string>();

private static readonly bool UseOldBehavior35152 =
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue35152", out var enabled35152) && enabled35152;

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 @@ -1548,9 +1551,20 @@ UnaryExpression EvaluateOperand(UnaryExpression unary, Expression operand, State
operand = ProcessEvaluatableRoot(operand, ref operandState);
}

if (_state.ContainsEvaluatable)
if (UseOldBehavior35152)
{
if (_state.ContainsEvaluatable)
{
_state = _calculatingPath
? State.CreateContainsEvaluatable(
typeof(UnaryExpression),
[_state.Path! with { PathFromParent = static e => Property(e, nameof(UnaryExpression.Operand)) }])
: State.NoEvaluatability;
}
}
else
{
_state = _calculatingPath
_state = operandState.ContainsEvaluatable && _calculatingPath
? State.CreateContainsEvaluatable(
typeof(UnaryExpression),
[_state.Path! with { PathFromParent = static e => Property(e, nameof(UnaryExpression.Operand)) }])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5276,6 +5276,17 @@ public virtual async Task ToPageAsync_in_subquery_throws()

#endregion ToPageAsync

public override async Task Cast_to_object_over_parameter_directly_in_lambda(bool async)
{
// Sync always throws before getting to exception being tested.
if (async)
{
// Cosmos doesn't support ORDER BY over parameter/constant:
// Unsupported ORDER BY clause. ORDER BY item expression could not be mapped to a document path.
await Assert.ThrowsAsync<CosmosException>(() => base.Cast_to_object_over_parameter_directly_in_lambda(async: true));
}
}

private void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5849,4 +5849,15 @@ public virtual Task Static_member_access_gets_parameterized_within_larger_evalua

private static string StaticProperty
=> "ALF";

[ConditionalTheory] // #35152
[MemberData(nameof(IsAsyncData))]
public virtual Task Cast_to_object_over_parameter_directly_in_lambda(bool async)
{
var i = 8;

return AssertQuery(
async,
ss => ss.Set<Order>().OrderBy(o => (object)i).Select(o => o));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7461,6 +7461,17 @@ FROM [Orders] AS [o]
""");
}

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

AssertSql(
"""
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate]
FROM [Orders] AS [o]
""");
}

private void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);

Expand Down

0 comments on commit 73ec049

Please sign in to comment.