Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #19907: Skip soft unions in widenSingle of widenInferred #19995

Merged
merged 4 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 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 we widenUnion on soft unions is independent of whether singletons
// are widened or not. This avoids an expensive subtype check in widenSingle,
// see 19907_*.scala for test cases.
noti0na1 marked this conversation as resolved.
Show resolved Hide resolved
tp.widenSingletons()
noti0na1 marked this conversation as resolved.
Show resolved Hide resolved
else if tpw <:< bound then tpw
else tp
else tp
else tp.hardenUnions

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

def isSingleton(tp: Type): Boolean = tp match
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