Skip to content

Commit 30e842f

Browse files
dwijnandWojciechMazur
authored andcommitted
Fix a bundle of patmat issues
Some of the issues are legitimate
1 parent a3ceec3 commit 30e842f

File tree

13 files changed

+158
-6
lines changed

13 files changed

+158
-6
lines changed

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -537,8 +537,7 @@ object SpaceEngine {
537537
// force type inference to infer a narrower type: could be singleton
538538
// see tests/patmat/i4227.scala
539539
mt.paramInfos(0) <:< scrutineeTp
540-
instantiateSelected(mt, tvars)
541-
isFullyDefined(mt, ForceDegree.all)
540+
maximizeType(mt.paramInfos(0), Spans.NoSpan)
542541
mt
543542
}
544543

@@ -552,7 +551,7 @@ object SpaceEngine {
552551
// Case unapplySeq:
553552
// 1. return the type `List[T]` where `T` is the element type of the unapplySeq return type `Seq[T]`
554553

555-
val resTp = ctx.typeAssigner.safeSubstMethodParams(mt, scrutineeTp :: Nil).finalResultType
554+
val resTp = wildApprox(ctx.typeAssigner.safeSubstMethodParams(mt, scrutineeTp :: Nil).finalResultType)
556555

557556
val sig =
558557
if (resTp.isRef(defn.BooleanClass))
@@ -573,14 +572,14 @@ object SpaceEngine {
573572
if (arity > 0)
574573
productSelectorTypes(resTp, unappSym.srcPos)
575574
else {
576-
val getTp = resTp.select(nme.get).finalResultType.widenTermRefExpr
575+
val getTp = extractorMemberType(resTp, nme.get, unappSym.srcPos)
577576
if (argLen == 1) getTp :: Nil
578577
else productSelectorTypes(getTp, unappSym.srcPos)
579578
}
580579
}
581580
}
582581

583-
sig.map(_.annotatedToRepeated)
582+
sig.map { case tp: WildcardType => tp.bounds.hi case tp => tp }
584583
}
585584

