diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs index 3de8d80d947..0000b06f571 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs @@ -2037,3 +2037,42 @@ if r <> 1 then failwith $"Expected 1 but got {r}" |> asExe |> compileAndRun |> shouldSucceed + + // The domain-order fix keeps the SRTP typar as the unification representative, so a nullable + // argument annotation survives the recursive specialization and nullness inference stays intact + // under --checknulls+ (no lost or spurious warning, no internal error). + [] + let ``Recursive inline SRTP memoization preserves nullable argument inference under checknulls`` () = + FSharp """ +module Test +open System.Collections.Concurrent + +type Default1 = class end + +[] +type MemoizationKeyWrapper<'a> = MemoizationKeyWrapper of 'a + +type MemoizeN = + inherit Default1 + static member getOrAdd (cd: ConcurrentDictionary,'b>) (f: 'a -> 'b) k = + cd.GetOrAdd (MemoizationKeyWrapper k, (fun (MemoizationKeyWrapper x) -> x) >> f) + +let inline memoizeN (f: ^F) : ^F = + let inline call_2 (a: ^MemoizeN, b: ^b) = ((^MemoizeN or ^b) : (static member MemoizeN : ^MemoizeN * 'b -> _ ) (a, b)) + call_2 (Unchecked.defaultof, Unchecked.defaultof< ^F >) f + +type MemoizeN with + static member MemoizeN (_: Default1, _: 'a -> 'b) = MemoizeN.getOrAdd (ConcurrentDictionary ()) + static member inline MemoizeN (_: MemoizeN, _:'t -> 'a -> 'b) = MemoizeN.getOrAdd (ConcurrentDictionary ()) << (<<) memoizeN + +let lookup (prefix: int) (index: int) (s: string | null) = s.Length + prefix + index +let mlookup = memoizeN lookup +mlookup 1 2 "abc" |> ignore +""" + |> withLangVersion "preview" + |> withCheckNulls + |> withWarnOn 3261 + |> compile + |> withDiagnostics [ + Warning 3261, Line 23, Col 60, Line 23, Col 61, "Nullness warning: Possible dereference of a null value when accessing member 'Length' on the nullable value 's' of type 'string | null'." + ]