Skip to content
Open
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
74 changes: 45 additions & 29 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ object Parsers {
case InGuard extends Location(false, false, false)
case InPatternArgs extends Location(false, true, true) // InParens not true, since it might be an alternative
case InBlock extends Location(false, false, false)
case ElseWhere extends Location(false, false, false)
case Elsewhere extends Location(false, false, false)

enum ParamOwner:
case Class // class or trait or enum
Expand Down Expand Up @@ -1914,7 +1914,7 @@ object Parsers {
def infixType(inContextBound: Boolean = false): Tree = infixTypeRest(inContextBound)(refinedType())

def infixTypeRest(inContextBound: Boolean = false)(t: Tree, operand: Location => Tree = refinedTypeFn): Tree =
infixOps(t, canStartInfixTypeTokens, operand, Location.ElseWhere, ParseKind.Type,
infixOps(t, canStartInfixTypeTokens, operand, Location.Elsewhere, ParseKind.Type,
isOperator = !followingIsVararg()
&& !isPureArrow
&& !(isIdent(nme.as) && sourceVersion.enablesNewGivens && inContextBound)
Expand Down Expand Up @@ -2400,9 +2400,9 @@ object Parsers {
inSepRegion(InCond):
expr1Rest(
postfixExprRest(
simpleExprRest(t, Location.ElseWhere),
Location.ElseWhere),
Location.ElseWhere)
simpleExprRest(t, Location.Elsewhere),
Location.Elsewhere),
Location.Elsewhere)
else
if rewriteToNewSyntax(t.span) then
dropParensOrBraces(t.span.start, tokenString(altToken))
Expand Down Expand Up @@ -2452,7 +2452,7 @@ object Parsers {
*/
val exprInParens: () => Tree = () => expr(Location.InParens)

val expr: () => Tree = () => expr(Location.ElseWhere)
val expr: () => Tree = () => expr(Location.Elsewhere)

def subExpr() = subPart(expr)

Expand Down Expand Up @@ -2497,7 +2497,7 @@ object Parsers {
wrapPlaceholders(t)
}

def expr1(location: Location = Location.ElseWhere): Tree = in.token match
def expr1(location: Location = Location.Elsewhere): Tree = in.token match
case IF =>
ifExpr(in.offset, If)
case WHILE =>
Expand Down Expand Up @@ -2602,7 +2602,7 @@ object Parsers {
t match
case Ident(_) | Select(_, _) | Apply(_, _) | PrefixOp(_, _) | PostfixOp(_, _) =>
atSpan(startOffset(t), in.skipToken()) {
val loc = if location.inArgs then location else Location.ElseWhere
val loc = if location.inArgs then location else Location.Elsewhere
Assign(t, subPart(() => expr(loc)))
}
case _ =>
Expand Down Expand Up @@ -2792,7 +2792,7 @@ object Parsers {
* | InfixExpr id ColonArgument
* | InfixExpr MatchClause
*/
def postfixExpr(location: Location = Location.ElseWhere): Tree =
def postfixExpr(location: Location = Location.Elsewhere): Tree =
val t = postfixExprRest(prefixExpr(location), location)
if location.inArgs && followingIsVararg() then
Typed(t, atSpan(in.skipToken()) { Ident(tpnme.WILDCARD_STAR) })
Expand Down Expand Up @@ -2874,7 +2874,7 @@ object Parsers {
newExpr()
case MACRO =>
val start = in.skipToken()
MacroTree(simpleExpr(Location.ElseWhere))
MacroTree(simpleExpr(Location.Elsewhere))
case _ =>
if isLiteral then
literal()
Expand Down Expand Up @@ -3312,30 +3312,46 @@ object Parsers {
if (isIdent(nme.raw.BAR)) { in.nextToken(); pattern1(location) :: patternAlts(location) }
else Nil

// After a pattern, accept colon and type or ascription per tree.
// Warn if old style ascription after pattern that is not a simple name.
// Warn mildly for case X: String, that is, introducing a "constant" id in a typed pattern.
def checkedAscription(pat: Tree, inPattern: Boolean = true)(tree: => Tree): Tree =
val atColon = in.isColon
tree.tap: tree =>
if atColon then
val isIdent = unsplice(pat) match {
case x: Ident =>
if inPattern && !x.name.isVarPattern then
val tpt = tree match
case Typed(_, tpt) => i"${tpt}"
case _ => "T"
report.warning(em"Typed pattern is not a variable pattern but could be written `${x.name} @ (_: $tpt)`",
pat.sourcePos)
true
case _ => false
}
if !isIdent && !pat.isInstanceOf[Number] then
report.errorOrMigrationWarning(
em"""Type ascriptions after patterns other than:
| * variable pattern, e.g. `case x: String =>`
| * number literal pattern, e.g. `case 10.5: Double =>`
|are no longer supported. Remove the type ascription or move it to a separate variable pattern.""",
pat.sourcePos,
MigrationVersion.AscriptionAfterPattern)

/** Pattern1 ::= PatVar `:` RefinedType
* | [‘-’] integerLiteral `:` RefinedType
* | [‘-’] floatingPointLiteral `:` RefinedType
* | Pattern2
*/
def pattern1(location: Location = Location.InPattern): Tree =
val p = pattern2(location)
if in.isColon then
val isVariable = unsplice(p) match {
case x: Ident => x.name.isVarPattern
case _ => false
}
val isVariableOrNumber = isVariable || p.isInstanceOf[Number]
if !isVariableOrNumber then
report.errorOrMigrationWarning(
em"""Type ascriptions after patterns other than:
| * variable pattern, e.g. `case x: String =>`
| * number literal pattern, e.g. `case 10.5: Double =>`
|are no longer supported. Remove the type ascription or move it to a separate variable pattern.""",
p.sourcePos,
MigrationVersion.AscriptionAfterPattern)
in.nextToken()
ascription(p, location)
else p
val pat = pattern2(location)
inline def maybeAscription =
if in.isColon then
in.nextToken()
ascription(pat, location)
else pat
checkedAscription(pat, inPattern = true)(maybeAscription)

/** Pattern3 ::= InfixPattern
*/
Expand Down Expand Up @@ -4106,7 +4122,7 @@ object Parsers {
case _ =>
first :: Nil
}
val tpt = typedOpt()
val tpt = checkedAscription(first, inPattern = false)(typedOpt())
val rhs =
if tpt.isEmpty || in.token == EQUALS then
accept(EQUALS)
Expand Down
14 changes: 0 additions & 14 deletions tests/neg/i15784.check
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,3 @@
| Not found: A
|
| longer explanation available when compiling with `-explain`
-- Warning: tests/neg/i15784.scala:7:7 ---------------------------------------------------------------------------------
7 | case X: Int => X // warn
| ^
| Type ascriptions after patterns other than:
| * variable pattern, e.g. `case x: String =>`
| * number literal pattern, e.g. `case 10.5: Double =>`
| are no longer supported. Remove the type ascription or move it to a separate variable pattern.
-- Warning: tests/neg/i15784.scala:10:7 --------------------------------------------------------------------------------
10 | case `Int`: Int => `Int` // warn
| ^^^^^
| Type ascriptions after patterns other than:
| * variable pattern, e.g. `case x: String =>`
| * number literal pattern, e.g. `case 10.5: Double =>`
| are no longer supported. Remove the type ascription or move it to a separate variable pattern.
6 changes: 0 additions & 6 deletions tests/neg/i15784.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,3 @@ def i15784 = List(42) match
case List(_, Rest @ `a`) => Rest // error
case List(_, Rest @ A) => Rest // error
case _ => ???

def case2 = 42 match
case X: Int => X // warn

def case3 = 42 match
case `Int`: Int => `Int` // warn
7 changes: 7 additions & 0 deletions tests/neg/i25595.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- Error: tests/neg/i25595.scala:5:4 -----------------------------------------------------------------------------------
5 |val ((x1, f1), (x2, f2)): ( // error
| ^^^^^^^^^^^^^^^^^^^^
| Type ascriptions after patterns other than:
| * variable pattern, e.g. `case x: String =>`
| * number literal pattern, e.g. `case 10.5: Double =>`
| are no longer supported. Remove the type ascription or move it to a separate variable pattern.
8 changes: 8 additions & 0 deletions tests/neg/i25595.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//> using options -source:future

val avs = ((0d, BigDecimal(1)), (1d, BigDecimal(2)))

val ((x1, f1), (x2, f2)): ( // error
(Double, BigDecimal),
(Double, BigDecimal)
) = avs
2 changes: 1 addition & 1 deletion tests/warn/i25004/test_2.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//> using options -Werror -Wunused:all -Xcheck-macros
@main def Test =
TestBuilder.test:
val start @ _: String = "" // Converting this to a match expression resolves the error
val start @ (_: String) = "" // Converting this to a match expression resolves the error
// Alternative: val Seq(start) = Seq("")
print(start)
2 changes: 1 addition & 1 deletion tests/warn/i25004b/test_2.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//> using options -Werror -Wunused:all
@main def Test =
TestBuilder.test:
val start @ _: String = "" // Converting this to a match expression resolves the error
val start @ (_: String) = "" // Converting this to a match expression resolves the error
// Alternative: val Seq(start) = Seq("")
print(start)
15 changes: 15 additions & 0 deletions tests/warn/i25595.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- Warning: tests/warn/i25595.scala:3:4 --------------------------------------------------------------------------------
3 |val ((x1, f1), (x2, f2)): ( // warn
| ^^^^^^^^^^^^^^^^^^^^
| Type ascriptions after patterns other than:
| * variable pattern, e.g. `case x: String =>`
| * number literal pattern, e.g. `case 10.5: Double =>`
| are no longer supported. Remove the type ascription or move it to a separate variable pattern.
-- Warning: tests/warn/i25595.scala:9:7 --------------------------------------------------------------------------------
9 | case X: Int => X // warn
| ^
| Typed pattern is not a variable pattern but could be written `X @ (_: Int)`
-- Warning: tests/warn/i25595.scala:12:7 -------------------------------------------------------------------------------
12 | case `Int`: Int => `Int` // warn
| ^^^^^
| Typed pattern is not a variable pattern but could be written `Int @ (_: Int)`
12 changes: 12 additions & 0 deletions tests/warn/i25595.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
val avs = ((0d, BigDecimal(1)), (1d, BigDecimal(2)))

val ((x1, f1), (x2, f2)): ( // warn
(Double, BigDecimal),
(Double, BigDecimal)
) = avs

def notVar(i: Int) = i match
case X: Int => X // warn

def notVarBackquoted(i: Int) = i match
case `Int`: Int => `Int` // warn
Loading