diff --git a/compiler/src/dotty/tools/dotc/core/Mode.scala b/compiler/src/dotty/tools/dotc/core/Mode.scala index 39e3ca21462d..5affc2cb8fd4 100644 --- a/compiler/src/dotty/tools/dotc/core/Mode.scala +++ b/compiler/src/dotty/tools/dotc/core/Mode.scala @@ -8,7 +8,7 @@ case class Mode(val bits: Int) extends AnyVal { def &~ (that: Mode) = Mode(bits & ~that.bits) def is (that: Mode) = (bits & that.bits) == that.bits - def isExpr = (this & PatternOrType) == None + def isExpr = (this & PatternOrTypeBits) == None override def toString = (0 until 31).filter(i => (bits & (1 << i)) != 0).map(modeName).mkString("Mode(", ",", ")") @@ -42,6 +42,9 @@ object Mode { /** We are looking at the arguments of a supercall */ val InSuperCall = newMode(6, "InSuperCall") + /** We are in a pattern alternative */ + val InPatternAlternative = newMode(7, "InPatternAlternative") + /** Allow GADTFlexType labelled types to have their bounds adjusted */ val GADTflexible = newMode(8, "GADTflexible") @@ -87,7 +90,7 @@ object Mode { /** Don't suppress exceptions thrown during show */ val PrintShowExceptions = newMode(18, "PrintShowExceptions") - val PatternOrType = Pattern | Type + val PatternOrTypeBits = Pattern | Type | InPatternAlternative /** We are elaborating the fully qualified name of a package clause. * In this case, identifiers should never be imported. diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 61c57858f450..36216adf06dd 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -936,10 +936,10 @@ class Namer { typer: Typer => } def typedAheadType(tree: Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree = - typedAheadImpl(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrType addMode Mode.Type)) + typedAheadImpl(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrTypeBits addMode Mode.Type)) def typedAheadExpr(tree: Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree = - typedAheadImpl(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrType)) + typedAheadImpl(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrTypeBits)) def typedAheadAnnotation(tree: Tree)(implicit ctx: Context): Symbol = tree match { case Apply(fn, _) => typedAheadAnnotation(fn) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index c4679416e53f..e8da2e58b628 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1210,13 +1210,19 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit tpd.cpy.UnApply(body1)(fn, Nil, typed(untpd.Bind(tree.name, untpd.TypedSplice(arg)).withPos(tree.pos), arg.tpe) :: Nil) case _ => - val sym = newPatternBoundSym(tree.name, body1.tpe, tree.pos) - assignType(cpy.Bind(tree)(tree.name, body1), sym) + if (tree.name == nme.WILDCARD) body1 + else { + val sym = newPatternBoundSym(tree.name, body1.tpe, tree.pos) + if (ctx.mode.is(Mode.InPatternAlternative)) + ctx.error(i"Illegal variable ${sym.name} in pattern alternative", tree.pos) + assignType(cpy.Bind(tree)(tree.name, body1), sym) + } } } def typedAlternative(tree: untpd.Alternative, pt: Type)(implicit ctx: Context): Alternative = track("typedAlternative") { - val trees1 = tree.trees mapconserve (typed(_, pt)) + val nestedCtx = ctx.addMode(Mode.InPatternAlternative) + val trees1 = tree.trees.mapconserve(typed(_, pt)(nestedCtx)) assignType(cpy.Alternative(tree)(trees1), trees1) } @@ -1754,7 +1760,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit Inliner.removeInlineAccessors(mdef.symbol) def typedExpr(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = - typed(tree, pt)(ctx retractMode Mode.PatternOrType) + typed(tree, pt)(ctx retractMode Mode.PatternOrTypeBits) def typedType(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = // todo: retract mode between Type and Pattern? typed(tree, pt)(ctx addMode Mode.Type) def typedPattern(tree: untpd.Tree, selType: Type = WildcardType)(implicit ctx: Context): Tree = diff --git a/tests/neg/i3332.scala b/tests/neg/i3332.scala new file mode 100644 index 000000000000..e2964a22050e --- /dev/null +++ b/tests/neg/i3332.scala @@ -0,0 +1,21 @@ +object Main { + def main(args: Array[String]): Unit = { + (1: Any) match { + case x: String | Int => "OK" // error: Illegal variable in pattern alternative + case (_: String) | (_: Int) => "OK" + case (s: String) | _: Int => s // error: Illegal variable in pattern alternative + } + } +} + +// #1612 +object Test { + case class A() + def g(p:(Int,Int)) = p match { + case (10,n) | (n,10) => println(n) // error // error (Illegal variable in pattern alternative) + case _ => println("nope") + } + def test(x: Any) = x match { + case _: String | _ @ A() => 1 + } +}