Skip to content

Commit ca488f5

Browse files
1 parent 19b4216 commit ca488f5

File tree

5 files changed

+134
-16
lines changed

5 files changed

+134
-16
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,6 +2136,20 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
21362136
/** Returns last check's debug mode, if explicitly enabled. */
21372137
def lastTrace(): String = ""
21382138

2139+
/** Is `tp` an empty type?
2140+
*
2141+
* `true` implies that we found a proof; uncertainty default to `false`.
2142+
*/
2143+
def provablyEmpty(tp: Type): Boolean =
2144+
tp.dealias match {
2145+
case tp if tp.isBottomType => true
2146+
case AndType(tp1, tp2) => disjoint(tp1, tp2)
2147+
case OrType(tp1, tp2) => provablyEmpty(tp1) && provablyEmpty(tp2)
2148+
case tp: RefinedType => provablyEmpty(tp.parent)
2149+
case tp: TypeRef => provablyEmpty(tp.prefix)
2150+
case _ => false
2151+
}
2152+
21392153
/** Are `tp1` and `tp2` disjoint types?
21402154
*
21412155
* `true` implies that we found a proof; uncertainty default to `false`.
@@ -2419,6 +2433,7 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
24192433
}.apply(tp)
24202434

24212435
val defn.MatchCase(pat, body) = cas1
2436+
24222437
if (isSubType(scrut, pat))
24232438
// `scrut` is a subtype of `pat`: *It's a Match!*
24242439
Some {
@@ -2433,7 +2448,7 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
24332448
else if (isSubType(widenAbstractTypes(scrut), widenAbstractTypes(pat)))
24342449
Some(NoType)
24352450
else if (disjoint(scrut, pat))
2436-
// We found a proof that `scrut` and `pat` are incompatible.
2451+
// We found a proof that `scrut` and `pat` are incompatible.
24372452
// The search continues.
24382453
None
24392454
else
@@ -2445,7 +2460,10 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
24452460
case Nil => NoType
24462461
}
24472462

2448-
inFrozenConstraint(recur(cases))
2463+
if (provablyEmpty(scrut))
2464+
NoType
2465+
else
2466+
inFrozenConstraint(recur(cases))
24492467
}
24502468
}
24512469

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

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -527,17 +527,8 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
527527
val sym1 = if (sym.is(ModuleClass)) sym.sourceModule else sym
528528
val refined = ctx.refineUsingParent(tp, sym1)
529529

530-
def inhabited(tp: Type): Boolean =
531-
tp.dealias match {
532-
case AndType(tp1, tp2) => !ctx.typeComparer.disjoint(tp1, tp2)
533-
case OrType(tp1, tp2) => inhabited(tp1) || inhabited(tp2)
534-
case tp: RefinedType => inhabited(tp.parent)
535-
case tp: TypeRef => inhabited(tp.prefix)
536-
case _ => true
537-
}
538-
539-
if (inhabited(refined)) refined
540-
else NoType
530+
if (ctx.typeComparer.provablyEmpty(refined)) NoType
531+
else refined
541532
} filter(_.exists)
542533

543534
debug.println(s"${tp.show} decomposes to [${parts.map(_.show).mkString(", ")}]")

tests/neg/6314-1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ object G {
1818
}
1919

2020
def main(args: Array[String]): Unit = {
21-
val a: Bar[X & Y] = "hello"
21+
val a: Bar[X & Y] = "hello" // error
2222
val i: Bar[Y & Foo] = Foo.apply[Bar](a)
2323
val b: Int = i // error
2424
println(b + 1)

tests/neg/6314-2.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ object G {
1212
case Y => Int
1313
}
1414

15-
val a: Bar[X & Foo] = "hello"
15+
val a: Bar[X & Foo] = "hello" // error
1616
val b: Bar[Y & Foo] = 1 // error
1717

1818
def main(args: Array[String]): Unit = {
19-
val a: Bar[X & Foo] = "hello"
19+
val a: Bar[X & Foo] = "hello" // error
2020
val i: Bar[Y & Foo] = Foo.apply[Bar](a)
2121
val b: Int = i // error
2222
println(b + 1)

tests/neg/6570.scala

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
object Base {
2+
trait Trait1
3+
trait Trait2
4+
type N[t] = t match {
5+
case String => Trait1
6+
case Int => Trait2
7+
}
8+
}
9+
import Base._
10+
11+
object UpperBoundParametricVariant {
12+
trait Cov[+T]
13+
type M[t] = t match {
14+
case Cov[x] => N[x]
15+
}
16+
17+
trait Root[A] {
18+
def thing: M[A]
19+
}
20+
21+
trait Child[A <: Cov[Int]] extends Root[A]
22+
23+
// we reduce `M[T]` to `Trait2`, even though we cannot be certain of that
24+
def foo[T <: Cov[Int]](c: Child[T]): Trait2 = c.thing
25+
26+
class Asploder extends Child[Cov[String & Int]] {
27+
def thing = new Trait1 {} // error
28+
}
29+
30+
def explode = foo(new Asploder) // ClassCastException
31+
}
32+
33+
object InheritanceVariant {
34+
// allows binding a variable to the UB of a type member
35+
type Trick[a] = { type A <: a }
36+
type M[t] = t match { case Trick[a] => N[a] }
37+
38+
trait Root {
39+
type B
40+
def thing: M[B]
41+
}
42+
43+
trait Child extends Root { type B <: { type A <: Int } }
44+
45+
def foo(c: Child): Trait2 = c.thing
46+
47+
class Asploder extends Child {
48+
type B = { type A = String & Int }
49+
def thing = new Trait1 {} // error
50+
}
51+
}
52+
53+
object ThisTypeVariant {
54+
type Trick[a] = { type A <: a }
55+
type M[t] = t match { case Trick[a] => N[a] }
56+
57+
trait Root {
58+
def thing: M[this.type]
59+
}
60+
61+
trait Child extends Root { type A <: Int }
62+
63+
def foo(c: Child): Trait2 = c.thing
64+
65+
class Asploder extends Child {
66+
type A = String & Int
67+
def thing = new Trait1 {} // error
68+
}
69+
}
70+
71+
object ParametricVariant {
72+
type Trick[a] = { type A <: a }
73+
type M[t] = t match { case Trick[a] => N[a] }
74+
75+
trait Root[B] {
76+
def thing: M[B]
77+
}
78+
79+
trait Child[B <: { type A <: Int }] extends Root[B]
80+
81+
def foo[T <: { type A <: Int }](c: Child[T]): Trait2 = c.thing
82+
83+
class Asploder extends Child[{ type A = String & Int }] {
84+
def thing = new Trait1 {} // error
85+
}
86+
87+
def explode = foo(new Asploder)
88+
}
89+
90+
object UpperBoundVariant {
91+
trait Cov[+T]
92+
type M[t] = t match { case Cov[t] => N[t] }
93+
94+
trait Root {
95+
type A
96+
def thing: M[A]
97+
}
98+
99+
trait Child extends Root { type A <: Cov[Int] }
100+
101+
def foo(c: Child): Trait2 = c.thing
102+
103+
class Asploder extends Child {
104+
type A = Cov[String & Int]
105+
def thing = new Trait1 {} // error
106+
}
107+
108+
def explode = foo(new Asploder)
109+
}

0 commit comments

Comments
 (0)