Skip to content

Commit 777bfaf

Browse files
committed
Move deskolemization from TypeComparer to TypeOps
It's no longer needed in TypeComparer. We now deskolemize when locally inferring types of vals and defs.
1 parent 9c3782c commit 777bfaf

File tree

2 files changed

+114
-16
lines changed

2 files changed

+114
-16
lines changed

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

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import scala.util.control.NonFatal
1616

1717
/** Provides methods to compare types.
1818
*/
19-
class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling with Skolemization {
19+
class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
2020
implicit val ctx: Context = initctx
2121

2222
val state = ctx.typerState
@@ -531,19 +531,16 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi
531531
* rebase both itself and the member info of `tp` on a freshly created skolem type.
532532
*/
533533
protected def hasMatchingMember(name: Name, tp1: Type, tp2: RefinedType): Boolean = {
534-
val saved = skolemsState
535-
if (skolemsState == Skolemization.SkolemsDisallowed) skolemsState = Skolemization.SkolemsAllowed
536-
try {
537-
val rebindNeeded = tp2.refinementRefersToThis
538-
val base = if (rebindNeeded) ensureStableSingleton(tp1) else tp1
539-
val rinfo2 = if (rebindNeeded) tp2.refinedInfo.substRefinedThis(tp2, base) else tp2.refinedInfo
540-
def qualifies(m: SingleDenotation) = isSubType(m.info, rinfo2)
541-
def memberMatches(mbr: Denotation): Boolean = mbr match { // inlined hasAltWith for performance
542-
case mbr: SingleDenotation => qualifies(mbr)
543-
case _ => mbr hasAltWith qualifies
544-
}
545-
/*>|>*/ ctx.traceIndented(i"hasMatchingMember($base . $name :? ${tp2.refinedInfo}) ${base.member(name).info.show} $rinfo2", subtyping) /*<|<*/ {
546-
memberMatches(base member name) ||
534+
val rebindNeeded = tp2.refinementRefersToThis
535+
val base = if (rebindNeeded) ensureStableSingleton(tp1) else tp1
536+
val rinfo2 = if (rebindNeeded) tp2.refinedInfo.substRefinedThis(tp2, base) else tp2.refinedInfo
537+
def qualifies(m: SingleDenotation) = isSubType(m.info, rinfo2)
538+
def memberMatches(mbr: Denotation): Boolean = mbr match { // inlined hasAltWith for performance
539+
case mbr: SingleDenotation => qualifies(mbr)
540+
case _ => mbr hasAltWith qualifies
541+
}
542+
/*>|>*/ ctx.traceIndented(i"hasMatchingMember($base . $name :? ${tp2.refinedInfo}) ${base.member(name).info.show} $rinfo2", subtyping) /*<|<*/ {
543+
memberMatches(base member name) ||
547544
tp1.isInstanceOf[SingletonType] &&
548545
{ // special case for situations like:
549546
// class C { type T }
@@ -554,9 +551,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi
554551
case _ => false
555552
}
556553
}
557-
}
558554
}
559-
finally skolemsState = saved
555+
}
556+
557+
final def ensureStableSingleton(tp: Type): SingletonType = tp.stripTypeVar match {
558+
case tp: SingletonType if tp.isStable => tp
559+
case tp: ValueType => SkolemType(tp)
560+
case tp: TypeProxy => ensureStableSingleton(tp.underlying)
560561
}
561562

562563
/** Skip refinements in `tp2` which match corresponding refinements in `tp1`.

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

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,103 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
7676
var unstable = false
7777
}
7878

79+
/** Approximate a type `tp` with a type that does not contain skolem types.
80+
*/
81+
final def deskolemize(tp: Type): Type = deskolemize(tp, 1, Set())
82+
83+
private def deskolemize(tp: Type, variance: Int, seen: Set[SkolemType]): Type = {
84+
def approx(lo: Type = defn.NothingType, hi: Type = defn.AnyType, newSeen: Set[SkolemType] = seen) =
85+
if (variance == 0) NoType
86+
else deskolemize(if (variance < 0) lo else hi, variance, newSeen)
87+
tp match {
88+
case tp: SkolemType =>
89+
if (seen contains tp) NoType
90+
else approx(hi = tp.info, newSeen = seen + tp)
91+
case tp: NamedType =>
92+
val sym = tp.symbol
93+
if (sym.isStatic) tp
94+
else {
95+
val pre1 = deskolemize(tp.prefix, variance, seen)
96+
if (pre1 eq tp.prefix) tp
97+
else {
98+
val d = tp.prefix.member(tp.name)
99+
d.info match {
100+
case TypeAlias(alias) => deskolemize(alias, variance, seen)
101+
case _ =>
102+
if (pre1.exists && !pre1.isRef(defn.NothingClass)) tp.derivedSelect(pre1)
103+
else {
104+
ctx.log(s"deskolem: $tp: ${tp.info}")
105+
tp.info match {
106+
case TypeBounds(lo, hi) => approx(lo, hi)
107+
case info => approx(defn.NothingType, info)
108+
}
109+
}
110+
}
111+
}
112+
}
113+
case _: ThisType | _: BoundType | _: SuperType | NoType | NoPrefix =>
114+
tp
115+
case tp: RefinedType =>
116+
val parent1 = deskolemize(tp.parent, variance, seen)
117+
if (parent1.exists) {
118+
val refinedInfo1 = deskolemize(tp.refinedInfo, variance, seen)
119+
if (refinedInfo1.exists)
120+
tp.derivedRefinedType(parent1, tp.refinedName, refinedInfo1)
121+
else
122+
approx(hi = parent1)
123+
}
124+
else approx()
125+
case tp: TypeAlias =>
126+
val alias1 = deskolemize(tp.alias, variance * tp.variance, seen)
127+
if (alias1.exists) tp.derivedTypeAlias(alias1)
128+
else approx(hi = TypeBounds.empty)
129+
case tp: TypeBounds =>
130+
val lo1 = deskolemize(tp.lo, -variance, seen)
131+
val hi1 = deskolemize(tp.hi, variance, seen)
132+
if (lo1.exists && hi1.exists) tp.derivedTypeBounds(lo1, hi1)
133+
else approx(hi =
134+
if (lo1.exists) TypeBounds.lower(lo1)
135+
else if (hi1.exists) TypeBounds.upper(hi1)
136+
else TypeBounds.empty)
137+
case tp: ClassInfo =>
138+
val pre1 = deskolemize(tp.prefix, variance, seen)
139+
if (pre1.exists) tp.derivedClassInfo(pre1)
140+
else NoType
141+
case tp: AndOrType =>
142+
val tp1d = deskolemize(tp.tp1, variance, seen)
143+
val tp2d = deskolemize(tp.tp2, variance, seen)
144+
if (tp1d.exists && tp2d.exists)
145+
tp.derivedAndOrType(tp1d, tp2d)
146+
else if (tp.isAnd)
147+
approx(hi = tp1d & tp2d) // if one of tp1d, tp2d exists, it is the result of tp1d & tp2d
148+
else
149+
approx(lo = tp1d & tp2d)
150+
case tp: WildcardType =>
151+
val bounds1 = deskolemize(tp.optBounds, variance, seen)
152+
if (bounds1.exists) tp.derivedWildcardType(bounds1)
153+
else WildcardType
154+
case _ =>
155+
if (tp.isInstanceOf[MethodicType]) assert(variance != 0, tp)
156+
deskolemizeMap.mapOver(tp, variance, seen)
157+
}
158+
}
159+
160+
object deskolemizeMap extends TypeMap {
161+
private var seen: Set[SkolemType] = _
162+
def apply(tp: Type) = deskolemize(tp, variance, seen)
163+
def mapOver(tp: Type, variance: Int, seen: Set[SkolemType]) = {
164+
val savedVariance = this.variance
165+
val savedSeen = this.seen
166+
this.variance = variance
167+
this.seen = seen
168+
try super.mapOver(tp)
169+
finally {
170+
this.variance = savedVariance
171+
this.seen = savedSeen
172+
}
173+
}
174+
}
175+
79176
/** Implementation of Types#simplified */
80177
final def simplify(tp: Type, theMap: SimplifyMap): Type = tp match {
81178
case tp: NamedType =>

0 commit comments

Comments
 (0)