Skip to content

Commit

Permalink
Fix #19907: Skip soft unions in widenSingle of widenInferred (#19995)
Browse files Browse the repository at this point in the history
Fix #19907: Skip soft unions in widenSingle of widenInferred
  • Loading branch information
noti0na1 authored Mar 25, 2024
2 parents 7171211 + fd61afb commit 198750b
Show file tree
Hide file tree
Showing 6 changed files with 2,199 additions and 14 deletions.
17 changes: 13 additions & 4 deletions compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
Original file line number Diff line number Diff line change
Expand Up @@ -651,11 +651,20 @@ trait ConstraintHandling {
def widenOr(tp: Type) =
if widenUnions then
val tpw = tp.widenUnion
if (tpw ne tp) && !tpw.isTransparent() && (tpw <:< bound) then tpw else tp
if tpw ne tp then
if tpw.isTransparent() then
// Now also widen singletons of soft unions. Before these were skipped
// since widenUnion on soft unions is independent of whether singletons
// are widened or not. This avoids an expensive subtype check in widenSingle,
// see i19907_*.scala for test cases.
widenSingle(tp, skipSoftUnions = false)
else if tpw <:< bound then tpw
else tp
else tp
else tp.hardenUnions

def widenSingle(tp: Type) =
val tpw = tp.widenSingletons
def widenSingle(tp: Type, skipSoftUnions: Boolean) =
val tpw = tp.widenSingletons(skipSoftUnions)
if (tpw ne tp) && (tpw <:< bound) then tpw else tp

def isSingleton(tp: Type): Boolean = tp match
Expand All @@ -665,7 +674,7 @@ trait ConstraintHandling {
val wideInst =
if isSingleton(bound) then inst
else
val widenedFromSingle = widenSingle(inst)
val widenedFromSingle = widenSingle(inst, skipSoftUnions = widenUnions)
val widenedFromUnion = widenOr(widenedFromSingle)
val widened = dropTransparentTraits(widenedFromUnion, bound)
widenIrreducible(widened)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
def widenOK =
(tp2.widenSingletons eq tp2)
&& (tp1.widenSingletons ne tp1)
&& inFrozenGadtAndConstraint(recur(tp1.widenSingletons, tp2))
&& inFrozenGadtAndConstraint(recur(tp1.widenSingletons(), tp2))

def joinOK = tp2.dealiasKeepRefiningAnnots match {
case tp2: AppliedType if !tp2.tycon.typeSymbol.isClass =>
Expand Down
20 changes: 11 additions & 9 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1377,15 +1377,15 @@ object Types extends TypeUtils {
* and going to the operands of & and |.
* Overridden and cached in OrType.
*/
def widenSingletons(using Context): Type = dealias match {
def widenSingletons(skipSoftUnions: Boolean = false)(using Context): Type = dealias match {
case tp: SingletonType =>
tp.widen
case tp: OrType =>
val tp1w = tp.widenSingletons
val tp1w = tp.widenSingletons(skipSoftUnions)
if (tp1w eq tp) this else tp1w
case tp: AndType =>
val tp1w = tp.tp1.widenSingletons
val tp2w = tp.tp2.widenSingletons
val tp1w = tp.tp1.widenSingletons(skipSoftUnions)
val tp2w = tp.tp2.widenSingletons(skipSoftUnions)
if ((tp.tp1 eq tp1w) && (tp.tp2 eq tp2w)) this else tp1w & tp2w
case _ =>
this
Expand Down Expand Up @@ -3619,8 +3619,8 @@ object Types extends TypeUtils {
else tp1n.atoms | tp2n.atoms

private def computeWidenSingletons()(using Context): Type =
val tp1w = tp1.widenSingletons
val tp2w = tp2.widenSingletons
val tp1w = tp1.widenSingletons()
val tp2w = tp2.widenSingletons()
if ((tp1 eq tp1w) && (tp2 eq tp2w)) this else TypeComparer.lub(tp1w, tp2w, isSoft = isSoft)

private def ensureAtomsComputed()(using Context): Unit =
Expand All @@ -3633,9 +3633,11 @@ object Types extends TypeUtils {
ensureAtomsComputed()
myAtoms

override def widenSingletons(using Context): Type =
ensureAtomsComputed()
myWidened
override def widenSingletons(skipSoftUnions: Boolean)(using Context): Type =
if isSoft && skipSoftUnions then this
else
ensureAtomsComputed()
myWidened

def derivedOrType(tp1: Type, tp2: Type, soft: Boolean = isSoft)(using Context): Type =
if ((tp1 eq this.tp1) && (tp2 eq this.tp2) && soft == isSoft) this
Expand Down
Loading

0 comments on commit 198750b

Please sign in to comment.