Skip to content

Commit 819487c

Browse files
committed
Fix subtyping flexible type with type parameters
1 parent a8ed1de commit 819487c

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
@@ -755,8 +754,6 @@ object Types {
755754
case d: ClassDenotation => d.findMember(name, pre, required, excluded)
756755
case d => go(d.info)
757756
}
758-
case tp: FlexibleType =>
759-
go(tp.underlying)
760757
case tp: AppliedType =>
761758
tp.tycon match {
762759
case tc: TypeRef =>
@@ -976,8 +973,6 @@ object Types {
976973
if (keepOnly(pre, tp.refinedName)) ns + tp.refinedName else ns
977974
case tp: TypeProxy =>
978975
tp.superType.memberNames(keepOnly, pre)
979-
case tp: FlexibleType =>
980-
tp.underlying.memberNames(keepOnly, pre)
981976
case tp: AndType =>
982977
tp.tp1.memberNames(keepOnly, pre) | tp.tp2.memberNames(keepOnly, pre)
983978
case tp: OrType =>
@@ -1435,7 +1430,6 @@ object Types {
14351430
case tp: ExprType => tp.resType.atoms
14361431
case tp: OrType => tp.atoms // `atoms` overridden in OrType
14371432
case tp: AndType => tp.tp1.atoms & tp.tp2.atoms
1438-
case tp: FlexibleType => tp.underlying.atoms
14391433
case tp: TypeRef if tp.symbol.is(ModuleClass) =>
14401434
// The atom of a module class is the module itself,
14411435
// this corresponds to the special case in TypeComparer
@@ -3414,26 +3408,30 @@ object Types {
34143408
* in Kotlin. A FlexibleType(T) generally behaves like an abstract type with bad bounds
34153409
* T|Null .. T, so that T|Null <: FlexibleType(T) <: T.
34163410
*/
3417-
case class FlexibleType(underlying: Type, lo: Type, hi: Type) extends CachedGroundType with ValueType {
3418-
def derivedFlexibleType(underlying: Type)(using Context): Type =
3419-
if this.underlying eq underlying then this else FlexibleType(underlying)
3411+
case class FlexibleType(original: Type, lo: Type, hi: Type) extends CachedProxyType with ValueType {
3412+
def underlying(using Context): Type = original
34203413

3421-
override def computeHash(bs: Binders): Int = doHash(bs, underlying)
3414+
override def superType(using Context): Type = hi
34223415

3423-
override final def baseClasses(using Context): List[ClassSymbol] = underlying.baseClasses
3416+
def derivedFlexibleType(original: Type)(using Context): Type =
3417+
if this.original eq original then this else FlexibleType(original)
3418+
3419+
override def computeHash(bs: Binders): Int = doHash(bs, original)
3420+
3421+
override final def baseClasses(using Context): List[ClassSymbol] = original.baseClasses
34243422
}
34253423

34263424
object FlexibleType {
3427-
def apply(underlying: Type)(using Context): FlexibleType = underlying match {
3425+
def apply(original: Type)(using Context): FlexibleType = original match {
34283426
case ft: FlexibleType => ft
34293427
case _ =>
3430-
val hi = underlying.stripNull
3431-
val lo = if hi eq underlying then OrNull(hi) else underlying
3432-
new FlexibleType(underlying, lo, hi)
3428+
val hi = original.stripNull
3429+
val lo = if hi eq original then OrNull(hi) else original
3430+
new FlexibleType(original, lo, hi)
34333431
}
34343432

34353433
def unapply(tp: Type)(using Context): Option[Type] = tp match {
3436-
case ft: FlexibleType => Some(ft.underlying)
3434+
case ft: FlexibleType => Some(ft.original)
34373435
case _ => None
34383436
}
34393437
}
@@ -5680,6 +5678,7 @@ object Types {
56805678
val args1 = args.zipWithConserve(tparams):
56815679
case (arg @ TypeBounds(lo, hi), tparam) =>
56825680
boundFollowingVariance(lo, hi, tparam)
5681+
// TODO: why do we need this?
56835682
case (arg: FlexibleType, tparam) =>
56845683
boundFollowingVariance(arg.lo, arg.hi, tparam)
56855684
case (arg, _) => arg
@@ -5718,7 +5717,7 @@ object Types {
57185717
case tp: AnnotatedType =>
57195718
samClass(tp.underlying)
57205719
case tp: FlexibleType =>
5721-
samClass(tp.underlying)
5720+
samClass(tp.superType)
57225721
case _ =>
57235722
NoSymbol
57245723

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)