Skip to content

Commit 6466611

Browse files
Merge pull request #8137 from dotty-staging/fix-#8129
Fix #8129: Refine atoms computation
2 parents 1897ce3 + 63a9142 commit 6466611

File tree

4 files changed

+29
-16
lines changed

4 files changed

+29
-16
lines changed

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,9 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
440440
(tp1.widenSingletons ne tp1) &&
441441
recur(tp1.widenSingletons, tp2)
442442

443-
if (tp2.atoms.nonEmpty && canCompare(tp2.atoms))
444-
tp1.atoms.nonEmpty && tp1.atoms.subsetOf(tp2.atoms)
443+
if (tp2.atoms().nonEmpty && canCompare(tp2.atoms()))
444+
val atoms1 = tp1.atoms(widenOK = true)
445+
atoms1.nonEmpty && atoms1.subsetOf(tp2.atoms())
445446
else
446447
widenOK
447448
|| joinOK
@@ -612,8 +613,9 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
612613
}
613614
compareTypeLambda
614615
case OrType(tp21, tp22) =>
615-
if (tp2.atoms.nonEmpty && canCompare(tp2.atoms))
616-
return tp1.atoms.nonEmpty && tp1.atoms.subsetOf(tp2.atoms) || isSubType(tp1, NothingType)
616+
if (tp2.atoms().nonEmpty && canCompare(tp2.atoms()))
617+
val atoms1 = tp1.atoms(widenOK = true)
618+
return atoms1.nonEmpty && atoms1.subsetOf(tp2.atoms()) || isSubType(tp1, NothingType)
617619

618620
// The next clause handles a situation like the one encountered in i2745.scala.
619621
// We have:
@@ -1777,9 +1779,9 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
17771779
else if tp2.isAny && !tp1.isLambdaSub || tp2.isAnyKind || tp1.isRef(NothingClass) then tp2
17781780
else {
17791781
def mergedLub: Type = {
1780-
val atoms1 = tp1.atoms
1782+
val atoms1 = tp1.atoms(widenOK = true)
17811783
if (atoms1.nonEmpty && !widenInUnions) {
1782-
val atoms2 = tp2.atoms
1784+
val atoms2 = tp2.atoms(widenOK = true)
17831785
if (atoms2.nonEmpty) {
17841786
if (atoms1.subsetOf(atoms2)) return tp2
17851787
if (atoms2.subsetOf(atoms1)) return tp1

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

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,8 +1164,10 @@ object Types {
11641164
/** If this type is an alias of a disjunction of stable singleton types,
11651165
* these types as a set, otherwise the empty set.
11661166
* Overridden and cached in OrType.
1167+
* @param widenOK If type proxies that are upperbounded by types with atoms
1168+
* have the same atoms.
11671169
*/
1168-
def atoms(implicit ctx: Context): Set[Type] = dealias match {
1170+
def atoms(widenOK: Boolean = false)(implicit ctx: Context): Set[Type] = dealias match {
11691171
case tp: SingletonType =>
11701172
def normalize(tp: Type): Type = tp match {
11711173
case tp: SingletonType =>
@@ -1179,12 +1181,13 @@ object Types {
11791181
}
11801182
case _ => tp
11811183
}
1182-
val underlyingAtoms = tp.underlying.atoms
1184+
val underlyingAtoms = tp.underlying.atoms(widenOK)
11831185
if (underlyingAtoms.isEmpty && tp.isStable) Set.empty + normalize(tp)
11841186
else underlyingAtoms
1185-
case tp: ExprType => tp.resType.atoms
1186-
case tp: OrType => tp.atoms // `atoms` overridden in OrType
1187-
case tp: AndType => tp.tp1.atoms & tp.tp2.atoms
1187+
case tp: ExprType => tp.resType.atoms(widenOK)
1188+
case tp: OrType => tp.atoms(widenOK) // `atoms` overridden in OrType
1189+
case tp: AndType => tp.tp1.atoms(widenOK) & tp.tp2.atoms(widenOK)
1190+
case tp: TypeProxy if widenOK => tp.underlying.atoms(widenOK)
11881191
case _ => Set.empty
11891192
}
11901193

@@ -2902,22 +2905,26 @@ object Types {
29022905

29032906
private var atomsRunId: RunId = NoRunId
29042907
private var myAtoms: Set[Type] = _
2908+
private var myWidenedAtoms: Set[Type] = _
29052909
private var myWidened: Type = _
29062910

29072911
private def ensureAtomsComputed()(implicit ctx: Context): Unit =
29082912
if (atomsRunId != ctx.runId) {
2909-
val atoms1 = tp1.atoms
2910-
val atoms2 = tp2.atoms
2913+
val atoms1 = tp1.atoms()
2914+
val atoms2 = tp2.atoms()
29112915
myAtoms = if (atoms1.nonEmpty && atoms2.nonEmpty) atoms1 | atoms2 else Set.empty
2916+
val widenedAtoms1 = tp1.atoms(widenOK = true)
2917+
val widenedAtoms2 = tp2.atoms(widenOK = true)
2918+
myWidenedAtoms = if (widenedAtoms1.nonEmpty && widenedAtoms2.nonEmpty) widenedAtoms1 | widenedAtoms2 else Set.empty
29122919
val tp1w = tp1.widenSingletons
29132920
val tp2w = tp2.widenSingletons
29142921
myWidened = if ((tp1 eq tp1w) && (tp2 eq tp2w)) this else tp1w | tp2w
29152922
atomsRunId = ctx.runId
29162923
}
29172924

2918-
override def atoms(implicit ctx: Context): Set[Type] = {
2925+
override def atoms(widenOK: Boolean)(implicit ctx: Context): Set[Type] = {
29192926
ensureAtomsComputed()
2920-
myAtoms
2927+
if widenOK then myAtoms else myWidenedAtoms
29212928
}
29222929

29232930
override def widenSingletons(implicit ctx: Context): Type = {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ object ErrorReporting {
118118
else if (ctx.settings.explainTypes.value)
119119
i"""
120120
|${ctx.typerState.constraint}
121-
|${TypeComparer.explained((found <:< expected)(_))}"""
121+
|${TypeComparer.explained(found <:< expected)}"""
122122
else
123123
""
124124
}

tests/pos/i8129.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
object Test {
2+
type F[N <: 0 | 1] = N
3+
def fl[N <: 0 | 1]: F[N] = ???
4+
}

0 commit comments

Comments
 (0)