Skip to content

Commit

Permalink
Bugfix :: Nullness :: Unsafe cast no longer requires generic type to …
Browse files Browse the repository at this point in the history
…be `not null` typar (#18343)
  • Loading branch information
T-Gro authored Feb 28, 2025
1 parent c281bd0 commit 32c2764
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 7 deletions.
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/9.0.300.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* Cancellable: fix leaking cancellation token ([PR #18295](https://github.com/dotnet/fsharp/pull/18295))
* Fix NRE when accessing nullable fields of types within their equals/hash/compare methods ([PR #18296](https://github.com/dotnet/fsharp/pull/18296))
* Fix nullness warning for overrides of generic code with nullable type instance ([Issue #17988](https://github.com/dotnet/fsharp/issues/17988), [PR #18337](https://github.com/dotnet/fsharp/pull/18337))
* Unsafe downcast from `obj` to generic `T` no longer requires `not null` constraint on `T`([Issue #18275](https://github.com/dotnet/fsharp/issues/18275), [PR #18343](https://github.com/dotnet/fsharp/pull/18343))

### Added
* Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241))
Expand Down
8 changes: 3 additions & 5 deletions src/Compiler/Checking/Expressions/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2976,11 +2976,9 @@ let TcRuntimeTypeTest isCast isOperator (cenv: cenv) denv m tgtTy srcTy =
if isSealedTy g srcTy then
error(RuntimeCoercionSourceSealed(denv, srcTy, m))

if isSealedTy g tgtTy || isTyparTy g tgtTy || not (isInterfaceTy g srcTy) then
if isCast then
AddCxTypeMustSubsumeType (ContextInfo.RuntimeTypeTest isOperator) denv cenv.css m NoTrace srcTy tgtTy
else
AddCxTypeMustSubsumeType ContextInfo.NoContext denv cenv.css m NoTrace srcTy tgtTy
if (isSealedTy g tgtTy || isTyparTy g tgtTy || not (isInterfaceTy g srcTy)) && not (isObjTyAnyNullness g srcTy) then
let context = if isCast then ContextInfo.RuntimeTypeTest isOperator else ContextInfo.NoContext
AddCxTypeMustSubsumeType context denv cenv.css m NoTrace srcTy tgtTy

if isErasedType g tgtTy then
if isCast then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,8 @@ let doNotWarnOnDowncastRepeatedNestedNullable(o:objnull) = o :? list<((AB | null
|> shouldFail
|> withDiagnostics
[ Error 3264, Line 4, Col 39, Line 4, Col 47, "Nullness warning: Downcasting from 'objnull' into 'AB' can introduce unexpected null values. Cast to 'AB|null' instead or handle the null before downcasting."
Error 3261, Line 5, Col 42, Line 5, Col 59, "Nullness warning: The types 'obj' and 'AB | null' do not have compatible nullability."
Error 3060, Line 5, Col 42, Line 5, Col 59, "This type test or downcast will erase the provided type 'AB | null' to the type 'AB'"
Error 3060, Line 6, Col 41, Line 6, Col 55, "This type test or downcast will erase the provided type 'AB | null' to the type 'AB'"
Error 3261, Line 7, Col 51, Line 7, Col 97, "Nullness warning: The types 'obj' and 'AB | null array | null list | null' do not have compatible nullability."
Error 3060, Line 7, Col 51, Line 7, Col 97, "This type test or downcast will erase the provided type 'List<AB | null array | null> | null' to the type 'List<AB array>'"]


Expand Down Expand Up @@ -1381,6 +1379,20 @@ dict["ok"] <- 42
|> typeCheckWithStrictNullness
|> shouldSucceed

[<InlineData("t :?> 'T")>]
[<InlineData("(downcast t) : 'T")>]
[<InlineData("t |> unbox<'T>")>]
[<InlineData("(t : objnull) :?> 'T")>]
[<Theory>]
let ``Unsafe cast should not insist on not null constraint``(castOp:string) =

FSharp $"""module MyLibrary
let test<'T> () =
let t = obj()
{castOp}"""
|> asLibrary
|> typeCheckWithStrictNullness
|> shouldSucceed


[<InlineData("null")>]
Expand Down

0 comments on commit 32c2764

Please sign in to comment.