Skip to content

Commit 8205a5b

Browse files
authored
Fix syntax and parsing of vararg patterns (#18055)
Syntax: Remove outdated `*` after InfixPattern Parsing: Only allow vararg `*` in ArgumentPatterns Fixes #17443
2 parents d43c2cf + d7ec913 commit 8205a5b

File tree

9 files changed

+40
-30
lines changed

9 files changed

+40
-30
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,7 +1666,7 @@ object Parsers {
16661666
if in.token == LPAREN then funParamClause() :: funParamClauses() else Nil
16671667

16681668
/** InfixType ::= RefinedType {id [nl] RefinedType}
1669-
* | RefinedType `^`
1669+
* | RefinedType `^` // under capture checking
16701670
*/
16711671
def infixType(): Tree = infixTypeRest(refinedType())
16721672

@@ -2881,13 +2881,13 @@ object Parsers {
28812881
if (isIdent(nme.raw.BAR)) { in.nextToken(); pattern1(location) :: patternAlts(location) }
28822882
else Nil
28832883

2884-
/** Pattern1 ::= PatVar Ascription
2885-
* | [‘-’] integerLiteral Ascription
2886-
* | [‘-’] floatingPointLiteral Ascription
2884+
/** Pattern1 ::= PatVar `:` RefinedType
2885+
* | [‘-’] integerLiteral `:` RefinedType
2886+
* | [‘-’] floatingPointLiteral `:` RefinedType
28872887
* | Pattern2
28882888
*/
28892889
def pattern1(location: Location = Location.InPattern): Tree =
2890-
val p = pattern2()
2890+
val p = pattern2(location)
28912891
if in.isColon then
28922892
val isVariableOrNumber = isVarPattern(p) || p.isInstanceOf[Number]
28932893
if !isVariableOrNumber then
@@ -2905,26 +2905,29 @@ object Parsers {
29052905
else p
29062906

29072907
/** Pattern3 ::= InfixPattern
2908-
* | PatVar ‘*’
29092908
*/
2910-
def pattern3(): Tree =
2909+
def pattern3(location: Location): Tree =
29112910
val p = infixPattern()
29122911
if followingIsVararg() then
29132912
val start = in.skipToken()
2914-
p match
2915-
case p @ Ident(name) if name.isVarPattern =>
2916-
Typed(p, atSpan(start) { Ident(tpnme.WILDCARD_STAR) })
2917-
case _ =>
2918-
syntaxError(em"`*` must follow pattern variable", start)
2919-
p
2913+
if location.inArgs then
2914+
p match
2915+
case p @ Ident(name) if name.isVarPattern =>
2916+
Typed(p, atSpan(start) { Ident(tpnme.WILDCARD_STAR) })
2917+
case _ =>
2918+
syntaxError(em"`*` must follow pattern variable", start)
2919+
p
2920+
else
2921+
syntaxError(em"bad use of `*` - sequence pattern not allowed here", start)
2922+
p
29202923
else p
29212924

29222925
/** Pattern2 ::= [id `@'] Pattern3
29232926
*/
2924-
val pattern2: () => Tree = () => pattern3() match
2927+
val pattern2: Location => Tree = location => pattern3(location) match
29252928
case p @ Ident(name) if in.token == AT =>
29262929
val offset = in.skipToken()
2927-
pattern3() match {
2930+
pattern3(location) match {
29282931
case pt @ Bind(nme.WILDCARD, pt1: Typed) if pt.mods.is(Given) =>
29292932
atSpan(startOffset(p), 0) { Bind(name, pt1).withMods(pt.mods) }
29302933
case Typed(Ident(nme.WILDCARD), pt @ Ident(tpnme.WILDCARD_STAR)) =>
@@ -2954,6 +2957,7 @@ object Parsers {
29542957
* | XmlPattern
29552958
* | `(' [Patterns] `)'
29562959
* | SimplePattern1 [TypeArgs] [ArgumentPatterns]
2960+
* | ‘given’ RefinedType
29572961
* SimplePattern1 ::= SimpleRef
29582962
* | SimplePattern1 `.' id
29592963
* PatVar ::= id
@@ -3597,7 +3601,7 @@ object Parsers {
35973601
* VarDcl ::= id {`,' id} `:' Type
35983602
*/
35993603
def patDefOrDcl(start: Offset, mods: Modifiers): Tree = atSpan(start, nameStart) {
3600-
val first = pattern2()
3604+
val first = pattern2(Location.InPattern)
36013605
var lhs = first match {
36023606
case id: Ident if in.token == COMMA =>
36033607
in.nextToken()

docs/_docs/internals/syntax.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ Pattern1 ::= PatVar ‘:’ RefinedType
317317
| [‘-’] integerLiteral ‘:’ RefinedType Typed(pat, tpe)
318318
| [‘-’] floatingPointLiteral ‘:’ RefinedType Typed(pat, tpe)
319319
| Pattern2
320-
Pattern2 ::= [id ‘@’] InfixPattern [‘*’] Bind(name, pat)
320+
Pattern2 ::= [id ‘@’] InfixPattern Bind(name, pat)
321321
InfixPattern ::= SimplePattern { id [nl] SimplePattern } InfixOp(pat, op, pat)
322322
SimplePattern ::= PatVar Ident(wildcard)
323323
| Literal Bind(name, Ident(wildcard))

docs/_docs/reference/syntax.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ Pattern1 ::= PatVar ‘:’ RefinedType
318318
| [‘-’] integerLiteral ‘:’ RefinedType
319319
| [‘-’] floatingPointLiteral ‘:’ RefinedType
320320
| Pattern2
321-
Pattern2 ::= [id ‘@’] InfixPattern [‘*’]
321+
Pattern2 ::= [id ‘@’] InfixPattern
322322
InfixPattern ::= SimplePattern { id [nl] SimplePattern }
323323
SimplePattern ::= PatVar
324324
| Literal

tests/neg/i17443.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def run() =
2+
val x = List(1) match { case (xs*) => xs } // error

tests/neg/i8715.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- Error: tests/neg/i8715.scala:2:46 -----------------------------------------------------------------------------------
2+
2 |def Test = List(42) match { case List(xs @ (ys*)) => xs } // error
3+
| ^
4+
| bad use of `*` - sequence pattern not allowed here

tests/neg/i8715.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@main
2+
def Test = List(42) match { case List(xs @ (ys*)) => xs } // error

tests/neg/t5702-neg-bad-and-wild.check

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
| pattern expected
2121
|
2222
| longer explanation available when compiling with `-explain`
23+
-- Error: tests/neg/t5702-neg-bad-and-wild.scala:16:16 -----------------------------------------------------------------
24+
16 | case (1, x*) => // error: bad use of *
25+
| ^
26+
| bad use of `*` - sequence pattern not allowed here
2327
-- [E031] Syntax Error: tests/neg/t5702-neg-bad-and-wild.scala:17:18 ---------------------------------------------------
2428
17 | case (1, x: _*) => // error: bad use of _* (sequence pattern not allowed)
2529
| ^
@@ -32,6 +36,10 @@
3236
| pattern expected
3337
|
3438
| longer explanation available when compiling with `-explain`
39+
-- Error: tests/neg/t5702-neg-bad-and-wild.scala:25:14 -----------------------------------------------------------------
40+
25 | val (b, _ * ) = (5,6) // error: bad use of `*`
41+
| ^
42+
| bad use of `*` - sequence pattern not allowed here
3543
-- [E161] Naming Error: tests/neg/t5702-neg-bad-and-wild.scala:24:10 ---------------------------------------------------
3644
24 | val K(x) = k // error: x is already defined as value x
3745
| ^^^^^^^^^^^^
@@ -71,11 +79,3 @@
7179
| If the narrowing is intentional, this can be communicated by adding `: @unchecked` after the expression,
7280
| which may result in a MatchError at runtime.
7381
| This patch can be rewritten automatically under -rewrite -source 3.2-migration.
74-
-- Warning: tests/neg/t5702-neg-bad-and-wild.scala:25:20 ---------------------------------------------------------------
75-
25 | val (b, _ * ) = (5,6) // ok
76-
| ^^^^^
77-
| pattern's type Int* does not match the right hand side expression's type Int
78-
|
79-
| If the narrowing is intentional, this can be communicated by adding `: @unchecked` after the expression,
80-
| which may result in a MatchError at runtime.
81-
| This patch can be rewritten automatically under -rewrite -source 3.2-migration.

tests/neg/t5702-neg-bad-and-wild.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ object Test {
1313
case List(1, _*3:) => // error // error
1414
case List(1, x*) => // ok
1515
case List(x*, 1) => // error: pattern expected
16-
case (1, x*) => //ok
16+
case (1, x*) => // error: bad use of *
1717
case (1, x: _*) => // error: bad use of _* (sequence pattern not allowed)
1818
}
1919

@@ -22,7 +22,7 @@ object Test {
2222
val K(x @ _*) = k
2323
val K(ns @ _*, xx) = k // error: pattern expected // error
2424
val K(x) = k // error: x is already defined as value x
25-
val (b, _ * ) = (5,6) // ok
25+
val (b, _ * ) = (5,6) // error: bad use of `*`
2626
// no longer complains
2727
//bad-and-wild.scala:15: error: ')' expected but '}' found.
2828
}

tests/pos/i8715.scala

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)