Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement nullability simplification for COLLATE and AT TIME ZONE #34263

Merged
merged 6 commits into from
Jul 26, 2024

Conversation

ranma42
Copy link
Contributor

@ranma42 ranma42 commented Jul 21, 2024

This changeset extends the simplification for IS [NOT] NULL to handle COLLATE and AT TIME ZONE.

Closes #34295

@ranma42
Copy link
Contributor Author

ranma42 commented Jul 21, 2024

This was born out of @roji's comment here: #34127 (comment)

Should I simply open a new issue covering COLLATE/AT TIME ZONE or there is some place where nullability computation for the AST is being tracked?

@ranma42 ranma42 marked this pull request as ready for review July 21, 2024 15:43
@cincuranet
Copy link
Contributor

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@cincuranet
Copy link
Contributor

The Helix failure(s) is weird:

    Microsoft.EntityFrameworkCore.Query.PrecompiledQuerySqliteTest.ToDictionary_over_anonymous_type [FAIL]
      Precompilation error: System.IO.FileLoadException: Could not load file or assembly 'TestCompilation, Culture=neutral, PublicKeyToken=null'. An operation is not legal in the current state. (0x80131509)
      File name: 'TestCompilation, Culture=neutral, PublicKeyToken=null'
       ---> System.InvalidOperationException: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.
         at System.Collections.Generic.Dictionary`2.FindValue(TKey key)
         at System.Collections.Generic.Dictionary`2.TryGetValue(TKey key, TValue& value)
         at Xunit.DependencyContextAssemblyCache.LoadManagedDll(String assemblyName, Func`2 managedAssemblyLoader) in /_/src/common/AssemblyResolution/DependencyContextAssemblyCache.cs:line 158
         at Xunit.AssemblyHelper.OnResolving(AssemblyLoadContext context, AssemblyName name) in /_/src/common/AssemblyResolution/AssemblyHelper_NetCoreApp.cs:line 85
         at System.Runtime.Loader.AssemblyLoadContext.GetFirstResolvedAssemblyFromResolvingEvent(AssemblyName assemblyName)
         at System.Runtime.Loader.AssemblyLoadContext.ResolveUsingEvent(AssemblyName assemblyName)
         at System.Runtime.Loader.AssemblyLoadContext.ResolveUsingResolvingEvent(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName)
      
         at System.Reflection.RuntimeAssembly.<InternalLoad>g____PInvoke|49_0(NativeAssemblyNameParts* __pAssemblyNameParts_native, ObjectHandleOnStack __requestingAssembly_native, StackCrawlMarkHandle __stackMark_native, Int32 __throwOnFileNotFound_native, ObjectHandleOnStack __assemblyLoadContext_native, ObjectHandleOnStack __retAssembly_native)
         at System.Reflection.RuntimeAssembly.<InternalLoad>g____PInvoke|49_0(NativeAssemblyNameParts* __pAssemblyNameParts_native, ObjectHandleOnStack __requestingAssembly_native, StackCrawlMarkHandle __stackMark_native, Int32 __throwOnFileNotFound_native, ObjectHandleOnStack __assemblyLoadContext_native, ObjectHandleOnStack __retAssembly_native)
         at System.Reflection.RuntimeAssembly.InternalLoad(AssemblyName assemblyName, StackCrawlMark& stackMark, AssemblyLoadContext assemblyLoadContext, RuntimeAssembly requestingAssembly, Boolean throwOnFileNotFound)
         at System.Reflection.Assembly.Load(String assemblyString)
         at Microsoft.EntityFrameworkCore.Query.Internal.CSharpToLinqTranslator.<>c__DisplayClass41_0.<ResolveType>g__LoadAnonymousTypes|2(IAssemblySymbol assemblySymbol) in D:\a\_work\1\s\src\EFCore.Design\Query\Internal\CSharpToLinqTranslator.cs:line 1177
         at Microsoft.EntityFrameworkCore.Query.Internal.CSharpToLinqTranslator.ResolveType(ITypeSymbol typeSymbol, Dictionary`2 genericParameterMap) in D:\a\_work\1\s\src\EFCore.Design\Query\Internal\CSharpToLinqTranslator.cs:line 1075
         at Microsoft.EntityFrameworkCore.Query.Internal.CSharpToLinqTranslator.<>c__DisplayClass25_0.<VisitInvocationExpression>b__2(ITypeSymbol a) in D:\a\_work\1\s\src\EFCore.Design\Query\Internal\CSharpToLinqTranslator.cs:line 593
         at System.Linq.Enumerable.ArraySelectIterator`2.ToArray()
         at Microsoft.EntityFrameworkCore.Query.Internal.CSharpToLinqTranslator.VisitInvocationExpression(InvocationExpressionSyntax invocation) in D:\a\_work\1\s\src\EFCore.Design\Query\Internal\CSharpToLinqTranslator.cs:line 593
         at Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
         at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.Visit(SyntaxNode node)
         at Microsoft.EntityFrameworkCore.Query.Internal.CSharpToLinqTranslator.Visit(SyntaxNode node) in D:\a\_work\1\s\src\EFCore.Design\Query\Internal\CSharpToLinqTranslator.cs:line 124
         at Microsoft.EntityFrameworkCore.Query.Internal.CSharpToLinqTranslator.VisitInvocationExpression(InvocationExpressionSyntax invocation) in D:\a\_work\1\s\src\EFCore.Design\Query\Internal\CSharpToLinqTranslator.cs:line 528
         at Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
         at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.Visit(SyntaxNode node)
         at Microsoft.EntityFrameworkCore.Query.Internal.CSharpToLinqTranslator.Visit(SyntaxNode node) in D:\a\_work\1\s\src\EFCore.Design\Query\Internal\CSharpToLinqTranslator.cs:line 124
         at Microsoft.EntityFrameworkCore.Query.Internal.CSharpToLinqTranslator.Translate(SyntaxNode node, SemanticModel semanticModel) in D:\a\_work\1\s\src\EFCore.Design\Query\Internal\CSharpToLinqTranslator.cs:line 110
         at Microsoft.EntityFrameworkCore.Query.Internal.PrecompiledQueryCodeGenerator.ProcessSyntaxTree(SyntaxTree syntaxTree, SemanticModel semanticModel, IReadOnlyList`1 locatedQueries, List`1 precompilationErrors, String suffix, ISet`1 generatedFileNames, CancellationToken cancellationToken) in D:\a\_work\1\s\src\EFCore.Design\Query\Internal\PrecompiledQueryCodeGenerator.cs:line 157
      Stack Trace:
        D:\a\_work\1\s\test\EFCore.Relational.Specification.Tests\TestUtilities\PrecompiledQueryTestHelpers.cs(122,0): at Microsoft.EntityFrameworkCore.TestUtilities.PrecompiledQueryTestHelpers.FullSourceTest(String sourceCode, DbContextOptions dbContextOptions, Type dbContextType, Action`1 interceptorCodeAsserter, Action`1 errorAsserter, ITestOutputHelper testOutputHelper, Boolean alwaysPrintGeneratedSources, String callerName)
        D:\a\_work\1\s\test\EFCore.Relational.Specification.Tests\TestUtilities\PrecompiledQueryTestHelpers.cs(131,0): at Microsoft.EntityFrameworkCore.TestUtilities.PrecompiledQueryTestHelpers.FullSourceTest(String sourceCode, DbContextOptions dbContextOptions, Type dbContextType, Action`1 interceptorCodeAsserter, Action`1 errorAsserter, ITestOutputHelper testOutputHelper, Boolean alwaysPrintGeneratedSources, String callerName)
        --- End of stack trace from previous location ---

