From 04df30e924ddb4b23c9c512d755f07e51691c1d3 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Thu, 18 Jun 2026 16:31:27 +0200 Subject: [PATCH 1/2] Checker: recover on checking language version --- src/Compiler/Checking/CheckDeclarations.fs | 2 +- src/Compiler/Checking/CheckFormatStrings.fs | 2 +- src/Compiler/Checking/CheckPatterns.fs | 2 +- .../Checking/Expressions/CheckExpressions.fs | 14 +++++++------- ...rnTypeDirectedPartialActivePatternTests.fs | 19 +++++++++++++++++++ 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index aa8eb266d07..17fc8c30715 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -751,7 +751,7 @@ let TcOpenModuleOrNamespaceDecl tcSink g amap scopem env (longId, m) = let TcOpenTypeDecl (cenv: cenv) mOpenDecl scopem env (synType: SynType, m) = let g = cenv.g - checkLanguageFeatureError g.langVersion LanguageFeature.OpenTypeDeclaration mOpenDecl + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.OpenTypeDeclaration mOpenDecl let ty, _tpenv = TcType cenv NoNewTypars CheckCxs ItemOccurrence.Open WarnOnIWSAM.Yes env emptyUnscopedTyparEnv synType diff --git a/src/Compiler/Checking/CheckFormatStrings.fs b/src/Compiler/Checking/CheckFormatStrings.fs index 2021888970f..70608224578 100644 --- a/src/Compiler/Checking/CheckFormatStrings.fs +++ b/src/Compiler/Checking/CheckFormatStrings.fs @@ -396,7 +396,7 @@ let parseFormatStringInternal let ch = fmt[i] match ch with | 'd' | 'i' | 'u' | 'B' | 'o' | 'x' | 'X' -> - if ch = 'B' then checkLanguageFeatureError g.langVersion Features.LanguageFeature.PrintfBinaryFormat m + if ch = 'B' then checkLanguageFeatureAndRecover g.langVersion Features.LanguageFeature.PrintfBinaryFormat m if info.precision then failwith (FSComp.SR.forFormatDoesntSupportPrecision(ch.ToString())) collectSpecifierLocation fragLine fragCol 1 let i = skipPossibleInterpolationHole (i+1) diff --git a/src/Compiler/Checking/CheckPatterns.fs b/src/Compiler/Checking/CheckPatterns.fs index e6d0e5c7dce..23f210fb7a0 100644 --- a/src/Compiler/Checking/CheckPatterns.fs +++ b/src/Compiler/Checking/CheckPatterns.fs @@ -286,7 +286,7 @@ and TcPat warnOnUpper (cenv: cenv) env valReprInfo vFlags (patEnv: TcPatLinearEn match synPat with | SynPat.As (_, SynPat.Named _, _) -> () - | SynPat.As (_, _, m) -> checkLanguageFeatureError g.langVersion LanguageFeature.NonVariablePatternsToRightOfAsPatterns m + | SynPat.As (_, _, m) -> checkLanguageFeatureAndRecover g.langVersion LanguageFeature.NonVariablePatternsToRightOfAsPatterns m | _ -> () match synPat with diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 070ce6b3e8e..7a56457c581 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -5391,7 +5391,7 @@ and TcPatLongIdentActivePatternCase warnOnUpper (cenv: cenv) (env: TcEnv) vFlags // partial active pattern (returning bool) doesn't have output arg if (not apinfo.IsTotal && isBoolTy g retTy) then - checkLanguageFeatureError g.langVersion LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern m + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern m if paramCount = List.length args then args, SynPat.Const(SynConst.Unit, m) else @@ -5946,7 +5946,7 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE | SynExpr.InterpolatedString (parts, _, m) -> TcNonControlFlowExpr env <| fun env -> - checkLanguageFeatureError g.langVersion LanguageFeature.StringInterpolation m + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.StringInterpolation m CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) TcInterpolatedStringExpr cenv overallTy env m tpenv parts @@ -11438,11 +11438,11 @@ and TcNormalizedBinding declKind (cenv: cenv) env tpenv overallTy safeThisValOpt match apRetTy with | ActivePatternReturnKind.Boolean -> - checkLanguageFeatureError g.langVersion LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern mBinding + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern mBinding | ActivePatternReturnKind.StructTypeWrapper when not isStructRetTy -> - checkLanguageFeatureError g.langVersion LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern mBinding + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern mBinding | ActivePatternReturnKind.StructTypeWrapper -> - checkLanguageFeatureError g.langVersion LanguageFeature.StructActivePattern mBinding + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.StructActivePattern mBinding | ActivePatternReturnKind.RefTypeWrapper -> () UnifyTypes cenv env mBinding (apinfo.ResultType g m activePatResTys apRetTy) apReturnTy @@ -11933,7 +11933,7 @@ and TcLetBinding (cenv: cenv) isUse env containerInfo declKind tpenv (synBinds, if not isDiscarded then errorR(Error(FSComp.SR.tcInvalidUseBinding(), m)) else - checkLanguageFeatureError g.langVersion LanguageFeature.UseBindingValueDiscard checkedPat.Range + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.UseBindingValueDiscard checkedPat.Range elif isFixed then errorR(Error(FSComp.SR.tcInvalidUseBinding(), m)) @@ -12287,7 +12287,7 @@ and CheckForNonAbstractInterface (g: TcGlobals) declKind tcref (memberFlags: Syn if not isMemberStatic then error(Error(FSComp.SR.tcConcreteMembersIllegalInInterface(), m)) else - checkLanguageFeatureError g.langVersion LanguageFeature.StaticMembersInInterfaces m + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.StaticMembersInInterfaces m //------------------------------------------------------------------------- // TcLetrecBindings - AnalyzeAndMakeAndPublishRecursiveValue s diff --git a/tests/FSharp.Compiler.ComponentTests/Language/BooleanReturningAndReturnTypeDirectedPartialActivePatternTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/BooleanReturningAndReturnTypeDirectedPartialActivePatternTests.fs index 382d3395abe..9a0a51a6eb2 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/BooleanReturningAndReturnTypeDirectedPartialActivePatternTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/BooleanReturningAndReturnTypeDirectedPartialActivePatternTests.fs @@ -100,3 +100,22 @@ match "A" with Result") (Error 3868, Line 13, Col 3, Line 13, Col 30, "This active pattern does not expect any arguments, i.e., it should be used like 'IsA' instead of 'IsA x'.") ] + +[] +let ``Language version check`` () = + FSharp """ +let (|LessThan|_|) (other: int) x = x <= other + +match 1 with +| LessThan "" -> UnresolvedName +| _ -> () +""" + |> withLangVersion80 + |> typecheck + |> shouldFail + |> withDiagnostics [ + Error 3350, Line 2, Col 6, Line 2, Col 18, "Feature 'Boolean-returning and return-type-directed partial active patterns' is not available in F# 8.0. Please use language version 9.0 or greater." + Error 3350, Line 5, Col 3, Line 5, Col 14, "Feature 'Boolean-returning and return-type-directed partial active patterns' is not available in F# 8.0. Please use language version 9.0 or greater." + Error 1, Line 5, Col 12, Line 5, Col 14, "This expression was expected to have type\n 'int' \n but here has type\n 'string' " + Error 39, Line 5, Col 18, Line 5, Col 32, "The value or constructor 'UnresolvedName' is not defined." + ] \ No newline at end of file From 28375095c24b5a262783089a52372cd7bdd88385 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Thu, 18 Jun 2026 19:34:58 +0200 Subject: [PATCH 2/2] Release notes --- docs/release-notes/.FSharp.Compiler.Service/11.0.100.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index 5d4bd0fe6ac..254296db8a0 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -95,6 +95,7 @@ * Debug: rework for expressions stepping ([PR #19894](https://github.com/dotnet/fsharp/pull/19894)) * Debug: rework conditional erasure, fix stepping over literals ([PR #19897](https://github.com/dotnet/fsharp/pull/19897)) * Debug: fix if and match condition sequence points ([PR #19932](https://github.com/dotnet/fsharp/pull/19932)) +* Checker: recover on checking language version ([PR ##19970](https://github.com/dotnet/fsharp/pull/19970)) ### Changed