Skip to content

Commit b122f26

Browse files
authored
Parser: recover on unfinished cons patterns (#17231)
1 parent 958ce12 commit b122f26

File tree

11 files changed

+151
-2
lines changed

11 files changed

+151
-2
lines changed

docs/release-notes/.FSharp.Compiler.Service/8.0.400.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
### Added
2020

2121
* Generate new `Equals` overload to avoid boxing for structural comparison ([PR #16857](https://github.com/dotnet/fsharp/pull/16857))
22+
* Parser: better recovery for unfinished patterns ([PR #17231](https://github.com/dotnet/fsharp/pull/17231))
2223

2324
### Changed
2425
* Enforce `AttributeTargets.Interface` ([PR #17173](https://github.com/dotnet/fsharp/pull/17173))

src/Compiler/pars.fsy

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3454,6 +3454,17 @@ headBindingPattern:
34543454
{ let mColonColon = rhs parseState 2
34553455
SynPat.ListCons($1, $3, rhs2 parseState 1 3, { ColonColonRange = mColonColon }) }
34563456

3457+
| headBindingPattern COLON_COLON recover
3458+
{ let mColonColon = rhs parseState 2
3459+
let pat2 = SynPat.Wild(mColonColon.EndRange)
3460+
SynPat.ListCons($1, pat2, rhs2 parseState 1 2, { ColonColonRange = mColonColon }) }
3461+
3462+
| headBindingPattern COLON_COLON
3463+
{ let mColonColon = rhs parseState 2
3464+
reportParseErrorAt mColonColon (FSComp.SR.parsExpectingPattern ())
3465+
let pat2 = SynPat.Wild(mColonColon.EndRange)
3466+
SynPat.ListCons($1, pat2, rhs2 parseState 1 2, { ColonColonRange = mColonColon }) }
3467+
34573468
| tuplePatternElements %prec pat_tuple
34583469
{ let pats, commas = $1
34593470
let pats, commas = normalizeTuplePat pats commas
@@ -3760,6 +3771,17 @@ parenPattern:
37603771
{ let mColonColon = rhs parseState 2
37613772
SynPat.ListCons($1, $3, rhs2 parseState 1 3, { ColonColonRange = mColonColon }) }
37623773

3774+
| parenPattern COLON_COLON recover
3775+
{ let mColonColon = rhs parseState 2
3776+
let pat2 = SynPat.Wild(mColonColon.EndRange)
3777+
SynPat.ListCons($1, pat2, rhs2 parseState 1 2, { ColonColonRange = mColonColon }) }
3778+
3779+
| parenPattern COLON_COLON
3780+
{ let mColonColon = rhs parseState 2
3781+
reportParseErrorAt mColonColon (FSComp.SR.parsExpectingPattern ())
3782+
let pat2 = SynPat.Wild(mColonColon.EndRange)
3783+
SynPat.ListCons($1, pat2, rhs2 parseState 1 2, { ColonColonRange = mColonColon }) }
3784+
37633785
| constrPattern { $1 }
37643786

37653787
tupleParenPatternElements:

tests/service/PatternMatchCompilationTests.fs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,7 @@ let z as =
756756
"(10,7--10,9): Unexpected keyword 'as' in binding";
757757
"(10,5--10,6): Expecting pattern";
758758
"(11,10--11,12): Unexpected keyword 'as' in binding. Expected '=' or other token.";
759-
"(12,9--12,11): Unexpected keyword 'as' in binding";
759+
"(12,6--12,8): Expecting pattern";
760760
"(13,8--13,10): Unexpected keyword 'as' in binding";
761761
"(14,8--14,10): Unexpected keyword 'as' in binding";
762762
"(15,8--15,10): Unexpected keyword 'as' in pattern. Expected ')' or other token.";
@@ -776,6 +776,8 @@ let z as =
776776
"(8,29--8,30): This expression was expected to have type\u001d 'unit' \u001dbut here has type\u001d 'int'";
777777
"(9,26--9,27): This expression was expected to have type\u001d 'unit' \u001dbut here has type\u001d 'int'";
778778
"(10,14--10,15): This expression was expected to have type\u001d ''a * 'b' \u001dbut here has type\u001d 'int'";
779+
"(12,16--12,18): This expression was expected to have type\u001d ''a list' \u001dbut here has type\u001d 'int'";
780+
"(12,4--12,13): Incomplete pattern matches on this expression. For example, the value '[]' may indicate a case not covered by the pattern(s).";
779781
"(15,4--15,5): The pattern discriminator 'r' is not defined.";
780782
"(15,4--15,12): Incomplete pattern matches on this expression."
781783
]
@@ -1176,7 +1178,7 @@ let as :? z =
11761178
"(10,7--10,9): Unexpected keyword 'as' in binding";
11771179
"(10,5--10,6): Expecting pattern";
11781180
"(11,10--11,12): Unexpected keyword 'as' in binding. Expected '=' or other token.";
1179-
"(12,9--12,11): Unexpected keyword 'as' in binding";
1181+
"(12,6--12,8): Expecting pattern";
11801182
"(13,8--13,10): Unexpected keyword 'as' in binding";
11811183
"(14,8--14,10): Unexpected keyword 'as' in binding";
11821184
"(15,13--15,15): Unexpected keyword 'as' in pattern. Expected '(' or other token.";
@@ -1204,6 +1206,8 @@ let as :? z =
12041206
"(9,22--9,26): The type 'unit' does not have any proper subtypes and cannot be used as the source of a type test or runtime coercion.";
12051207
"(10,13--10,14): The type 'i' is not defined.";
12061208
"(10,10--10,14): The type ''a * 'b' does not have any proper subtypes and cannot be used as the source of a type test or runtime coercion.";
1209+
"(12,15--12,16): The type 'm' is not defined.";
1210+
"(12,12--12,16): The type ''a list' does not have any proper subtypes and cannot be used as the source of a type test or runtime coercion.";
12071211
"(16,4--16,5): The pattern discriminator 't' is not defined.";
12081212
"(16,14--16,15): The type 'u' is not defined.";
12091213
"(16,11--16,15): This runtime coercion or type test from type\u001d 'a \u001d to \u001d 'b \u001dinvolves an indeterminate type based on information prior to this program point. Runtime type tests are not allowed on some types. Further type annotations are needed."
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module Module
2+
3+
match () with
4+
| _ :: _ -> ()
5+
6+
()
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
ImplFile
2+
(ParsedImplFileInput
3+
("/root/Pattern/Cons 01.fs", false, QualifiedNameOfFile Module, [], [],
4+
[SynModuleOrNamespace
5+
([Module], false, NamedModule,
6+
[Expr
7+
(Match
8+
(Yes (3,0--3,13), Const (Unit, (3,6--3,8)),
9+
[SynMatchClause
10+
(ListCons
11+
(Wild (4,2--4,3), Wild (4,7--4,8), (4,2--4,8),
12+
{ ColonColonRange = (4,4--4,6) }), None,
13+
Const (Unit, (4,12--4,14)), (4,2--4,14), Yes,
14+
{ ArrowRange = Some (4,9--4,11)
15+
BarRange = Some (4,0--4,1) })], (3,0--4,14),
16+
{ MatchKeyword = (3,0--3,5)
17+
WithKeyword = (3,9--3,13) }), (3,0--4,14));
18+
Expr (Const (Unit, (6,0--6,2)), (6,0--6,2))],
19+
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
20+
(1,0--6,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
21+
{ ConditionalDirectives = []
22+
CodeComments = [] }, set []))
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module Module
2+
3+
match () with
4+
| _ :: -> ()
5+
6+
()
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
ImplFile
2+
(ParsedImplFileInput
3+
("/root/Pattern/Cons 02.fs", false, QualifiedNameOfFile Module, [], [],
4+
[SynModuleOrNamespace
5+
([Module], false, NamedModule,
6+
[Expr
7+
(Match
8+
(Yes (3,0--3,13), Const (Unit, (3,6--3,8)),
9+
[SynMatchClause
10+
(ListCons
11+
(Wild (4,2--4,3), Wild (4,6--4,6), (4,2--4,6),
12+
{ ColonColonRange = (4,4--4,6) }), None,
13+
Const (Unit, (4,10--4,12)), (4,2--4,12), Yes,
14+
{ ArrowRange = Some (4,7--4,9)
15+
BarRange = Some (4,0--4,1) })], (3,0--4,12),
16+
{ MatchKeyword = (3,0--3,5)
17+
WithKeyword = (3,9--3,13) }), (3,0--4,12));
18+
Expr (Const (Unit, (6,0--6,2)), (6,0--6,2))],
19+
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
20+
(1,0--6,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
21+
{ ConditionalDirectives = []
22+
CodeComments = [] }, set []))
23+
24+
(4,4)-(4,6) parse error Expecting pattern
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module Module
2+
3+
match () with
4+
| _ ::
5+
6+
()
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
ImplFile
2+
(ParsedImplFileInput
3+
("/root/Pattern/Cons 03.fs", false, QualifiedNameOfFile Module, [], [],
4+
[SynModuleOrNamespace
5+
([Module], false, NamedModule,
6+
[Expr
7+
(Match
8+
(Yes (3,0--3,13), Const (Unit, (3,6--3,8)),
9+
[SynMatchClause
10+
(ListCons
11+
(Wild (4,2--4,3), Wild (4,6--4,6), (4,2--4,6),
12+
{ ColonColonRange = (4,4--4,6) }), None,
13+
ArbitraryAfterError ("patternClauses2", (4,6--4,6)),
14+
(4,2--4,6), Yes, { ArrowRange = None
15+
BarRange = Some (4,0--4,1) })],
16+
(3,0--4,6), { MatchKeyword = (3,0--3,5)
17+
WithKeyword = (3,9--3,13) }), (3,0--4,6));
18+
Expr (Const (Unit, (6,0--6,2)), (6,0--6,2))],
19+
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
20+
(1,0--6,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
21+
{ ConditionalDirectives = []
22+
CodeComments = [] }, set []))
23+
24+
(4,4)-(4,6) parse error Expecting pattern
25+
(6,0)-(6,1) parse error Incomplete structured construct at or before this point in pattern matching. Expected '->' or other token.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module Module
2+
3+
match () with
4+
| _ ::
5+
| _ -> ()
6+
7+
()
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
ImplFile
2+
(ParsedImplFileInput
3+
("/root/Pattern/Cons 04.fs", false, QualifiedNameOfFile Module, [], [],
4+
[SynModuleOrNamespace
5+
([Module], false, NamedModule,
6+
[Expr
7+
(Match
8+
(Yes (3,0--3,13), Const (Unit, (3,6--3,8)),
9+
[SynMatchClause
10+
(Or
11+
(ListCons
12+
(Wild (4,2--4,3), Wild (4,6--4,6), (4,2--4,6),
13+
{ ColonColonRange = (4,4--4,6) }), Wild (5,2--5,3),
14+
(4,2--5,3), { BarRange = (5,0--5,1) }), None,
15+
Const (Unit, (5,7--5,9)), (4,2--5,9), Yes,
16+
{ ArrowRange = Some (5,4--5,6)
17+
BarRange = Some (4,0--4,1) })], (3,0--5,9),
18+
{ MatchKeyword = (3,0--3,5)
19+
WithKeyword = (3,9--3,13) }), (3,0--5,9));
20+
Expr (Const (Unit, (7,0--7,2)), (7,0--7,2))],
21+
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
22+
(1,0--7,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
23+
{ ConditionalDirectives = []
24+
CodeComments = [] }, set []))
25+
26+
(4,4)-(4,6) parse error Expecting pattern

0 commit comments

Comments
 (0)