Skip to content

Commit a15a7f6

Browse files
authored
Merge pull request #3429 from dotty-staging/fix-3332
Fix #3332: Disallow bound variables in pattern alternatives
2 parents 6dab4c2 + de55510 commit a15a7f6

File tree

4 files changed

+38
-8
lines changed

4 files changed

+38
-8
lines changed

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ case class Mode(val bits: Int) extends AnyVal {
88
def &~ (that: Mode) = Mode(bits & ~that.bits)
99
def is (that: Mode) = (bits & that.bits) == that.bits
1010

11-
def isExpr = (this & PatternOrType) == None
11+
def isExpr = (this & PatternOrTypeBits) == None
1212

1313
override def toString =
1414
(0 until 31).filter(i => (bits & (1 << i)) != 0).map(modeName).mkString("Mode(", ",", ")")
@@ -42,6 +42,9 @@ object Mode {
4242
/** We are looking at the arguments of a supercall */
4343
val InSuperCall = newMode(6, "InSuperCall")
4444

45+
/** We are in a pattern alternative */
46+
val InPatternAlternative = newMode(7, "InPatternAlternative")
47+
4548
/** Allow GADTFlexType labelled types to have their bounds adjusted */
4649
val GADTflexible = newMode(8, "GADTflexible")
4750

@@ -87,7 +90,7 @@ object Mode {
8790
/** Don't suppress exceptions thrown during show */
8891
val PrintShowExceptions = newMode(18, "PrintShowExceptions")
8992

90-
val PatternOrType = Pattern | Type
93+
val PatternOrTypeBits = Pattern | Type | InPatternAlternative
9194

9295
/** We are elaborating the fully qualified name of a package clause.
9396
* In this case, identifiers should never be imported.

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -936,10 +936,10 @@ class Namer { typer: Typer =>
936936
}
937937

938938
def typedAheadType(tree: Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree =
939-
typedAheadImpl(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrType addMode Mode.Type))
939+
typedAheadImpl(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrTypeBits addMode Mode.Type))
940940

941941
def typedAheadExpr(tree: Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree =
942-
typedAheadImpl(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrType))
942+
typedAheadImpl(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrTypeBits))
943943

944944
def typedAheadAnnotation(tree: Tree)(implicit ctx: Context): Symbol = tree match {
945945
case Apply(fn, _) => typedAheadAnnotation(fn)

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,13 +1210,19 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
12101210
tpd.cpy.UnApply(body1)(fn, Nil,
12111211
typed(untpd.Bind(tree.name, untpd.TypedSplice(arg)).withPos(tree.pos), arg.tpe) :: Nil)
12121212
case _ =>
1213-
val sym = newPatternBoundSym(tree.name, body1.tpe, tree.pos)
1214-
assignType(cpy.Bind(tree)(tree.name, body1), sym)
1213+
if (tree.name == nme.WILDCARD) body1
1214+
else {
1215+
val sym = newPatternBoundSym(tree.name, body1.tpe, tree.pos)
1216+
if (ctx.mode.is(Mode.InPatternAlternative))
1217+
ctx.error(i"Illegal variable ${sym.name} in pattern alternative", tree.pos)
1218+
assignType(cpy.Bind(tree)(tree.name, body1), sym)
1219+
}
12151220
}
12161221
}
12171222

12181223
def typedAlternative(tree: untpd.Alternative, pt: Type)(implicit ctx: Context): Alternative = track("typedAlternative") {
1219-
val trees1 = tree.trees mapconserve (typed(_, pt))
1224+
val nestedCtx = ctx.addMode(Mode.InPatternAlternative)
1225+
val trees1 = tree.trees.mapconserve(typed(_, pt)(nestedCtx))
12201226
assignType(cpy.Alternative(tree)(trees1), trees1)
12211227
}
12221228

@@ -1754,7 +1760,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
17541760
Inliner.removeInlineAccessors(mdef.symbol)
17551761

17561762
def typedExpr(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree =
1757-
typed(tree, pt)(ctx retractMode Mode.PatternOrType)
1763+
typed(tree, pt)(ctx retractMode Mode.PatternOrTypeBits)
17581764
def typedType(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = // todo: retract mode between Type and Pattern?
17591765
typed(tree, pt)(ctx addMode Mode.Type)
17601766
def typedPattern(tree: untpd.Tree, selType: Type = WildcardType)(implicit ctx: Context): Tree =

tests/neg/i3332.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
object Main {
2+
def main(args: Array[String]): Unit = {
3+
(1: Any) match {
4+
case x: String | Int => "OK" // error: Illegal variable in pattern alternative
5+
case (_: String) | (_: Int) => "OK"
6+
case (s: String) | _: Int => s // error: Illegal variable in pattern alternative
7+
}
8+
}
9+
}
10+
11+
// #1612
12+
object Test {
13+
case class A()
14+
def g(p:(Int,Int)) = p match {
15+
case (10,n) | (n,10) => println(n) // error // error (Illegal variable in pattern alternative)
16+
case _ => println("nope")
17+
}
18+
def test(x: Any) = x match {
19+
case _: String | _ @ A() => 1
20+
}
21+
}

0 commit comments

Comments
 (0)