Skip to content

Commit ee5b3ac

Browse files
committed
Simplify instantiateToSubType
1 parent 0a76dcf commit ee5b3ac

File tree

2 files changed

+34
-48
lines changed

2 files changed

+34
-48
lines changed

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

Lines changed: 32 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -659,42 +659,38 @@ object TypeOps:
659659
*/
660660
private def instantiateToSubType(tp1: NamedType, tp2: Type)(using Context): Type = {
661661
/** expose abstract type references to their bounds or tvars according to variance */
662-
class AbstractTypeMap(maximize: Boolean)(using Context) extends TypeMap {
663-
def expose(lo: Type, hi: Type): Type =
664-
if (variance == 0)
665-
newTypeVar(TypeBounds(lo, hi))
666-
else if (variance == 1)
667-
if (maximize) hi else lo
668-
else
669-
if (maximize) lo else hi
662+
class ApproximateTypeParams(using Context) extends TypeMap {
663+
val boundTypeParams = util.HashMap[TypeRef, TypeVar]()
670664

671-
def apply(tp: Type): Type = tp match {
665+
def apply(tp: Type): Type = tp.dealias match {
672666
case _: MatchType =>
673667
tp // break cycles
674668

675-
case tp: TypeRef if isBounds(tp.underlying) =>
676-
val lo = this(tp.info.loBound)
677-
val hi = this(tp.info.hiBound)
678-
// See tests/patmat/gadt.scala tests/patmat/exhausting.scala tests/patmat/t9657.scala
679-
val exposed = expose(lo, hi)
680-
typr.println(s"$tp exposed to =====> $exposed")
681-
exposed
682-
683-
case AppliedType(tycon: TypeRef, args) if isBounds(tycon.underlying) =>
684-
val args2 = args.map(this)
685-
val lo = this(tycon.info.loBound).applyIfParameterized(args2)
686-
val hi = this(tycon.info.hiBound).applyIfParameterized(args2)
687-
val exposed = expose(lo, hi)
688-
typr.println(s"$tp exposed to =====> $exposed")
689-
exposed
669+
case tp: TypeRef if !tp.symbol.isClass =>
670+
def lo = apply(tp.underlying.loBound)
671+
def hi = apply(tp.underlying.hiBound)
672+
boundTypeParams.getOrElseUpdate(tp, newTypeVar(TypeBounds(lo, hi)))
673+
674+
case AppliedType(tycon: TypeRef, _) if !tycon.dealias.typeSymbol.isClass =>
675+
// Type inference cannot handle X[Y] <:< Int
676+
// See tests/patmat/i3645g.scala
677+
val bounds: TypeBounds = tycon.underlying match {
678+
case TypeBounds(tl1: HKTypeLambda, tl2: HKTypeLambda) =>
679+
TypeBounds(tl1.resType, tl2.resType)
680+
case TypeBounds(tl1: HKTypeLambda, tp2) =>
681+
TypeBounds(tl1.resType, tp2)
682+
case TypeBounds(tp1, tl2: HKTypeLambda) =>
683+
TypeBounds(tp1, tl2.resType)
684+
}
685+
686+
newTypeVar(bounds)
690687

691-
case _ =>
688+
case tp =>
692689
mapOver(tp)
693690
}
694691
}
695692

696-
def minTypeMap(using Context) = new AbstractTypeMap(maximize = false)
697-
def maxTypeMap(using Context) = new AbstractTypeMap(maximize = true)
693+
def approximateTypeParams(tp: Type)(using Context) = new ApproximateTypeParams().apply(tp)
698694

699695
// Prefix inference, replace `p.C.this.Child` with `X.Child` where `X <: p.C`
700696
// Note: we need to strip ThisType in `p` recursively.
@@ -721,37 +717,25 @@ object TypeOps:
721717
val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds) }
722718
val protoTp1 = inferThisMap.apply(tp1).appliedTo(tvars)
723719

724-
val force = new ForceDegree.Value(
725-
tvar =>
726-
!(ctx.typerState.constraint.entry(tvar.origin) `eq` tvar.origin.underlying) ||
727-
(tvar `eq` inferThisMap.prefixTVar), // always instantiate prefix
728-
IfBottom.flip
729-
)
730-
731720
// If parent contains a reference to an abstract type, then we should
732721
// refine subtype checking to eliminate abstract types according to
733722
// variance. As this logic is only needed in exhaustivity check,
734723
// we manually patch subtyping check instead of changing TypeComparer.
735-
// See tests/patmat/i3645b.scala
736-
def parentQualify = tp1.widen.classSymbol.info.parents.exists { parent =>
737-
inContext(ctx.fresh.setNewTyperState()) {
738-
parent.argInfos.nonEmpty && minTypeMap.apply(parent) <:< maxTypeMap.apply(tp2)
739-
}
724+
// See tests/patmat/3645b.scala
725+
def parentQualify(tp1: Type, tp2: Type) = tp1.widen.classSymbol.info.parents.exists { parent =>
726+
parent.argInfos.nonEmpty && approximateTypeParams(parent) <:< tp2
740727
}
741728

742-
if (protoTp1 <:< tp2) {
729+
def instantiate(): Type = {
743730
maximizeType(protoTp1, NoSpan, fromScala2x = false)
744731
wildApprox(protoTp1)
745732
}
733+
734+
if (protoTp1 <:< tp2) instantiate()
746735
else {
747-
val protoTp2 = maxTypeMap.apply(tp2)
748-
if (protoTp1 <:< protoTp2 || parentQualify)
749-
if (isFullyDefined(AndType(protoTp1, protoTp2), force)) protoTp1
750-
else wildApprox(protoTp1)
751-
else {
752-
typr.println(s"$protoTp1 <:< $protoTp2 = false")
753-
NoType
754-
}
736+
val protoTp2 = approximateTypeParams(tp2)
737+
if (protoTp1 <:< protoTp2 || parentQualify(protoTp1, protoTp2)) instantiate()
738+
else NoType
755739
}
756740
}
757741

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,8 @@ class SpaceEngine(using Context) extends SpaceLogic {
623623
val sym1 = if (sym.is(ModuleClass)) sym.sourceModule else sym
624624
val refined = TypeOps.refineUsingParent(tp, sym1)
625625

626+
debug.println(sym1.show + " refined to " + refined.show)
627+
626628
def inhabited(tp: Type): Boolean =
627629
tp.dealias match {
628630
case AndType(tp1, tp2) => !TypeComparer.provablyDisjoint(tp1, tp2)

0 commit comments

Comments
 (0)