Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/11.0.100.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### Fixed

* Preserve type abbreviations (`string`, user-defined aliases) in the refined type of bindings introduced after a `| null` pattern in a `match` expression. ([Issue #19646](https://github.com/dotnet/fsharp/issues/19646), [PR #19745](https://github.com/dotnet/fsharp/pull/19745))
* Fix attributes on return type of unparenthesized tuple methods being silently dropped from IL. ([Issue #462](https://github.com/dotnet/fsharp/issues/462), [PR #19714](https://github.com/dotnet/fsharp/pull/19714))
* Fix internal error FS0073 "Undefined or unsolved type variable" in IlxGen when nested inline SRTP functions with multiple overloads leave unsolved typars in the non-witness codegen path. ([Issue #19709](https://github.com/dotnet/fsharp/issues/19709), [PR #19710](https://github.com/dotnet/fsharp/pull/19710))
* Fix NRE when calling virtual Object methods on value types through inline SRTP functions. ([Issue #8098](https://github.com/dotnet/fsharp/issues/8098), [PR #19511](https://github.com/dotnet/fsharp/pull/19511))
Expand Down
17 changes: 12 additions & 5 deletions src/Compiler/Checking/Expressions/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10969,11 +10969,18 @@ and TcMatchClause cenv inputTy (resultTy: OverallTy) env isFirst tpenv synMatchC

let inputTypeForNextPatterns=
let removeNull t =
// Strip type equations (including abbreviations) and set nullness to non-null.
// For type abbreviations like `type objnull = obj | null`, we need to expand
// the abbreviation and apply non-null to the underlying type.
let stripped = stripTyEqns cenv.g t
replaceNullnessOfTy KnownWithoutNull stripped
// Remove nullness, preserving aliases when possible (#19646):
// `string | null` → `string` (not `System.String`)
// `MyStr | null` → `MyStr`
// Fall back to stripping when nullness is baked into the abbreviation
// RHS, e.g. `type objnull = obj | null` (#18488).
let nonNullOriginal = replaceNullnessOfTy KnownWithoutNull t
match (nullnessOfTy cenv.g nonNullOriginal).TryEvaluate() with
| ValueSome NullnessInfo.WithoutNull ->
nonNullOriginal
| _ ->
let stripped = stripTyEqns cenv.g t
replaceNullnessOfTy KnownWithoutNull stripped
let rec isWild (p:Pattern) =
match p with
| TPat_wild _ -> true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2373,3 +2373,25 @@ let main _ = 0
|> compile
|> run
|> verifyOutputContains [|"-1"|]

// https://github.com/dotnet/fsharp/issues/19646
// After `| null -> … | s -> …`, `s` must keep its type alias, not the BCL type.
[<Theory>]
[<InlineData("", "string", "'string'")>]
[<InlineData("type MyStr = string", "MyStr", "'MyStr'")>]
[<InlineData("open System\ntype MyUri = Uri", "MyUri", "'MyUri'")>]
let ``Issue 19646 - type alias is preserved after null pattern``
(typeDef: string, paramTypeName: string, expectedSubstring: string) =
FSharp $"""module Test

{typeDef}

let test (x: {paramTypeName} | null) : int =
match x with
| null -> 0
| s -> s
"""
|> asLibrary
|> typeCheckWithStrictNullness
|> shouldFail
|> withDiagnosticMessageMatches expectedSubstring
Loading