Skip to content

Commit

Permalink
Fix subtyping flexible type with type parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
noti0na1 committed Oct 4, 2023
1 parent 5ecea8c commit 45f56cb
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 28 deletions.
16 changes: 8 additions & 8 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,6 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
case OrType(tp21, tp22) =>
if (tp21.stripTypeVar eq tp22.stripTypeVar) recur(tp1, tp21)
else secondTry
// tp1 <: Flex(T) = T|N..T
// iff tp1 <: T|N
case tp2: FlexibleType =>
recur(tp1, tp2.lo)
case TypeErasure.ErasedValueType(tycon1, underlying2) =>
def compareErasedValueType = tp1 match {
case TypeErasure.ErasedValueType(tycon2, underlying1) =>
Expand Down Expand Up @@ -542,10 +538,6 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
hardenTypeVars(tp2)

res
// invariant: tp2 is NOT a FlexibleType
// is Flex(T) <: tp2?
case tp1: FlexibleType =>
recur(tp1.hi, tp2)
case CapturingType(parent1, refs1) =>
if tp2.isAny then true
else if subCaptures(refs1, tp2.captureSet, frozenConstraint).isOK && sameBoxed(tp1, tp2, refs1)
Expand Down Expand Up @@ -887,6 +879,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
false
}
compareClassInfo
// tp1 <: Flex(T) = T|N..T
// iff tp1 <: T|N
case tp2: FlexibleType =>
recur(tp1, tp2.lo)
case _ =>
fourthTry
}
Expand Down Expand Up @@ -1078,6 +1074,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
case tp1: ExprType if ctx.phaseId > gettersPhase.id =>
// getters might have converted T to => T, need to compensate.
recur(tp1.widenExpr, tp2)
// invariant: tp2 is NOT a FlexibleType
// is Flex(T) <: tp2?
case tp1: FlexibleType =>
recur(tp1.hi, tp2)
case _ =>
false
}
Expand Down
35 changes: 17 additions & 18 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,6 @@ object Types {
tp.bound.derivesFrom(cls) || tp.reduced.derivesFrom(cls)
case tp: TypeProxy =>
loop(tp.underlying)
case tp: FlexibleType =>
loop(tp.underlying)
case tp: AndType =>
loop(tp.tp1) || loop(tp.tp2)
case tp: OrType =>
Expand Down Expand Up @@ -346,6 +344,7 @@ object Types {
/** Is this type guaranteed not to have `null` as a value? */
final def isNotNull(using Context): Boolean = this match {
case tp: ConstantType => tp.value.value != null
case tp: FlexibleType => false
case tp: ClassInfo => !tp.cls.isNullableClass && tp.cls != defn.NothingClass
case tp: AppliedType => tp.superType.isNotNull
case tp: TypeBounds => tp.lo.isNotNull
Expand Down Expand Up @@ -749,8 +748,6 @@ object Types {
case d: ClassDenotation => d.findMember(name, pre, required, excluded)
case d => go(d.info)
}
case tp: FlexibleType =>
go(tp.underlying)
case tp: AppliedType =>
tp.tycon match {
case tc: TypeRef =>
Expand Down Expand Up @@ -970,8 +967,6 @@ object Types {
if (keepOnly(pre, tp.refinedName)) ns + tp.refinedName else ns
case tp: TypeProxy =>
tp.superType.memberNames(keepOnly, pre)
case tp: FlexibleType =>
tp.underlying.memberNames(keepOnly, pre)
case tp: AndType =>
tp.tp1.memberNames(keepOnly, pre) | tp.tp2.memberNames(keepOnly, pre)
case tp: OrType =>
Expand Down Expand Up @@ -1429,7 +1424,6 @@ object Types {
case tp: ExprType => tp.resType.atoms
case tp: OrType => tp.atoms // `atoms` overridden in OrType
case tp: AndType => tp.tp1.atoms & tp.tp2.atoms
case tp: FlexibleType => tp.underlying.atoms
case tp: TypeRef if tp.symbol.is(ModuleClass) =>
// The atom of a module class is the module itself,
// this corresponds to the special case in TypeComparer
Expand Down Expand Up @@ -3408,26 +3402,30 @@ object Types {
* in Kotlin. A FlexibleType(T) generally behaves like an abstract type with bad bounds
* T|Null .. T, so that T|Null <: FlexibleType(T) <: T.
*/
case class FlexibleType(underlying: Type, lo: Type, hi: Type) extends CachedGroundType with ValueType {
def derivedFlexibleType(underlying: Type)(using Context): Type =
if this.underlying eq underlying then this else FlexibleType(underlying)
case class FlexibleType(original: Type, lo: Type, hi: Type) extends CachedProxyType with ValueType {
def underlying(using Context): Type = original

override def computeHash(bs: Binders): Int = doHash(bs, underlying)
override def superType(using Context): Type = hi

override final def baseClasses(using Context): List[ClassSymbol] = underlying.baseClasses
def derivedFlexibleType(original: Type)(using Context): Type =
if this.original eq original then this else FlexibleType(original)

override def computeHash(bs: Binders): Int = doHash(bs, original)

override final def baseClasses(using Context): List[ClassSymbol] = original.baseClasses
}

object FlexibleType {
def apply(underlying: Type)(using Context): FlexibleType = underlying match {
def apply(original: Type)(using Context): FlexibleType = original match {
case ft: FlexibleType => ft
case _ =>
val hi = underlying.stripNull
val lo = if hi eq underlying then OrNull(hi) else underlying
new FlexibleType(underlying, lo, hi)
val hi = original.stripNull
val lo = if hi eq original then OrNull(hi) else original
new FlexibleType(original, lo, hi)
}

def unapply(tp: Type)(using Context): Option[Type] = tp match {
case ft: FlexibleType => Some(ft.underlying)
case ft: FlexibleType => Some(ft.original)
case _ => None
}
}
Expand Down Expand Up @@ -5671,6 +5669,7 @@ object Types {
val args1 = args.zipWithConserve(tparams):
case (arg @ TypeBounds(lo, hi), tparam) =>
boundFollowingVariance(lo, hi, tparam)
// TODO: why do we need this?
case (arg: FlexibleType, tparam) =>
boundFollowingVariance(arg.lo, arg.hi, tparam)
case (arg, _) => arg
Expand Down Expand Up @@ -5709,7 +5708,7 @@ object Types {
case tp: AnnotatedType =>
samClass(tp.underlying)
case tp: FlexibleType =>
samClass(tp.underlying)
samClass(tp.superType)
case _ =>
NoSymbol

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ object Scala2Erasure:
tpw
else
sym
case tpw: FlexibleType =>
pseudoSymbol(tpw.underlying)
case tpw: TypeProxy =>
pseudoSymbol(tpw.underlying)
case tpw: JavaArrayType =>
Expand Down

0 comments on commit 45f56cb

Please sign in to comment.