Skip to content

Commit 45f56cb

Browse files
committed
Fix subtyping flexible type with type parameters
1 parent 5ecea8c commit 45f56cb

File tree

3 files changed

+25
-28
lines changed

3 files changed

+25
-28
lines changed

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -390,10 +390,6 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
390390
case OrType(tp21, tp22) =>
391391
if (tp21.stripTypeVar eq tp22.stripTypeVar) recur(tp1, tp21)
392392
else secondTry
393-
// tp1 <: Flex(T) = T|N..T
394-
// iff tp1 <: T|N
395-
case tp2: FlexibleType =>
396-
recur(tp1, tp2.lo)
397393
case TypeErasure.ErasedValueType(tycon1, underlying2) =>
398394
def compareErasedValueType = tp1 match {
399395
case TypeErasure.ErasedValueType(tycon2, underlying1) =>
@@ -542,10 +538,6 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
542538
hardenTypeVars(tp2)
543539

544540
res
545-
// invariant: tp2 is NOT a FlexibleType
546-
// is Flex(T) <: tp2?
547-
case tp1: FlexibleType =>
548-
recur(tp1.hi, tp2)
549541
case CapturingType(parent1, refs1) =>
550542
if tp2.isAny then true
551543
else if subCaptures(refs1, tp2.captureSet, frozenConstraint).isOK && sameBoxed(tp1, tp2, refs1)
@@ -887,6 +879,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
887879
false
888880
}
889881
compareClassInfo
882+
// tp1 <: Flex(T) = T|N..T
883+
// iff tp1 <: T|N
884+
case tp2: FlexibleType =>
885+
recur(tp1, tp2.lo)
890886
case _ =>
891887
fourthTry
892888
}
@@ -1078,6 +1074,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
10781074
case tp1: ExprType if ctx.phaseId > gettersPhase.id =>
10791075
// getters might have converted T to => T, need to compensate.
10801076
recur(tp1.widenExpr, tp2)
1077+
// invariant: tp2 is NOT a FlexibleType
1078+
// is Flex(T) <: tp2?
1079+
case tp1: FlexibleType =>
1080+
recur(tp1.hi, tp2)
10811081
case _ =>
10821082
false
10831083
}

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

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,6 @@ object Types {
282282
tp.bound.derivesFrom(cls) || tp.reduced.derivesFrom(cls)
283283
case tp: TypeProxy =>
284284
loop(tp.underlying)
285-
case tp: FlexibleType =>
286-
loop(tp.underlying)
287285
case tp: AndType =>
288286
loop(tp.tp1) || loop(tp.tp2)
289287
case tp: OrType =>
@@ -346,6 +344,7 @@ object Types {
346344
/** Is this type guaranteed not to have `null` as a value? */
347345
final def isNotNull(using Context): Boolean = this match {
348346
case tp: ConstantType => tp.value.value != null
347+
case tp: FlexibleType => false
349348
case tp: ClassInfo => !tp.cls.isNullableClass && tp.cls != defn.NothingClass
350349
case tp: AppliedType => tp.superType.isNotNull
351350
case tp: TypeBounds => tp.lo.isNotNull
@@ -749,8 +748,6 @@ object Types {
749748
case d: ClassDenotation => d.findMember(name, pre, required, excluded)
750749
case d => go(d.info)
751750
}
752-
case tp: FlexibleType =>
753-
go(tp.underlying)
754751
case tp: AppliedType =>
755752
tp.tycon match {
756753
case tc: TypeRef =>
@@ -970,8 +967,6 @@ object Types {
970967
if (keepOnly(pre, tp.refinedName)) ns + tp.refinedName else ns
971968
case tp: TypeProxy =>
972969
tp.superType.memberNames(keepOnly, pre)
973-
case tp: FlexibleType =>
974-
tp.underlying.memberNames(keepOnly, pre)
975970
case tp: AndType =>
976971
tp.tp1.memberNames(keepOnly, pre) | tp.tp2.memberNames(keepOnly, pre)
977972
case tp: OrType =>
@@ -1429,7 +1424,6 @@ object Types {
14291424
case tp: ExprType => tp.resType.atoms
14301425
case tp: OrType => tp.atoms // `atoms` overridden in OrType
14311426
case tp: AndType => tp.tp1.atoms & tp.tp2.atoms
1432-
case tp: FlexibleType => tp.underlying.atoms
14331427
case tp: TypeRef if tp.symbol.is(ModuleClass) =>
14341428
// The atom of a module class is the module itself,
14351429
// this corresponds to the special case in TypeComparer
@@ -3408,26 +3402,30 @@ object Types {
34083402
* in Kotlin. A FlexibleType(T) generally behaves like an abstract type with bad bounds
34093403
* T|Null .. T, so that T|Null <: FlexibleType(T) <: T.
34103404
*/
3411-
case class FlexibleType(underlying: Type, lo: Type, hi: Type) extends CachedGroundType with ValueType {
3412-
def derivedFlexibleType(underlying: Type)(using Context): Type =
3413-
if this.underlying eq underlying then this else FlexibleType(underlying)
3405+
case class FlexibleType(original: Type, lo: Type, hi: Type) extends CachedProxyType with ValueType {
3406+
def underlying(using Context): Type = original
34143407

3415-
override def computeHash(bs: Binders): Int = doHash(bs, underlying)
3408+
override def superType(using Context): Type = hi
34163409

3417-
override final def baseClasses(using Context): List[ClassSymbol] = underlying.baseClasses
3410+
def derivedFlexibleType(original: Type)(using Context): Type =
3411+
if this.original eq original then this else FlexibleType(original)
3412+
3413+
override def computeHash(bs: Binders): Int = doHash(bs, original)
3414+
3415+
override final def baseClasses(using Context): List[ClassSymbol] = original.baseClasses
34183416
}
34193417

34203418
object FlexibleType {
3421-
def apply(underlying: Type)(using Context): FlexibleType = underlying match {
3419+
def apply(original: Type)(using Context): FlexibleType = original match {
34223420
case ft: FlexibleType => ft
34233421
case _ =>
3424-
val hi = underlying.stripNull
3425-
val lo = if hi eq underlying then OrNull(hi) else underlying
3426-
new FlexibleType(underlying, lo, hi)
3422+
val hi = original.stripNull
3423+
val lo = if hi eq original then OrNull(hi) else original
3424+
new FlexibleType(original, lo, hi)
34273425
}
34283426

34293427
def unapply(tp: Type)(using Context): Option[Type] = tp match {
3430-
case ft: FlexibleType => Some(ft.underlying)
3428+
case ft: FlexibleType => Some(ft.original)
34313429
case _ => None
34323430
}
34333431
}
@@ -5671,6 +5669,7 @@ object Types {
56715669
val args1 = args.zipWithConserve(tparams):
56725670
case (arg @ TypeBounds(lo, hi), tparam) =>
56735671
boundFollowingVariance(lo, hi, tparam)
5672+
// TODO: why do we need this?
56745673
case (arg: FlexibleType, tparam) =>
56755674
boundFollowingVariance(arg.lo, arg.hi, tparam)
56765675
case (arg, _) => arg
@@ -5709,7 +5708,7 @@ object Types {
57095708
case tp: AnnotatedType =>
57105709
samClass(tp.underlying)
57115710
case tp: FlexibleType =>
5712-
samClass(tp.underlying)
5711+
samClass(tp.superType)
57135712
case _ =>
57145713
NoSymbol
57155714

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Erasure.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ object Scala2Erasure:
8888
tpw
8989
else
9090
sym
91-
case tpw: FlexibleType =>
92-
pseudoSymbol(tpw.underlying)
9391
case tpw: TypeProxy =>
9492
pseudoSymbol(tpw.underlying)
9593
case tpw: JavaArrayType =>

0 commit comments

Comments
 (0)