diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index 1c78cff8fe9..491273fa561 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -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)) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index ee465013b6b..e873ba12f17 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -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 diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs index bb95ba7a6a1..ced7e02fdca 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs @@ -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 | null' to the type 'List'"] @@ -1381,6 +1379,20 @@ dict["ok"] <- 42 |> typeCheckWithStrictNullness |> shouldSucceed +[ 'T")>] +[] +[ unbox<'T>")>] +[ 'T")>] +[] +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 []