Skip to content

Commit 27db996

Browse files
authored
Bugfix for breaking change when using Option.ofObj :: Type parameter constraint null implies not struct (#18323)
1 parent f939050 commit 27db996

File tree

5 files changed

+16
-0
lines changed

5 files changed

+16
-0
lines changed

docs/release-notes/.FSharp.Compiler.Service/9.0.300.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* Add support for C# `Experimental` attribute. ([PR #18253](https://github.com/dotnet/fsharp/pull/18253))
1919
* Nullness warnings are issued for signature<>implementation conformance ([PR #18186](https://github.com/dotnet/fsharp/pull/18186))
2020
* Symbols: Add FSharpAssembly.IsFSharp ([PR #18290](https://github.com/dotnet/fsharp/pull/18290))
21+
* Type parameter constraint `null` in generic code will now automatically imply `not struct` ([Issue #18320](https://github.com/dotnet/fsharp/issues/18320), [PR #18323](https://github.com/dotnet/fsharp/pull/18323))
2122

2223
### Changed
2324

src/Compiler/Checking/ConstraintSolver.fs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2478,6 +2478,8 @@ and CheckConstraintImplication (csenv: ConstraintSolverEnv) tpc1 tpc2 =
24782478
| TyparConstraint.SupportsEquality _, TyparConstraint.SupportsEquality _
24792479
// comparison implies equality
24802480
| TyparConstraint.SupportsComparison _, TyparConstraint.SupportsEquality _
2481+
// 'null' implies reference type ('not struct')
2482+
| TyparConstraint.SupportsNull _, TyparConstraint.IsReferenceType _
24812483
| TyparConstraint.SupportsNull _, TyparConstraint.SupportsNull _
24822484
| TyparConstraint.NotSupportsNull _, TyparConstraint.NotSupportsNull _
24832485
| TyparConstraint.IsNonNullableStruct _, TyparConstraint.IsNonNullableStruct _

src/Compiler/CodeGen/IlxGen.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5679,6 +5679,7 @@ and GenGenericParam cenv eenv (tp: Typar) =
56795679
tp.Constraints
56805680
|> List.exists (function
56815681
| TyparConstraint.IsReferenceType _
5682+
// 'null' automatically implies 'not struct'
56825683
| TyparConstraint.SupportsNull _ -> true
56835684
| _ -> false)
56845685

tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/SupportsNull.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ let iAcceptNullWithNullAnnotation(arg: 'a | null when 'a: not struct) =
2626
else
2727
0
2828

29+
// This test case emits the `class T` constraint in IL
2930
let iAcceptNullExplicitAnnotation(arg: 'T when 'T:null) =
3031
if isNull arg then
3132
1

tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ let typeCheckWithStrictNullness cu =
1717
|> withNullnessOptions
1818
|> typecheck
1919

20+
21+
[<Fact>]
22+
let ``Can imply notstruct for classconstraint`` () =
23+
FSharp """module Foo =
24+
let failIfNull<'a when 'a : null> (a : 'a) : 'a option =
25+
(a |> Option.ofObj)
26+
"""
27+
|> asLibrary
28+
|> typecheck // This has nullable off!
29+
|> shouldSucceed
30+
2031
[<Fact>]
2132
let ``Warning on nullness hidden behind interface upcast`` () =
2233
FSharp """module Test

0 commit comments

Comments
 (0)