Skip to content

Commit 2553b9e

Browse files
authored
Merge pull request #12261 from dotty-staging/fix-12260
Fix #12260: Add underscore to match type syntax
2 parents a018159 + bb96d95 commit 2553b9e

File tree

8 files changed

+59
-7
lines changed

8 files changed

+59
-7
lines changed

compiler/src/dotty/tools/dotc/core/MatchTypeTrace.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ object MatchTypeTrace:
8484

8585
private def caseText(tp: Type)(using Context): String = tp match
8686
case tp: HKTypeLambda => caseText(tp.resultType)
87+
case defn.MatchCase(any, body) if any eq defn.AnyType => i"case _ => $body"
8788
case defn.MatchCase(pat, body) => i"case $pat => $body"
8889
case _ => i"case $tp"
8990

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1829,7 +1829,7 @@ object Parsers {
18291829

18301830
def typeDependingOn(location: Location): Tree =
18311831
if location.inParens then typ()
1832-
else if location.inPattern then refinedType()
1832+
else if location.inPattern then rejectWildcardType(refinedType())
18331833
else infixType()
18341834

18351835
/* ----------- EXPRESSIONS ------------------------------------------------ */
@@ -2615,15 +2615,21 @@ object Parsers {
26152615
})
26162616
}
26172617

2618-
/** TypeCaseClause ::= ‘case’ InfixType ‘=>’ Type [semi]
2618+
/** TypeCaseClause ::= ‘case’ (InfixType | ‘_’) ‘=>’ Type [semi]
26192619
*/
26202620
def typeCaseClause(): CaseDef = atSpan(in.offset) {
26212621
val pat = inSepRegion(InCase) {
26222622
accept(CASE)
2623-
infixType()
2623+
in.token match {
2624+
case USCORE if in.lookahead.isArrow =>
2625+
val start = in.skipToken()
2626+
Ident(tpnme.WILDCARD).withSpan(Span(start, in.lastOffset, start))
2627+
case _ =>
2628+
rejectWildcardType(infixType())
2629+
}
26242630
}
26252631
CaseDef(pat, EmptyTree, atSpan(accept(ARROW)) {
2626-
val t = typ()
2632+
val t = rejectWildcardType(typ())
26272633
if in.token == SEMI then in.nextToken()
26282634
newLinesOptWhenFollowedBy(CASE)
26292635
t

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
498498
if ctx.mode.is(Mode.Pattern) then
499499
if name == nme.WILDCARD then
500500
return tree.withType(pt)
501+
if name == tpnme.WILDCARD then
502+
return tree.withType(defn.AnyType)
501503
if untpd.isVarPattern(tree) && name.isTermName then
502504
return typed(desugar.patternVar(tree), pt)
503505
else if ctx.mode.is(Mode.QuotedPattern) then
@@ -1561,6 +1563,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
15611563
case defn.MatchCase(patternTp, _) => tpt.tpe frozen_=:= patternTp
15621564
case _ => false
15631565
}
1566+
case (id @ Ident(nme.WILDCARD), pt) =>
1567+
pt match {
1568+
case defn.MatchCase(patternTp, _) => defn.AnyType frozen_=:= patternTp
1569+
case _ => false
1570+
}
15641571
case _ => false
15651572
}
15661573

docs/docs/internals/syntax.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ CaseClauses ::= CaseClause { CaseClause }
291291
CaseClause ::= ‘case’ Pattern [Guard] ‘=>’ Block CaseDef(pat, guard?, block) // block starts at =>
292292
ExprCaseClause ::= ‘case’ Pattern [Guard] ‘=>’ Expr
293293
TypeCaseClauses ::= TypeCaseClause { TypeCaseClause }
294-
TypeCaseClause ::= ‘case’ InfixType ‘=>’ Type [semi]
294+
TypeCaseClause ::= ‘case’ (InfixType | ‘_’) ‘=>’ Type [semi]
295295
296296
Pattern ::= Pattern1 { ‘|’ Pattern1 } Alternative(pats)
297297
Pattern1 ::= Pattern2 [‘:’ RefinedType] Bind(name, Typed(Ident(wildcard), tpe))

tests/neg/12261.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
type M0[X] = X match {
2+
case ? => String // error: Unbound wildcard type
3+
}
4+
5+
type M1[X] = X match {
6+
case Any => _ // error: Unbound wildcard type
7+
}
8+
9+
type M2[X] = X match {
10+
case Any => ? // error: Unbound wildcard type
11+
}
12+
13+
val a = "" match { case _: _ => () } // error: Unbound wildcard type
14+
15+
val b = try { } catch { case _: _ => () } // error: Unbound wildcard type

tests/pos/9239.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ object ABug:
2424
N match
2525
case Zero => One
2626
case One => One
27-
case ? => ![--[N]] × (N)
27+
case _ => ![--[N]] × (N)
2828
case ? :: ? => ![--[N]] × (N)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// `case _ => expr` in a match expression should be equivalant to
2+
// `case _: Any => expr`. Likewise, in a match type, `case _ => T`
3+
// should be equivalant to `case Any => T`.
4+
5+
object Test0 {
6+
type M[X] = X match { case String => Int case Any => String }
7+
def m[X](x: X): M[X] = x match { case _: String => 1 case _: Any => "s" }
8+
}
9+
10+
object Test1 {
11+
type M[X] = X match { case String => Int case Any => String }
12+
def m[X](x: X): M[X] = x match { case _: String => 1 case _ => "s" }
13+
}
14+
15+
object Test2 {
16+
type M[X] = X match { case String => Int case _ => String }
17+
def m[X](x: X): M[X] = x match { case _: String => 1 case _: Any => "s" }
18+
}
19+
20+
object Test3 {
21+
type M[X] = X match { case String => Int case _ => String }
22+
def m[X](x: X): M[X] = x match { case _: String => 1 case _ => "s" }
23+
}

0 commit comments

Comments
 (0)