Skip to content

Commit bacc160

Browse files
authored
Bugfix: Warn when upcast drops nullness via FindUniqueFeasibleSupertype (#18261)
* Warn when upcast drops nullness via FindUniqueFeasibleSupertype * temporary null shutuops before `use` is softened * notes added
1 parent 0263870 commit bacc160

File tree

4 files changed

+28
-5
lines changed

4 files changed

+28
-5
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
@@ -3,6 +3,7 @@
33
* Fix optimizer internal error for records with static fields ([Issue #18165](https://github.com/dotnet/fsharp/issues/18165), [PR #18280](https://github.com/dotnet/fsharp/pull/18280))
44
* Fix internal error when missing measure attribute in an unsolved measure typar. ([Issue #7491](https://github.com/dotnet/fsharp/issues/7491), [PR #18234](https://github.com/dotnet/fsharp/pull/18234)==
55
* Set `Cancellable.token` from async computation ([Issue #18235](https://github.com/dotnet/fsharp/issues/18235), [PR #18238](https://github.com/dotnet/fsharp/pull/18238))
6+
* Fix missing nullness warning when static upcast dropped nullness ([Issue #18232](https://github.com/dotnet/fsharp/issues/18232), [PR #18261](https://github.com/dotnet/fsharp/pull/18261))
67
* Cancellable: only cancel on OCE with own token ([PR #18277](https://github.com/dotnet/fsharp/pull/18277))
78
* Cancellable: set token in more places ([PR #18283](https://github.com/dotnet/fsharp/pull/18283))
89

src/Compiler/Checking/TypeRelations.fs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,5 +341,13 @@ let IteratedAdjustLambdaToMatchValReprInfo g amap valReprInfo lambdaExpr =
341341
/// "Single Feasible Type" inference
342342
/// Look for the unique supertype of ty2 for which ty2 :> ty1 might feasibly hold
343343
let FindUniqueFeasibleSupertype g amap m ty1 ty2 =
344-
let supertypes = Option.toList (GetSuperTypeOfType g amap m ty2) @ (GetImmediateInterfacesOfType SkipUnrefInterfaces.Yes g amap m ty2)
345-
supertypes |> List.tryFind (TypeFeasiblySubsumesType 0 g amap m ty1 NoCoerce)
344+
let n2 = nullnessOfTy g ty2
345+
let nullify t = addNullnessToTy n2 t
346+
347+
let supertypes =
348+
Option.toList (GetSuperTypeOfType g amap m ty2) @
349+
(GetImmediateInterfacesOfType SkipUnrefInterfaces.Yes g amap m ty2)
350+
351+
supertypes
352+
|> List.tryFind (TypeFeasiblySubsumesType 0 g amap m ty1 NoCoerce)
353+
|> Option.map nullify

src/Compiler/Utilities/Activity.fs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,14 @@ module internal Activity =
9393
let activity = activitySource.CreateActivity(name, ActivityKind.Internal)
9494

9595
match activity with
96-
| null -> activity
96+
| null -> !!activity //TODO change retTy to |null after PR #18262 is merged!!
9797
| activity ->
9898
for key, value in tags do
9999
activity.AddTag(key, value) |> ignore
100100

101101
activity.Start()
102102

103-
let startNoTags (name: string) : IDisposable = activitySource.StartActivity name
103+
let startNoTags (name: string) : IDisposable = !! (activitySource.StartActivity name) //TODO change retTy to |null after PR #18262 is merged!!
104104

105105
let addEvent name =
106106
match Activity.Current with
@@ -122,7 +122,7 @@ module internal Activity =
122122

123123
let private profiledSource = new ActivitySource(ActivityNames.ProfiledSourceName)
124124

125-
let startAndMeasureEnvironmentStats (name: string) : IDisposable = profiledSource.StartActivity(name)
125+
let startAndMeasureEnvironmentStats (name: string) : IDisposable = !!(profiledSource.StartActivity(name)) //TODO change retTy to |null after PR #18262 is merged!!
126126

127127
type private GCStats = int[]
128128

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

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

20+
[<Fact>]
21+
let ``Warning on nullness hidden behind interface upcast`` () =
22+
FSharp """module Test
23+
24+
open System.IO
25+
open System
26+
27+
// This is bad - input is nullable, output is not = must warn
28+
let whatisThis (s:Stream|null) : IDisposable =
29+
s"""
30+
|> asLibrary
31+
|> typeCheckWithStrictNullness
32+
|> shouldFail
33+
|> withDiagnostics [Error 3261, Line 8, Col 5, Line 8, Col 6, "Nullness warning: The types 'IDisposable' and 'IDisposable | null' do not have compatible nullability."]
2034

2135
[<FSharp.Test.FactForNETCOREAPPAttribute>]
2236
let ``Report warning when applying anon record to a nullable generic return value`` () =

0 commit comments

Comments
 (0)