@ranma42
Copy link
Contributor Author

ranma42 commented Jul 23, 2024

I will need some guidance to reproduce the error locally.
FWIW I am much more confident about the changes to SqlNullabilityProcessor.cs than to those I made to the tests and the seeding 😅

select e.Id).ToList();

var actual = (from e in context.Set<OperatorEntityNullableDateTimeOffset>()
where !((DateTimeOffset?)EF.Functions.AtTimeZone(e.Value.Value, "UTC")).HasValue
Copy link
Contributor Author

@ranma42 ranma42 Jul 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(unrelated to this PR)

this syntax looks convoluted and is fragile when combined with other operations
I was able to invoke EF.Functions.AtTimeZone on a DateTimeOffset? with .Value, but I was unable to convince the compiler that comparing its result to null was reasonable, even after a cast.
Specifically, the compiler rejects:

  • EF.Functions.AtTimeZone(e.Value.Value, "UTC") == null (which looks like the most natural way to perform this check in an expression, but is forbidden because on the C# side the result of AtTimeZone is a non-nullable value type)
  • ((DateTimeOffset?)EF.Functions.AtTimeZone(e.Value.Value, "UTC")) == null

💔

EDIT: mentioned that it is not a problem in the commits (but I would still love to express this more cleanly 😇 )

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use pragma to work around compiler block:

        var actual = (from e in context.Set<OperatorEntityNullableDateTimeOffset>()
#pragma warning disable CS8073 // The result of the expression is always the same since a value of this type is never equal to 'null'
                      where EF.Functions.AtTimeZone(e.Value.Value, "UTC") == null
#pragma warning restore CS8073 // The result of the expression is always the same since a value of this type is never equal to 'null'
                      select e.Id).ToList();

@cincuranet
Copy link
Contributor

I will need some guidance to reproduce the error locally.

Given that it reproduces only on Helix machines and not the rest, makes me believe that it's not going to be easy to reproduce it locally. :(

@cincuranet
Copy link
Contributor

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@cincuranet
Copy link
Contributor

@ranma42 Seems to be OK now. Phew.

Instead of working around the compiler by casting the expression, simply
suppress the compiler warning.

Suggested by @maumar.
@roji roji merged commit b981879 into dotnet:main Jul 26, 2024
7 checks passed
@ranma42 ranma42 deleted the more-nullability branch July 27, 2024 10:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement nullability simplification for COLLATE and AT TIME ZONE
4 participants