Skip to content

Commit 640e6a0

Browse files
committed
Fix #10108: Keep an isSoft flag in OrTypes
It turned out that it's generally clear whether an OrType should be soft or hard, so this is a good first step to solve the problem.
1 parent 4cf3bf0 commit 640e6a0

File tree

9 files changed

+33
-27
lines changed

9 files changed

+33
-27
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ class Definitions {
440440
def AnyKindType: TypeRef = AnyKindClass.typeRef
441441

442442
@tu lazy val andType: TypeSymbol = enterBinaryAlias(tpnme.AND, AndType(_, _))
443-
@tu lazy val orType: TypeSymbol = enterBinaryAlias(tpnme.OR, OrType(_, _))
443+
@tu lazy val orType: TypeSymbol = enterBinaryAlias(tpnme.OR, OrType(_, _, soft = false))
444444

445445
/** Marker method to indicate an argument to a call-by-name parameter.
446446
* Created by byNameClosures and elimByName, eliminated by Erasure,

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ trait Hashable {
9393
protected final def doHash(bs: Binders, x1: Int, tp2: Type): Int =
9494
finishHash(bs, hashing.mix(hashSeed, x1), 1, tp2)
9595

96+
protected final def doHash(bs: Binders, x1: Int, tp2: Type, tp3: Type): Int =
97+
finishHash(bs, hashing.mix(hashSeed, x1), 1, tp2, tp3)
98+
9699
protected final def doHash(bs: Binders, tp1: Type, tp2: Type): Int =
97100
finishHash(bs, hashSeed, 0, tp1, tp2)
98101

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
616616
}
617617
}
618618
compareTypeLambda
619-
case OrType(tp21, tp22) =>
619+
case tp2 as OrType(tp21, tp22) =>
620620
compareAtoms(tp1, tp2) match
621621
case Some(b) => return b
622622
case _ =>
@@ -648,12 +648,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
648648
// solutions. The rewriting delays the point where we have to choose.
649649
tp21 match {
650650
case AndType(tp211, tp212) =>
651-
return recur(tp1, OrType(tp211, tp22)) && recur(tp1, OrType(tp212, tp22))
651+
return recur(tp1, OrType(tp211, tp22, tp2.isSoft)) && recur(tp1, OrType(tp212, tp22, tp2.isSoft))
652652
case _ =>
653653
}
654654
tp22 match {
655655
case AndType(tp221, tp222) =>
656-
return recur(tp1, OrType(tp21, tp221)) && recur(tp1, OrType(tp21, tp222))
656+
return recur(tp1, OrType(tp21, tp221, tp2.isSoft)) && recur(tp1, OrType(tp21, tp222, tp2.isSoft))
657657
case _ =>
658658
}
659659
either(recur(tp1, tp21), recur(tp1, tp22)) || fourthTry
@@ -2123,7 +2123,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
21232123
val t2 = distributeOr(tp2, tp1)
21242124
if (t2.exists) t2
21252125
else if (isErased) erasedLub(tp1, tp2)
2126-
else liftIfHK(tp1, tp2, OrType(_, _), _ | _, _ & _)
2126+
else liftIfHK(tp1, tp2, OrType(_, _, soft = true), _ | _, _ & _)
21272127
}
21282128
}
21292129

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

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,7 +1040,7 @@ object Types {
10401040
def safe_& (that: Type)(using Context): Type = (this, that) match {
10411041
case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) =>
10421042
TypeBounds(
1043-
OrType.makeHk(lo1.stripLazyRef, lo2.stripLazyRef),
1043+
OrType.makeHk(lo1.stripLazyRef, lo2.stripLazyRef),
10441044
AndType.makeHk(hi1.stripLazyRef, hi2.stripLazyRef))
10451045
case _ =>
10461046
this & that
@@ -2917,8 +2917,9 @@ object Types {
29172917

29182918
def derivedAndOrType(tp1: Type, tp2: Type)(using Context) =
29192919
if ((tp1 eq this.tp1) && (tp2 eq this.tp2)) this
2920-
else if (isAnd) AndType.make(tp1, tp2, checkValid = true)
2921-
else OrType.make(tp1, tp2)
2920+
else this match
2921+
case tp: OrType => OrType.make(tp1, tp2, tp.isSoft)
2922+
case tp: AndType => AndType.make(tp1, tp2, checkValid = true)
29222923
}
29232924

29242925
abstract case class AndType(tp1: Type, tp2: Type) extends AndOrType {
@@ -2992,6 +2993,7 @@ object Types {
29922993

29932994
abstract case class OrType(tp1: Type, tp2: Type) extends AndOrType {
29942995
def isAnd: Boolean = false
2996+
def isSoft: Boolean
29952997
private var myBaseClassesPeriod: Period = Nowhere
29962998
private var myBaseClasses: List[ClassSymbol] = _
29972999
/** Base classes of are the intersection of the operand base classes. */
@@ -3054,30 +3056,31 @@ object Types {
30543056

30553057
def derivedOrType(tp1: Type, tp2: Type)(using Context): Type =
30563058
if ((tp1 eq this.tp1) && (tp2 eq this.tp2)) this
3057-
else OrType.make(tp1, tp2)
3059+
else OrType.make(tp1, tp2, isSoft)
30583060

3059-
override def computeHash(bs: Binders): Int = doHash(bs, tp1, tp2)
3061+
override def computeHash(bs: Binders): Int =
3062+
doHash(bs, if isSoft then 0 else 1, tp1, tp2)
30603063

30613064
override def eql(that: Type): Boolean = that match {
3062-
case that: OrType => tp1.eq(that.tp1) && tp2.eq(that.tp2)
3065+
case that: OrType => tp1.eq(that.tp1) && tp2.eq(that.tp2) && isSoft == that.isSoft
30633066
case _ => false
30643067
}
30653068
}
30663069

3067-
final class CachedOrType(tp1: Type, tp2: Type) extends OrType(tp1, tp2)
3070+
final class CachedOrType(tp1: Type, tp2: Type, override val isSoft: Boolean) extends OrType(tp1, tp2)
30683071

30693072
object OrType {
3070-
def apply(tp1: Type, tp2: Type)(using Context): OrType = {
3073+
def apply(tp1: Type, tp2: Type, soft: Boolean)(using Context): OrType = {
30713074
assertUnerased()
3072-
unique(new CachedOrType(tp1, tp2))
3075+
unique(new CachedOrType(tp1, tp2, soft))
30733076
}
3074-
def make(tp1: Type, tp2: Type)(using Context): Type =
3077+
def make(tp1: Type, tp2: Type, soft: Boolean)(using Context): Type =
30753078
if (tp1 eq tp2) tp1
3076-
else apply(tp1, tp2)
3079+
else apply(tp1, tp2, soft)
30773080

30783081
/** Like `make`, but also supports higher-kinded types as argument */
30793082
def makeHk(tp1: Type, tp2: Type)(using Context): Type =
3080-
TypeComparer.liftIfHK(tp1, tp2, OrType(_, _), makeHk, _ & _)
3083+
TypeComparer.liftIfHK(tp1, tp2, OrType(_, _, soft = true), makeHk, _ & _)
30813084
}
30823085

30833086
/** An extractor object to pattern match against a nullable union.
@@ -3089,7 +3092,7 @@ object Types {
30893092
*/
30903093
object OrNull {
30913094
def apply(tp: Type)(using Context) =
3092-
OrType(tp, defn.NullType)
3095+
OrType(tp, defn.NullType, soft = false)
30933096
def unapply(tp: Type)(using Context): Option[Type] =
30943097
if (ctx.explicitNulls) {
30953098
val tp1 = tp.stripNull()
@@ -3107,7 +3110,7 @@ object Types {
31073110
*/
31083111
object OrUncheckedNull {
31093112
def apply(tp: Type)(using Context) =
3110-
OrType(tp, defn.UncheckedNullAliasType)
3113+
OrType(tp, defn.UncheckedNullAliasType, soft = false)
31113114
def unapply(tp: Type)(using Context): Option[Type] =
31123115
if (ctx.explicitNulls) {
31133116
val tp1 = tp.stripUncheckedNull

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ class TreeUnpickler(reader: TastyReader,
368368
case ANDtype =>
369369
AndType(readType(), readType())
370370
case ORtype =>
371-
OrType(readType(), readType())
371+
OrType(readType(), readType(), soft = false)
372372
case SUPERtype =>
373373
SuperType(readType(), readType())
374374
case MATCHtype =>
@@ -1222,7 +1222,7 @@ class TreeUnpickler(reader: TastyReader,
12221222
val args = until(end)(readTpt())
12231223
val ownType =
12241224
if (tycon.symbol == defn.andType) AndType(args(0).tpe, args(1).tpe)
1225-
else if (tycon.symbol == defn.orType) OrType(args(0).tpe, args(1).tpe)
1225+
else if (tycon.symbol == defn.orType) OrType(args(0).tpe, args(1).tpe, soft = false)
12261226
else tycon.tpe.safeAppliedTo(args.tpes)
12271227
untpd.AppliedTypeTree(tycon, args).withType(ownType)
12281228
case ANNOTATEDtpt =>

compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1823,7 +1823,7 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext:
18231823
end OrTypeTypeTest
18241824

18251825
object OrType extends OrTypeModule:
1826-
def apply(lhs: TypeRepr, rhs: TypeRepr): OrType = Types.OrType(lhs, rhs)
1826+
def apply(lhs: TypeRepr, rhs: TypeRepr): OrType = Types.OrType(lhs, rhs, soft = false)
18271827
def unapply(x: OrType): Option[(TypeRepr, TypeRepr)] = Some((x.left, x.right))
18281828
end OrType
18291829

compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ object TypeTestsCasts {
7171
case tref: TypeRef if tref.typeSymbol.isPatternBound =>
7272
if (variance == 1) tref.info.hiBound
7373
else if (variance == -1) tref.info.loBound
74-
else OrType(defn.AnyType, defn.NothingType)
74+
else OrType(defn.AnyType, defn.NothingType, soft = true)
7575
case _ => mapOver(tp)
7676
}
7777
}.apply(tp)

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -477,8 +477,8 @@ class SpaceEngine(using Context) extends SpaceLogic {
477477
else args.map(arg => erase(arg, inArray = false))
478478
tp.derivedAppliedType(erase(tycon, inArray), args2)
479479

480-
case OrType(tp1, tp2) =>
481-
OrType(erase(tp1, inArray), erase(tp2, inArray))
480+
case tp as OrType(tp1, tp2) =>
481+
OrType(erase(tp1, inArray), erase(tp2, inArray), tp.isSoft)
482482

483483
case AndType(tp1, tp2) =>
484484
AndType(erase(tp1, inArray), erase(tp2, inArray))
@@ -862,7 +862,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
862862
if (ctx.explicitNulls || selTyp.classSymbol.isPrimitiveValueClass)
863863
project(selTyp)
864864
else
865-
project(OrType(selTyp, constantNullType))
865+
project(OrType(selTyp, constantNullType, soft = false))
866866

867867
// in redundancy check, take guard as false in order to soundly approximate
868868
def projectPrevCases(cases: List[CaseDef]): Space =

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ trait TypeAssigner {
463463
val ownType =
464464
if (sameLength(tparams, args))
465465
if (tycon.symbol == defn.andType) AndType(args(0).tpe, args(1).tpe)
466-
else if (tycon.symbol == defn.orType) OrType(args(0).tpe, args(1).tpe)
466+
else if (tycon.symbol == defn.orType) OrType(args(0).tpe, args(1).tpe, soft = false)
467467
else tycon.tpe.appliedTo(args.tpes)
468468
else wrongNumberOfTypeArgs(tycon.tpe, tparams, args, tree.srcPos)
469469
tree.withType(ownType)

0 commit comments

Comments
 (0)