From 14f2da9597199a45155c28806079c781e81c05a2 Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Fri, 30 May 2025 18:01:44 -0400 Subject: [PATCH 1/3] Add test for active pattern w/fun ty w/unsolved range typar --- .../ActivePatternArgCountMismatchTest.fs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ActivePatternArgCountMismatchTest.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ActivePatternArgCountMismatchTest.fs index 8c2133721d2..09de043f4fd 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ActivePatternArgCountMismatchTest.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ActivePatternArgCountMismatchTest.fs @@ -761,6 +761,26 @@ match 1 with P expr2 pat -> () |> typecheck |> shouldSucceed + module ``Recursive active pattern definition with and`` = + /// See https://github.com/dotnet/fsharp/issues/18638 + [] + let ``match expr1 with P expr2 pat -> …`` () = + FSharp """ +let rec parse p = + function + | IsSomething p v -> Some v + | _ -> None + +and (|IsSomething|_|) p = + function + | "nested" -> parse p "42" + | "42" -> Some 42 + | _ -> None + """ + |> withNoWarn IncompletePatternMatches + |> typecheck + |> shouldSucceed + module ``int → int → int voption`` = // Normal usage; pat is int. [] From 64a7d1084dd87d5d8ae0755b26b8015695352400 Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Fri, 30 May 2025 18:03:00 -0400 Subject: [PATCH 2/3] Treat `(|P|) : 'a -> 'b` similarly to `(|P|) : 'a` That is, for an active pattern whose type is known to be a function type but whose range type is not yet solved, assume that it _could_ be solved to, e.g., another function type. This can show up in, e.g., an active pattern that is defined mutually-recursively with `and`, has no type annotations, and returns a lambda with `fun` or `function`. --- src/Compiler/Checking/Expressions/CheckExpressions.fs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 4ce2fb1700b..e1410e8c595 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -5259,6 +5259,8 @@ and TcPatLongIdentActivePatternCase warnOnUpper (cenv: cenv) (env: TcEnv) vFlags | _, _ -> FSComp.SR.tcActivePatternArgsCountNotMatchArgsAndPat(paramCount, caseName, fmtExprArgs paramCount) error(Error(msg, m)) + let isUnsolvedTyparTy g ty = tryDestTyparTy g ty |> ValueOption.exists (fun typar -> not typar.IsSolved) + // partial active pattern (returning bool) doesn't have output arg if (not apinfo.IsTotal && isBoolTy g retTy) then checkLanguageFeatureError g.langVersion LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern m @@ -5281,7 +5283,8 @@ and TcPatLongIdentActivePatternCase warnOnUpper (cenv: cenv) (env: TcEnv) vFlags showErrMsg 1 // active pattern in function param (e.g. let f (|P|_|) = ...) - elif tryDestTyparTy g vExprTy |> ValueOption.exists (fun typar -> not typar.IsSolved) then + // or in mutual recursion with a lambda: `and (|P|) x = fun y -> …` + elif isUnsolvedTyparTy g vExprTy || tryDestFunTy g vExprTy |> ValueOption.exists (fun (_, rangeTy) -> isUnsolvedTyparTy g rangeTy) then List.frontAndBack args // args count should equal to AP function params count From 3b4b7395ff9b451d7400e1b7152a42828dce6662 Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Fri, 30 May 2025 18:20:22 -0400 Subject: [PATCH 3/3] Update release notes --- docs/release-notes/.FSharp.Compiler.Service/10.0.100.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md index a3949c5b823..3f356fcc03a 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md @@ -11,6 +11,7 @@ * Fix find all references for F# exceptions ([PR #18565](https://github.com/dotnet/fsharp/pull/18565)) * Shorthand lambda: fix completion for chained calls and analysis for unfinished expression ([PR #18560](https://github.com/dotnet/fsharp/pull/18560)) * Completion: fix previous namespace considered opened [PR #18609](https://github.com/dotnet/fsharp/pull/18609) +* Fix active pattern typechecking regression. ([Issue #18638](https://github.com/dotnet/fsharp/issues/18638), [PR #18642](https://github.com/dotnet/fsharp/pull/18642)) ### Added