Skip to content

Parser: recover on unfinished isConst patterns #17232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Sep 4, 2024
Merged
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/9.0.100.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
* Allow object expression without overrides. ([Language suggestion #632](https://github.com/fsharp/fslang-suggestions/issues/632), [PR #17387](https://github.com/dotnet/fsharp/pull/17387))
* Enable FSharp 9.0 Language Version ([Issue #17497](https://github.com/dotnet/fsharp/issues/17438)), [PR](https://github.com/dotnet/fsharp/pull/17500)))
* Enable LanguageFeature.EnforceAttributeTargets in F# 9.0. ([Issue #17514](https://github.com/dotnet/fsharp/issues/17558), [PR #17516](https://github.com/dotnet/fsharp/pull/17558))
* Parser: better recovery for unfinished patterns ([PR #17231](https://github.com/dotnet/fsharp/pull/17231), [PR #17232](https://github.com/dotnet/fsharp/pull/17232)))
* Enable consuming generic arguments defined as `allows ref struct` in C# ([Issue #17597](https://github.com/dotnet/fsharp/issues/17597)

### Changed
Expand Down
23 changes: 21 additions & 2 deletions src/Compiler/pars.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ let parse_error_rich = Some(fun (ctxt: ParseErrorContext<_>) ->
%type <SynPat> headBindingPattern
%type <SynType> appTypeNullableInParens
%type <SynType> atomTypeNonAtomicDeprecated
%type <SynType> atomTypeOrAnonRecdType
%type <SynExpr> atomicExprAfterType
%type <SynExpr> typedSequentialExprBlock
%type <SynExpr * bool> atomicExpr
Expand Down Expand Up @@ -3550,7 +3551,7 @@ headBindingPattern:
{ let mColonColon = rhs parseState 2
SynPat.ListCons($1, $3, rhs2 parseState 1 3, { ColonColonRange = mColonColon }) }

| headBindingPattern COLON_COLON recover
| headBindingPattern COLON_COLON ends_coming_soon_or_recover
{ let mColonColon = rhs parseState 2
let pat2 = SynPat.Wild(mColonColon.EndRange)
SynPat.ListCons($1, pat2, rhs2 parseState 1 2, { ColonColonRange = mColonColon }) }
Expand Down Expand Up @@ -3679,7 +3680,21 @@ constrPattern:
SynPat.LongIdent(lid, None, None, args, vis, m) }

| COLON_QMARK atomTypeOrAnonRecdType %prec pat_isinst
{ SynPat.IsInst($2, lhs parseState) }
{ let m = unionRanges (rhs parseState 1) $2.Range
SynPat.IsInst($2, m) }

| COLON_QMARK recover %prec pat_isinst
{ let mColon = rhs parseState 1
if not $2 then
reportParseErrorAt mColon (FSComp.SR.parsExpectingPattern ())
let ty = SynType.FromParseError(mColon.EndRange)
SynPat.IsInst(ty, mColon) }

| COLON_QMARK %prec pat_isinst
{ let mColon = rhs parseState 1
let ty = SynType.FromParseError(mColon.EndRange)
reportParseErrorAt mColon (FSComp.SR.parsExpectingType ())
SynPat.IsInst(ty, mColon) }

| atomicPattern
{ $1 }
Expand Down Expand Up @@ -3856,6 +3871,8 @@ parenPattern:

| parenPattern COLON recover
{ let mColon = rhs parseState 2
if not $3 then
reportParseErrorAt mColon (FSComp.SR.parsExpectingPattern ())
let ty = SynType.FromParseError(mColon.EndRange)
SynPat.Typed($1, ty, unionRanges $1.Range mColon) }

Expand All @@ -3869,6 +3886,8 @@ parenPattern:

| parenPattern COLON_COLON recover
{ let mColonColon = rhs parseState 2
if not $3 then
reportParseErrorAt mColonColon (FSComp.SR.parsExpectingPattern ())
let pat2 = SynPat.Wild(mColonColon.EndRange)
SynPat.ListCons($1, pat2, rhs2 parseState 1 2, { ColonColonRange = mColonColon }) }

Expand Down
6 changes: 6 additions & 0 deletions tests/service/data/SyntaxTree/MatchClause/Missing pat 05.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Module

match () with
|

()
18 changes: 18 additions & 0 deletions tests/service/data/SyntaxTree/MatchClause/Missing pat 05.fs.bsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
ImplFile
(ParsedImplFileInput
("/root/MatchClause/Missing pat 05.fs", false, QualifiedNameOfFile Module,
[], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Expr
(Match
(Yes (3,0--3,13), Const (Unit, (3,6--3,8)), [], (3,0--4,1),
{ MatchKeyword = (3,0--3,5)
WithKeyword = (3,9--3,13) }), (3,0--4,1));
Expr (Const (Unit, (6,0--6,2)), (6,0--6,2))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(6,0)-(6,1) parse error Incomplete structured construct at or before this point in expression
6 changes: 6 additions & 0 deletions tests/service/data/SyntaxTree/Pattern/IsInst 01.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Module

match () with
| :? T -> ()

()
21 changes: 21 additions & 0 deletions tests/service/data/SyntaxTree/Pattern/IsInst 01.fs.bsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
ImplFile
(ParsedImplFileInput
("/root/Pattern/IsInst 01.fs", false, QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Expr
(Match
(Yes (3,0--3,13), Const (Unit, (3,6--3,8)),
[SynMatchClause
(IsInst
(LongIdent (SynLongIdent ([T], [], [None])), (4,2--4,6)),
None, Const (Unit, (4,10--4,12)), (4,2--4,12), Yes,
{ ArrowRange = Some (4,7--4,9)
BarRange = Some (4,0--4,1) })], (3,0--4,12),
{ MatchKeyword = (3,0--3,5)
WithKeyword = (3,9--3,13) }), (3,0--4,12));
Expr (Const (Unit, (6,0--6,2)), (6,0--6,2))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))
6 changes: 6 additions & 0 deletions tests/service/data/SyntaxTree/Pattern/IsInst 02.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Module

match () with
| :? T

()
23 changes: 23 additions & 0 deletions tests/service/data/SyntaxTree/Pattern/IsInst 02.fs.bsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
ImplFile
(ParsedImplFileInput
("/root/Pattern/IsInst 02.fs", false, QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Expr
(Match
(Yes (3,0--3,13), Const (Unit, (3,6--3,8)),
[SynMatchClause
(IsInst
(LongIdent (SynLongIdent ([T], [], [None])), (4,2--4,6)),
None, ArbitraryAfterError ("patternClauses2", (4,6--4,6)),
(4,2--4,6), Yes, { ArrowRange = None
BarRange = Some (4,0--4,1) })],
(3,0--4,6), { MatchKeyword = (3,0--3,5)
WithKeyword = (3,9--3,13) }), (3,0--4,6));
Expr (Const (Unit, (6,0--6,2)), (6,0--6,2))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(6,0)-(6,1) parse error Incomplete structured construct at or before this point in pattern matching. Expected '->' or other token.
6 changes: 6 additions & 0 deletions tests/service/data/SyntaxTree/Pattern/IsInst 03.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Module

match () with
| :? -> ()

()
22 changes: 22 additions & 0 deletions tests/service/data/SyntaxTree/Pattern/IsInst 03.fs.bsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
ImplFile
(ParsedImplFileInput
("/root/Pattern/IsInst 03.fs", false, QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Expr
(Match
(Yes (3,0--3,13), Const (Unit, (3,6--3,8)),
[SynMatchClause
(IsInst (FromParseError (4,4--4,4), (4,2--4,4)), None,
Const (Unit, (4,8--4,10)), (4,2--4,10), Yes,
{ ArrowRange = Some (4,5--4,7)
BarRange = Some (4,0--4,1) })], (3,0--4,10),
{ MatchKeyword = (3,0--3,5)
WithKeyword = (3,9--3,13) }), (3,0--4,10));
Expr (Const (Unit, (6,0--6,2)), (6,0--6,2))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(4,2)-(4,4) parse error Expecting type
6 changes: 6 additions & 0 deletions tests/service/data/SyntaxTree/Pattern/IsInst 04.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Module

match () with
| :?

()
23 changes: 23 additions & 0 deletions tests/service/data/SyntaxTree/Pattern/IsInst 04.fs.bsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
ImplFile
(ParsedImplFileInput
("/root/Pattern/IsInst 04.fs", false, QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Expr
(Match
(Yes (3,0--3,13), Const (Unit, (3,6--3,8)),
[SynMatchClause
(IsInst (FromParseError (4,4--4,4), (4,2--4,4)), None,
ArbitraryAfterError ("patternClauses2", (4,4--4,4)),
(4,2--4,4), Yes, { ArrowRange = None
BarRange = Some (4,0--4,1) })],
(3,0--4,4), { MatchKeyword = (3,0--3,5)
WithKeyword = (3,9--3,13) }), (3,0--4,4));
Expr (Const (Unit, (6,0--6,2)), (6,0--6,2))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(4,2)-(4,4) parse error Expecting type
(6,0)-(6,1) parse error Incomplete structured construct at or before this point in pattern matching. Expected '->' or other token.
7 changes: 7 additions & 0 deletions tests/service/data/SyntaxTree/Pattern/IsInst 05.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module Module

match () with
| :?
| _ -> ()

()
24 changes: 24 additions & 0 deletions tests/service/data/SyntaxTree/Pattern/IsInst 05.fs.bsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
ImplFile
(ParsedImplFileInput
("/root/Pattern/IsInst 05.fs", false, QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Expr
(Match
(Yes (3,0--3,13), Const (Unit, (3,6--3,8)),
[SynMatchClause
(Or
(IsInst (FromParseError (4,4--4,4), (4,2--4,4)),
Wild (5,2--5,3), (4,2--5,3), { BarRange = (5,0--5,1) }),
None, Const (Unit, (5,7--5,9)), (4,2--5,9), Yes,
{ ArrowRange = Some (5,4--5,6)
BarRange = Some (4,0--4,1) })], (3,0--5,9),
{ MatchKeyword = (3,0--3,5)
WithKeyword = (3,9--3,13) }), (3,0--5,9));
Expr (Const (Unit, (7,0--7,2)), (7,0--7,2))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--7,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(4,2)-(4,4) parse error Expecting type
Loading