Nullness issue - `match` control flow for reference types
Issue description
let bar =
let getEnvironmentVariable : string -> _ = failwith ""
match "ENVVAR" |> getEnvironmentVariable with
| null ->
failwith ""
| x ->
x // inferred incorrectly as `obj | null` rather than `obj`
We've just pattern-matched, so it's locally provable that x is not null.
It's not explicitly stated in the RFC that this flow analysis is banned - the examples all use the new active pattern Null - but it's a big annoyance; I don't think it's possible for me to write polyglot F#-with-nullability and F#-before-v9 without this feature and without using unsafe casts? Is there a way to inject System.GetEnvironmentVariable as an argument to a function, while also satisfying the nullability checker, without breaking backward-compatibility and without calling unbox<string> (s : string | null) or similar?
My context is that I'm writing a source generator, so I must produce source which is compatible with any F# version (or else duplicate large amounts of code by providing two different generators). (https://github.com/Smaug123/WoofWare.Myriad/issues/364)
Choose one or more from the following categories of impact
- [x] Unexpected nullness warning (false positive in nullness checking, code uses --checknulls and langversion:preview).
- [ ] Missing nullness warning in a case which can produce nulls (false negative, code uses --checknulls and langversion:preview).
- [ ] Breaking change related to older
nullconstructs in code not using the checknulls switch. - [ ] Breaking change related to generic code and explicit type constraints (
null,not null). - [ ] Type inference issue (i.e. code worked without type annotations before, and applying the --checknulls enforces type annotations).
- [ ] C#/F# interop issue related to nullness metadata.
- [ ] Other (none of the categories above apply).
Operating System
macOS
What .NET runtime/SDK kind are you seeing the issue on
.NET SDK (.NET Core, .NET 5+)
.NET Runtime/SDK version
9.0.203
Reproducible code snippet and actual behavior
No response
Possible workarounds
Use |> unbox<string>.
Just specify _?
Sorry, I don't understand where. Is there a way to get x of type obj, and not obj or null?
I just tested it on latest preview.
Without having any further clue, the code is fully generic with 'a having the null constraint.
As soon as type is inferred from elsewhere or specified (e.g. by replacing _ with objnull or by replacing the pattern matched null to (null:objnull)), I am getting correct flow-analyzed elimination of null and x becomes System.Object.
If I use the real System.Environment.GetEnvironmentVariable, x also becomes full String instead of string|null after the null handling case.