Skip to content

Commit 67835c3

Browse files
authored
Merge pull request #11083 from dotty-staging/fix-#11003
Improve handling of disjunctions when comparing types
2 parents ce82cfb + 6724900 commit 67835c3

File tree

5 files changed

+31
-13
lines changed

5 files changed

+31
-13
lines changed

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

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
166166
try op finally frozenGadt = savedFrozenGadt
167167
}
168168

169+
private inline def inFrozenGadtAndConstraint[T](inline op: T): T =
170+
inFrozenGadtIf(true)(inFrozenConstraint(op))
171+
169172
protected def isSubType(tp1: Type, tp2: Type, a: ApproxState): Boolean = {
170173
val savedApprox = approx
171174
val savedLeftRoot = leftRoot
@@ -432,25 +435,18 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
432435
case Some(b) => return b
433436
case None =>
434437

435-
/** `recur` shouldn't normally be used with approximated types, according to its
436-
* documentation. In the specific examples where this function is
437-
* called, it is sound to do so as long as we freeze GADTs.
438-
*/
439-
def recurInFrozenGadt(tp1: Type, tp2: Type) =
440-
inFrozenGadt { recur(tp1, tp2) }
441-
442438
def widenOK =
443439
(tp2.widenSingletons eq tp2)
444440
&& (tp1.widenSingletons ne tp1)
445-
&& recurInFrozenGadt(tp1.widenSingletons, tp2)
441+
&& inFrozenGadtAndConstraint(recur(tp1.widenSingletons, tp2))
446442

447443
def joinOK = tp2.dealiasKeepRefiningAnnots match {
448444
case tp2: AppliedType if !tp2.tycon.typeSymbol.isClass =>
449445
// If we apply the default algorithm for `A[X] | B[Y] <: C[Z]` where `C` is a
450446
// type parameter, we will instantiate `C` to `A` and then fail when comparing
451447
// with `B[Y]`. To do the right thing, we need to instantiate `C` to the
452448
// common superclass of `A` and `B`.
453-
recurInFrozenGadt(tp1.join, tp2)
449+
inFrozenGadtAndConstraint(recur(tp1.join, tp2))
454450
case _ =>
455451
false
456452
}
@@ -477,7 +473,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
477473
widenOK
478474
|| joinOK
479475
|| (tp1.isSoft || constrainRHSVars(tp2)) && recur(tp11, tp2) && recur(tp12, tp2)
480-
|| containsAnd(tp1) && recurInFrozenGadt(tp1.join, tp2)
476+
|| containsAnd(tp1) && inFrozenGadt(recur(tp1.join, tp2))
481477
case tp1: MatchType =>
482478
val reduced = tp1.reduced
483479
if (reduced.exists) recur(reduced, tp2) else thirdTry

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3124,7 +3124,10 @@ object Types {
31243124

31253125
private def ensureAtomsComputed()(using Context): Unit =
31263126
if atomsRunId != ctx.runId then
3127-
myAtoms = tp1.atoms | tp2.atoms
3127+
myAtoms =
3128+
if tp1.hasClassSymbol(defn.NothingClass) then tp2.atoms
3129+
else if tp2.hasClassSymbol(defn.NothingClass) then tp1.atoms
3130+
else tp1.atoms | tp2.atoms
31283131
val tp1w = tp1.widenSingletons
31293132
val tp2w = tp2.widenSingletons
31303133
myWidened = if ((tp1 eq tp1w) && (tp2 eq tp2w)) this else tp1w | tp2w

scala3doc/test/dotty/dokka/SourceLinksTests.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ class SourceLinksTest:
6969
case (path: String, line: Int) => links.pathTo(projectRoot.resolve(path), line = Some(line))
7070
case (path: String, operation: Operation) => links.pathTo(projectRoot.resolve(path), operation = operation)
7171
case (path: String, line: Int, operation: Operation) => links.pathTo(projectRoot.resolve(path), operation = operation, line = Some(line))
72-
case _ => ??? // needed due to handling of singleton types inside union types
7372

7473
val expectedRes = expected match
7574
case s: String => Some(s)

tests/neg/singletonOrs.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ object Get2As1 {
2424
def get2as11X:V = tuToV()(2) // error
2525
}
2626
class Or11Nothing extends Or11X[Nothing]
27-
def get2as1:1 = new Or11Nothing().get2as11X // error
27+
def get2as1:1 = new Or11Nothing().get2as11X // ok
2828

2929
def main(a:Array[String]) = {
3030
println(get2as1) // prints 2

tests/pos/i11003.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
object Foo
2+
3+
val x: Foo.type = Foo
4+
val y: Foo.type | Nothing = x
5+
val z: Foo.type = y
6+
val a: 1 | Nothing = 1
7+
val b: 1 = a
8+
9+
val intSuper = summon[(Int | Nothing) <:< Int]
10+
val intSub = summon[Int <:< (Int | Nothing)]
11+
val intEq = summon[Int =:= (Int | Nothing)]
12+
13+
val fooSuper = summon[(Foo.type | Nothing) <:< Foo.type]
14+
val fooSub = summon[Foo.type <:< (Foo.type | Nothing)]
15+
val fooEq = summon[Foo.type =:= (Foo.type | Nothing)]
16+
17+
val oneSuper = summon[(1 | Nothing) <:< 1]
18+
val oneSub = summon[1 <:< (1 | Nothing)]
19+
val oneEq = summon[1 =:= (1 | Nothing)]
20+

0 commit comments

Comments
 (0)