Skip to content

Commit fd8ec1b

Browse files
committed
Better fix: skip bottom types in mapReduceOr
1 parent e65305d commit fd8ec1b

File tree

3 files changed

+77
-6
lines changed

3 files changed

+77
-6
lines changed

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

+8-6
Original file line numberDiff line numberDiff line change
@@ -459,9 +459,14 @@ object Types {
459459
case _ => f(this)
460460
}
461461

462-
/** Map function `f` over elements of an OrType, rebuilding with function `g` */
462+
/** Map function `f` over elements of an OrType, rebuilding with function `g`
463+
* Bottom types are skipped.
464+
*/
463465
final def mapReduceOr[T](f: Type => T)(g: (T, T) => T)(using Context): T = stripTypeVar match {
464-
case OrType(tp1, tp2) => g(tp1.mapReduceOr(f)(g), tp2.mapReduceOr(f)(g))
466+
case OrType(tp1, tp2) =>
467+
if tp1.isBottomType then tp2.mapReduceOr(f)(g)
468+
else if tp2.isBottomType then tp1.mapReduceOr(f)(g)
469+
else g(tp1.mapReduceOr(f)(g), tp2.mapReduceOr(f)(g))
465470
case _ => f(this)
466471
}
467472

@@ -3148,10 +3153,7 @@ object Types {
31483153
/** Replace or type by the closest non-or type above it */
31493154
def join(using Context): Type = {
31503155
if (myJoinPeriod != ctx.period) {
3151-
myJoin =
3152-
if tp1 frozen_<:< tp2 then tp2
3153-
else if tp2 frozen_<:< tp1 then tp1
3154-
else TypeOps.orDominator(this)
3156+
myJoin = TypeOps.orDominator(this)
31553157
core.println(i"join of $this == $myJoin")
31563158
assert(myJoin != this)
31573159
myJoinPeriod = ctx.period

tests/pos/i11968a.scala

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
2+
class A {
3+
def get(): Int = 0
4+
}
5+
6+
class B extends A {}
7+
8+
class C extends A {}
9+
10+
def test1 = {
11+
val s: String | Null = ???
12+
val l = s.length
13+
14+
val a: A | Null = new A
15+
a.get()
16+
17+
val bc: B | C = new B
18+
bc.get()
19+
20+
val bcn: B | (C | Null) = new C
21+
bcn.get()
22+
23+
val bnc: (B | Null) | C = null
24+
bnc.get()
25+
26+
val abcn: A | B | C | Null = new A
27+
abcn.get()
28+
}
29+
30+
def test2 = {
31+
val s: String | Nothing = ???
32+
val l = s.length
33+
34+
val a: A | Nothing = new A
35+
a.get()
36+
37+
val bc: B | C = new B
38+
bc.get()
39+
40+
val bcn: B | (C | Nothing) = new C
41+
bcn.get()
42+
43+
val bnc: (B | Nothing) | C = new B
44+
bnc.get()
45+
46+
val abcn: A | B | C | Nothing = new A
47+
abcn.get()
48+
}

tests/pos/i11981.scala

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
object Main:
2+
class Null
3+
type Optional[A] = A | Null
4+
5+
val maybeInt: Optional[Int] = 1
6+
7+
// simplest typeclass
8+
trait TC[F[_]]
9+
10+
// given instances for our Optional and standard Option[_]
11+
given g1: TC[Optional] = ???
12+
given g2: TC[Option] = ???
13+
14+
def summonTC[F[_], A](f: F[A])(using TC[F]): Unit = ???
15+
16+
summonTC(Option(42)) // OK
17+
18+
summonTC[Optional, Int](maybeInt) // OK
19+
20+
summonTC(maybeInt)
21+

0 commit comments

Comments
 (0)