From 9961e4508a005771b2a10126498acd40ae8c39d3 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 12 Sep 2024 14:55:58 +0200 Subject: [PATCH 1/3] repro added --- .../Nullness/NullableCsharpImportTests.fs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableCsharpImportTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableCsharpImportTests.fs index 24ff5798cbd..a40dc249276 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableCsharpImportTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableCsharpImportTests.fs @@ -225,4 +225,39 @@ let ``Consumption of nullable C# - no generics, just strings in methods and fiel Error 3261, Line 25, Col 85, Line 25, Col 97, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability." Error 3261, Line 28, Col 99, Line 28, Col 111, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability." Error 3261, Line 30, Col 97, Line 30, Col 109, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability."] + + +[] +let ``Regression 17701 - Nullable value type with nested generics`` () = + let csharpLib = + CSharp """ +using System; +using System.Collections.Immutable; + +namespace Nullables; +public class NullableClass { + public static ImmutableArray? nullableImmArrayOfStrings; +}""" |> withName "csNullableLib" + |> withCSharpLanguageVersionPreview + + FSharp """module FSNullable +open Nullables + +let nullablestrNoParams = NullableClass.nullableImmArrayOfStrings +let toOption = NullableClass.nullableImmArrayOfStrings |> Option.ofNullable +let lengthOfFirstString = (NullableClass.nullableImmArrayOfStrings.Value |> Seq.head).Length + """ + |> asLibrary + |> withReferences [csharpLib] + |> withStrictNullness + |> compile + |> shouldFail + |> withDiagnostics [ + Error 3261, Line 5, Col 40, Line 5, Col 85, "Nullness warning: The types 'string' and 'string | null' do not have compatible nullability." + Error 3261, Line 5, Col 40, Line 5, Col 85, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability." + Error 3261, Line 14, Col 34, Line 14, Col 62, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability." + Error 3261, Line 16, Col 35, Line 16, Col 39, "Nullness warning: The type 'string' does not support 'null'." + Error 3261, Line 25, Col 85, Line 25, Col 97, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability." + Error 3261, Line 28, Col 99, Line 28, Col 111, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability." + Error 3261, Line 30, Col 97, Line 30, Col 109, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability."] From b0f22e2238abcca2fcce18a2a6207473513e63a9 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Sun, 15 Sep 2024 13:03:19 +0200 Subject: [PATCH 2/3] Bugfix processing System.Nullable with nested generic nullness --- src/Compiler/Checking/import.fs | 8 ++++++- .../Nullness/NullableCsharpImportTests.fs | 22 +++++++++---------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/Compiler/Checking/import.fs b/src/Compiler/Checking/import.fs index 0f800e7bbd6..68e3512864b 100644 --- a/src/Compiler/Checking/import.fs +++ b/src/Compiler/Checking/import.fs @@ -273,12 +273,18 @@ For value types, a value is passed even though it is always 0 member this.Advance() = {Data = this.Data; Idx = this.Idx + 1} + let inline isSystemNullable (tspec:ILTypeSpec) = + match tspec.Name,tspec.Enclosing with + | "Nullable`1",["System"] -> true + | "System.Nullable`1",[] -> true + | _ -> false + let inline evaluateFirstOrderNullnessAndAdvance (ilt:ILType) (flags:NullableFlags) = match ilt with | ILType.Value tspec when tspec.GenericArgs.IsEmpty -> KnownWithoutNull, flags // System.Nullable is special-cased in C# spec for nullness metadata. // You CAN assign 'null' to it, and when boxed, it CAN be boxed to 'null'. - | ILType.Value tspec when tspec.Name = "Nullable`1" && tspec.Enclosing = ["System"] -> KnownWithoutNull, flags + | ILType.Value tspec when isSystemNullable tspec -> KnownWithoutNull, flags | ILType.Value _ -> KnownWithoutNull, flags.Advance() | _ -> flags.GetNullness(), flags.Advance() diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableCsharpImportTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableCsharpImportTests.fs index a40dc249276..5a4f3dedf10 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableCsharpImportTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableCsharpImportTests.fs @@ -233,10 +233,11 @@ let ``Regression 17701 - Nullable value type with nested generics`` () = CSharp """ using System; using System.Collections.Immutable; - +#nullable enable namespace Nullables; public class NullableClass { - public static ImmutableArray? nullableImmArrayOfStrings; + public static ImmutableArray? nullableImmArrayOfStrings; + public static ImmutableArray? nullableImmArrayOfNotNullStrings; }""" |> withName "csNullableLib" |> withCSharpLanguageVersionPreview @@ -245,19 +246,18 @@ open Nullables let nullablestrNoParams = NullableClass.nullableImmArrayOfStrings let toOption = NullableClass.nullableImmArrayOfStrings |> Option.ofNullable -let lengthOfFirstString = (NullableClass.nullableImmArrayOfStrings.Value |> Seq.head).Length +let firstString = (toOption.Value |> Seq.head) +let lengthOfIt = firstString.Length + +let theOtherOne = NullableClass.nullableImmArrayOfNotNullStrings """ |> asLibrary |> withReferences [csharpLib] |> withStrictNullness + |> withLangVersionPreview |> compile |> shouldFail - |> withDiagnostics [ - Error 3261, Line 5, Col 40, Line 5, Col 85, "Nullness warning: The types 'string' and 'string | null' do not have compatible nullability." - Error 3261, Line 5, Col 40, Line 5, Col 85, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability." - Error 3261, Line 14, Col 34, Line 14, Col 62, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability." - Error 3261, Line 16, Col 35, Line 16, Col 39, "Nullness warning: The type 'string' does not support 'null'." - Error 3261, Line 25, Col 85, Line 25, Col 97, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability." - Error 3261, Line 28, Col 99, Line 28, Col 111, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability." - Error 3261, Line 30, Col 97, Line 30, Col 109, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability."] + |> withDiagnostics + [Error 3261, Line 7, Col 18, Line 7, Col 36, "Nullness warning: The types 'string' and 'string | null' do not have compatible nullability."] + From 6b2805ea3ae5bf9838ef3aebf5c76fbb515adc37 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Sun, 15 Sep 2024 13:07:06 +0200 Subject: [PATCH 3/3] Update 9.0.100.md --- docs/release-notes/.FSharp.Compiler.Service/9.0.100.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md index 24ce8c5a07b..ce498130115 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md @@ -18,6 +18,7 @@ * Fix IsUnionCaseTester throwing for non-methods/properties [#17301](https://github.com/dotnet/fsharp/pull/17634) * Consider `open type` used when the type is an enum and any of the enum cases is used unqualified. ([PR #17628](https://github.com/dotnet/fsharp/pull/17628)) * Guard for possible StackOverflowException when typechecking non recursive modules and namespaces ([PR #17654](https://github.com/dotnet/fsharp/pull/17654)) +* Nullable - fix for processing System.Nullable types with nesting ([PR #17736](https://github.com/dotnet/fsharp/pull/17736)) ### Added