Skip to content

Commit b0a3ed0

Browse files
committed
Fix #8404: Use both scrutinee type and given type in pattern ascriptions
In a pattern ascription `x: T` type `x` to have the intersection of the given type `T` and the scrutinee type. This matches scalac's behavior. It now makes i5418.scala compile. The type intersection was enough to make that one compile, it did not need unsound covariant GADT matching (which was what I claimed before in the issue).
1 parent c6b681c commit b0a3ed0

File tree

7 files changed

+25
-3
lines changed

7 files changed

+25
-3
lines changed

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,8 +1573,20 @@ 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+
then body1.tpe
1589+
else pt1 & body1.tpe
15781590
val sym = ctx.newPatternBoundSymbol(name, symTp, tree.span)
15791591
if (pt == defn.ImplicitScrutineeTypeRef || tree.mods.is(Given)) sym.setFlag(Given)
15801592
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),
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)