586585
/** Whether the extractor covers the given type */
@@ -625,7 +624,21 @@ object SpaceEngine {
625624
// For instance, from i15029, `decompose((X | Y).Field[T]) = [X.Field[T], Y.Field[T]]`.
626625
parts.map(tp.derivedAppliedType(_, targs))
627626

628-
case tp if tp.isDecomposableToChildren =>
627+
case tpOriginal if tpOriginal.isDecomposableToChildren =>
628+
// isDecomposableToChildren uses .classSymbol.is(Sealed)
629+
// But that classSymbol could be from an AppliedType
630+
// where the type constructor is a non-class type
631+
// E.g. t11620 where `?1.AA[X]` returns as "sealed"
632+
// but using that we're not going to infer A1[X] and A2[X]
633+
// but end up with A1[<?>] and A2[<?>].
634+
// So we widen (like AppliedType superType does) away
635+
// non-class type constructors.
636+
def getAppliedClass(tp: Type): Type = tp match
637+
case tp @ AppliedType(_: HKTypeLambda, _) => tp
638+
case tp @ AppliedType(tycon: TypeRef, _) if tycon.symbol.isClass => tp
639+
case tp @ AppliedType(tycon: TypeProxy, _) => getAppliedClass(tycon.superType.applyIfParameterized(tp.args))
640+
case tp => tp
641+
val tp = getAppliedClass(tpOriginal)
629642
def getChildren(sym: Symbol): List[Symbol] =
630643
sym.children.flatMap { child =>
631644
if child eq sym then List(sym) // i3145: sealed trait Baz, val x = new Baz {}, Baz.children returns Baz...

tests/warn/i20121.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
sealed trait T_A[A, B]
2+
type X = T_A[Byte, Byte]
3+
4+
case class CC_B[A](a: A) extends T_A[A, X]
5+
6+
val v_a: T_A[X, X] = CC_B(null)
7+
val v_b = v_a match
8+
case CC_B(_) => 0 // warn: unreachable
9+
case _ => 1
10+
// for CC_B[A] to match T_A[X, X]
11+
// A := X
12+
// so require X, aka T_A[Byte, Byte]
13+
// which isn't instantiable, outside of null

tests/warn/i20122.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
sealed trait T_B[C, D]
2+
3+
case class CC_A()
4+
case class CC_B[A, C](a: A) extends T_B[C, CC_A]
5+
case class CC_C[C, D](a: T_B[C, D]) extends T_B[Int, CC_A]
6+
case class CC_E(a: CC_C[Char, Byte])
7+
8+
val v_a: T_B[Int, CC_A] = CC_B(CC_E(CC_C(null)))
9+
val v_b = v_a match
10+
case CC_B(CC_E(CC_C(_))) => 0 // warn: unreachable
11+
case _ => 1
12+
// for CC_B[A, C] to match T_B[C, CC_A]
13+
// C <: Int, ok
14+
// A <: CC_E, ok
15+
// but you need a CC_C[Char, Byte]
16+
// which requires a T_B[Char, Byte]
17+
// which isn't instantiable, outside of null

tests/warn/i20123.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
sealed trait T_A[A, B]
2+
sealed trait T_B[C]
3+
4+
case class CC_D[A, C]() extends T_A[A, C]
5+
case class CC_E() extends T_B[Nothing]
6+
case class CC_G[A, C](c: C) extends T_A[A, C]
7+
8+
val v_a: T_A[Boolean, T_B[Boolean]] = CC_G(null)
9+
val v_b = v_a match {
10+
case CC_D() => 0
11+
case CC_G(_) => 1 // warn: unreachable
12+
// for CC_G[A, C] to match T_A[Boolean, T_B[Boolean]]
13+
// A := Boolean, which is ok
14+
// C := T_B[Boolean],
15+
// which isn't instantiable, outside of null
16+
}

tests/warn/i20128.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
sealed trait T_A[A]
2+
case class CC_B[A](a: T_A[A]) extends T_A[Byte]
3+
case class CC_E[A](b: T_A[A]) extends T_A[Byte]
4+
5+
val v_a: T_A[Byte] = CC_E(CC_B(null))
6+
val v_b: Int = v_a match { // warn: not exhaustive
7+
case CC_E(CC_E(_)) => 0
8+
case CC_B(_) => 1
9+
}

tests/warn/i20129.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
sealed trait T_A[A]
2+
case class CC_B[A](a: T_A[A], c: T_A[A]) extends T_A[Char]
3+
case class CC_C[A]() extends T_A[A]
4+
case class CC_G() extends T_A[Char]
5+
6+
val v_a: T_A[Char] = CC_B(CC_G(), CC_C())
7+
val v_b: Int = v_a match { // warn: not exhaustive
8+
case CC_C() => 0
9+
case CC_G() => 1
10+
case CC_B(CC_B(_, _), CC_C()) => 2
11+
case CC_B(CC_C(), CC_C()) => 3
12+
case CC_B(_, CC_G()) => 4
13+
case CC_B(_, CC_B(_, _)) => 5
14+
}

tests/warn/i20130.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
sealed trait T_A[B]
2+
sealed trait T_B[C]
3+
case class CC_B[C]() extends T_A[T_B[C]]
4+
case class CC_C[B, C](c: T_A[B], d: T_B[C]) extends T_B[C]
5+
case class CC_E[C]() extends T_B[C]
6+
7+
val v_a: T_B[Int] = CC_C(null, CC_E())
8+
val v_b: Int = v_a match { // warn: not exhaustive
9+
case CC_C(_, CC_C(_, _)) => 0
10+
case CC_E() => 5
11+
}

tests/warn/i20131.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
sealed trait Foo
2+
case class Foo1() extends Foo
3+
case class Foo2[A, B]() extends Foo
4+
5+
sealed trait Bar[A, B]
6+
case class Bar1[A, C, D](a: Bar[C, D]) extends Bar[A, Bar[C, D]]
7+
case class Bar2[ C, D](b: Bar[C, D], c: Foo) extends Bar[Bar1[Int, Byte, Int], Bar[C, D]]
8+
9+
class Test:
10+
def m1(bar: Bar[Bar1[Int, Byte, Int], Bar[Char, Char]]): Int = bar match
11+
case Bar1(_) => 0
12+
case Bar2(_, Foo2()) => 1
13+
def t1 = m1(Bar2(null, Foo1()))
14+
// for Bar2[C, D] to match the scrutinee
15+
// C := Char and D := Char
16+
// which requires a Bar[Char, Char]
17+
// which isn't instantiable, outside of null

tests/warn/i20132.alt.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
sealed trait Foo[A]
2+
case class Bar[C](x: Foo[C]) extends Foo[C]
3+
case class End[B]() extends Foo[B]
4+
class Test:
5+
def m1[M](foo: Foo[M]): Int = foo match // warn: not exhaustive
6+
case End() => 0
7+
case Bar(End()) => 1
8+
def t1 = m1[Int](Bar[Int](Bar[Int](End[Int]())))

tests/warn/i20132.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
sealed trait Foo[A]
2+
case class Bar[C](x: Foo[C]) extends Foo[Int]
3+
case class End[B]() extends Foo[B]
4+
class Test:
5+
def m1[M](foo: Foo[M]): Int = foo match // warn: not exhaustive
6+
case End() => 0
7+
case Bar(End()) => 1
8+
def t1 = m1[Int](Bar[Int](Bar[Int](End[Int]())))

tests/warn/i20132.wo.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
sealed trait Foo[A]
2+
case class Bar[C](x: Foo[C]) extends Foo[Int]
3+
case class End[B]() extends Foo[B]
4+
class Test:
5+
def m1[M](foo: Foo[M]): Int = foo match
6+
case End() => 0
7+
case Bar(_) => 1
8+
def t1 = m1[Int](Bar[Int](Bar[Int](End[Int]())))

tests/warn/i5422.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
sealed trait Foo[A[_]]
2+
3+
case class Bar[C[_], X](x: C[X]) extends Foo[C]
4+
case class End[B[_]]() extends Foo[B]
5+
6+
class Test:
7+
def foo[M[_]](foo: Foo[M]): Int = foo match
8+
case End() => 0
9+
case Bar(_) => 1

tests/warn/t11620.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
sealed trait A[+T0]
2+
case class A1[+T1](t1: T1) extends A[T1]
3+
case class A2[+T2](t2: T2) extends A[T2]
4+
sealed trait B[+T3] { type AA[+U] <: A[U] ; def a: AA[T3] }
5+
object B { def unapply[T4](b: B[T4]): Some[b.AA[T4]] = Some(b.a) }
6+
class Test:
7+
def m1[X](b: B[X]): X = b match
8+
case B(A1(v1)) => v1
9+
case B(A2(v2)) => v2

0 commit comments

Comments
 (0)