diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 877630d4913e..7626ce6d55f1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1718,10 +1718,16 @@ class Typer extends Namer } if (name == nme.WILDCARD) body1 else { - // for a singleton pattern like `x @ Nil`, `x` should get the type from the scrutinee - // see tests/neg/i3200b.scala and SI-1503 + // In `x @ Nil`, `Nil` is a _stable identifier pattern_ and will be compiled + // to an `==` test, so the type of `x` is unrelated to the type of `Nil`. + // Similarly, in `x @ 1`, `1` is a _literal pattern_ and will also be compiled + // to an `==` test. + // See i3200*.scala and https://github.com/scala/bug/issues/1503. + val isStableIdentifierOrLiteral = + body1.isInstanceOf[RefTree] && !isWildcardArg(body1) + || body1.isInstanceOf[Literal] val symTp = - if body1.tpe.isInstanceOf[TermRef] then pt + if isStableIdentifierOrLiteral then pt else if isWildcardStarArg(body1) || pt == defn.ImplicitScrutineeTypeRef || body1.tpe <:< pt // There is some strange interaction with gadt matching. diff --git a/tests/neg/i3200b.scala b/tests/neg/i3200b.scala index 522f4e3d63ea..51de3e3964b8 100644 --- a/tests/neg/i3200b.scala +++ b/tests/neg/i3200b.scala @@ -1,5 +1,8 @@ object Test { def main(args: Array[String]): Unit = { - val a : Nil.type = (Vector(): Any) match { case n @ Nil => n } // error + val a: Nil.type = (Vector(): Any) match { case n @ Nil => n } // error + val b: Nil.type = (Vector(): Any) match { case n @ (m @ Nil) => n } // error + val c: Int = (1.0: Any) match { case n @ 1 => n } // error + val d: Int = (1.0: Any) match { case n @ (m @ 1) => n } // error } } diff --git a/tests/run/i3200c.scala b/tests/run/i3200c.scala new file mode 100644 index 000000000000..796e49a1040f --- /dev/null +++ b/tests/run/i3200c.scala @@ -0,0 +1,28 @@ +sealed trait X +case object Y extends X + +object Test { + def yIs1(proof: Y.type): Int = 1 + + def test(x: X) = x match { + case y: Y.type => yIs1(y) + } + + def test2(x: X) = x match { + case y @ (yy: Y.type) => + yIs1(y) + yIs1(yy) + } + + def main(args: Array[String]): Unit = { + test(Y) + + val a: Nil.type = (Vector(): Any) match { + case n: Nil.type => + assert(false, "should not be reached") + n + case _ => + Nil + } + } +}