Skip to content

Commit 8c2e2e0

Browse files
committed
Fix scala#3332: Disallow bound variable sin pattern alternatives
Disallow bound variables where the binder appears as a pattern alternative.
1 parent dfe45fc commit 8c2e2e0

File tree

4 files changed

+20
-6
lines changed

4 files changed

+20
-6
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: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,12 +1211,14 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
12111211
typed(untpd.Bind(tree.name, untpd.TypedSplice(arg)).withPos(tree.pos), arg.tpe) :: Nil)
12121212
case _ =>
12131213
val sym = newPatternBoundSym(tree.name, body1.tpe, tree.pos)
1214+
if (ctx.mode.is(Mode.InPatternAlternative)) ctx.error("Illegal variable in pattern alternative", tree.pos)
12141215
assignType(cpy.Bind(tree)(tree.name, body1), sym)
12151216
}
12161217
}
12171218

12181219
def typedAlternative(tree: untpd.Alternative, pt: Type)(implicit ctx: Context): Alternative = track("typedAlternative") {
1219-
val trees1 = tree.trees mapconserve (typed(_, pt))
1220+
val nestedCtx = ctx.addMode(Mode.InPatternAlternative)
1221+
val trees1 = tree.trees.mapconserve(typed(_, pt)(nestedCtx))
12201222
assignType(cpy.Alternative(tree)(trees1), trees1)
12211223
}
12221224

@@ -1754,7 +1756,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
17541756
Inliner.removeInlineAccessors(mdef.symbol)
17551757

17561758
def typedExpr(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree =
1757-
typed(tree, pt)(ctx retractMode Mode.PatternOrType)
1759+
typed(tree, pt)(ctx retractMode Mode.PatternOrTypeBits)
17581760
def typedType(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = // todo: retract mode between Type and Pattern?
17591761
typed(tree, pt)(ctx addMode Mode.Type)
17601762
def typedPattern(tree: untpd.Tree, selType: Type = WildcardType)(implicit ctx: Context): Tree =

tests/neg/i3332.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
object Main {
2+
def main(args: Array[String]): Unit = {
3+
(1: Any) match {
4+
case x: String | Int => "OK"
5+
case (_: String) | (_: Int) => "OK"
6+
case (s: String) | _: Int => s // error: Illegal variable in pattern alternative
7+
}
8+
}
9+
}

0 commit comments

Comments
 (0)