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 d8658f4ce49..a9ef9b621af 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md @@ -18,8 +18,10 @@ * 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)) * Fixes for the optimization of simple mappings in array and list comprehensions. ([Issue #17708](https://github.com/dotnet/fsharp/issues/17708), [PR #17711](https://github.com/dotnet/fsharp/pull/17711)) + ### Added * Support for nullable reference types ([PR #15181](https://github.com/dotnet/fsharp/pull/15181)) 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 24ff5798cbd..5a4f3dedf10 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; +#nullable enable +namespace Nullables; +public class NullableClass { + public static ImmutableArray? nullableImmArrayOfStrings; + public static ImmutableArray? nullableImmArrayOfNotNullStrings; +}""" |> withName "csNullableLib" + |> withCSharpLanguageVersionPreview + + FSharp """module FSNullable +open Nullables + +let nullablestrNoParams = NullableClass.nullableImmArrayOfStrings +let toOption = NullableClass.nullableImmArrayOfStrings |> Option.ofNullable +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 7, Col 18, Line 7, Col 36, "Nullness warning: The types 'string' and 'string | null' do not have compatible nullability."] +