Skip to content

Commit a7a81d6

Browse files
authored
Merge pull request #8413 from dotty-staging/fix-#8404
Fix #8404: Use both scrutinee type and given type in pattern ascriptions
2 parents c474275 + 526670d commit a7a81d6

File tree

9 files changed

+40
-3
lines changed

9 files changed

+40
-3
lines changed

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,8 +1573,21 @@ class Typer extends Namer
15731573
// for a singleton pattern like `x @ Nil`, `x` should get the type from the scrutinee
15741574
// see tests/neg/i3200b.scala and SI-1503
15751575
val symTp =
1576-
if (body1.tpe.isInstanceOf[TermRef]) pt1
1577-
else body1.tpe.underlyingIfRepeated(isJava = false)
1576+
if body1.tpe.isInstanceOf[TermRef] then pt1
1577+
else if isWildcardStarArg(body1)
1578+
|| pt1 == defn.ImplicitScrutineeTypeRef
1579+
|| body1.tpe <:< pt // There is some strange interaction with gadt matching.
1580+
// and implicit scopes.
1581+
// run/t2755.scala fails to compile if this subtype test is omitted
1582+
// and the else clause is changed to `body1.tpe & pt1`. What
1583+
// happens is that we get either an Array[Float] or an Array[T]
1584+
// where T is GADT constrained to := Float. But the case body
1585+
// compiles only if the bound variable is Array[Float]. If
1586+
// it is Array[T] we get an implicit not found. To avoid fragility
1587+
// wrt to operand order for `&`, we include the explicit subtype test here.
1588+
// See also #5649.
1589+
then body1.tpe
1590+
else pt1 & body1.tpe
15781591
val sym = ctx.newPatternBoundSymbol(name, symTp, tree.span)
15791592
if (pt == defn.ImplicitScrutineeTypeRef || tree.mods.is(Given)) sym.setFlag(Given)
15801593
if (ctx.mode.is(Mode.InPatternAlternative))

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class CompilationTests extends ParallelTesting {
4444
compileFile("tests/pos-special/sourcepath/outer/nested/Test4.scala", defaultOptions.and("-sourcepath", "tests/pos-special/sourcepath")),
4545
compileFilesInDir("tests/pos-special/fatal-warnings", defaultOptions.and("-Xfatal-warnings", "-feature")),
4646
compileFilesInDir("tests/pos-special/spec-t5545", defaultOptions),
47-
compileFilesInDir("tests/pos-special/strawman-collections", defaultOptions),
47+
compileFilesInDir("tests/pos-special/strawman-collections", allowDeepSubtypes),
4848
compileFilesInDir("tests/pos-special/isInstanceOf", allowDeepSubtypes.and("-Xfatal-warnings")),
4949
compileFilesInDir("tests/new", defaultOptions),
5050
compileFilesInDir("tests/pos-scala2", scala2CompatMode),

tests/neg/i8338.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
object test {
2+
trait B {
3+
type X; def mkX(i: Int): B#X
4+
}
5+
val b: B = new B {
6+
type X = Int; def mkX(i: Int): X = i // error
7+
}
8+
}

tests/pos/i3208.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class Test {
2+
trait E
3+
trait Marker
4+
5+
def test(es: List[E]): List[E] = es.collect { case e: Marker => e }
6+
}
File renamed without changes.

tests/pos/i8404.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
trait ActorRefScope
2+
class ActorRef
3+
case class DeathWatchNotification(actor: ActorRef)
4+
object Main {
5+
val ref: ActorRef = ???
6+
ref match {
7+
case r: ActorRefScope => DeathWatchNotification(r)
8+
case _ =>
9+
}
10+
}
File renamed without changes.

0 commit comments

Comments
 (0)