aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/TypeOps.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-01-08 11:13:21 +0100
committerMartin Odersky <odersky@gmail.com>2015-01-08 11:32:06 +0100
commit74b2584e399cca21159dafe433abbef8c821d1fd (patch)
tree904d65422d57bbb5f60c05217712a5ac383ca1e2 /src/dotty/tools/dotc/core/TypeOps.scala
parent5e6114911cb11336bb53938f2f3b3a70c328921a (diff)
downloaddotty-74b2584e399cca21159dafe433abbef8c821d1fd.tar.gz
dotty-74b2584e399cca21159dafe433abbef8c821d1fd.tar.bz2
dotty-74b2584e399cca21159dafe433abbef8c821d1fd.zip
Add deSkolemize method.
We will need that at some point because type checking refined types will generate skolem variables for representing RefinedThis types if the lower type is not a singleton.
Diffstat (limited to 'src/dotty/tools/dotc/core/TypeOps.scala')
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index 88f495f47..fb6ef6c09 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -86,6 +86,108 @@ trait TypeOps { this: Context =>
class SimplifyMap extends TypeMap {
def apply(tp: Type) = simplify(tp, this)
}
+
+ /** Approximate a type `tp` with a type that does not contain skolem termrefs.
+ * @param toSuper if true, return the smallest supertype of `tp` with this property
+ * e;se return the largest subtype.
+ */
+ final def deSkolemize(tp: Type, toSuper: Boolean): Type =
+ deSkolemize(tp, if (toSuper) 1 else -1, Set())
+
+ private def deSkolemize(tp: Type, variance: Int, seen: Set[Symbol]): Type =
+ traceIndented(s"deskolemize $tp, variance = $variance, seen = $seen = ") {
+ def approx(lo: Type = defn.NothingType, hi: Type = defn.AnyType, newSeen: Set[Symbol] = seen) =
+ if (variance == 0) NoType
+ else deSkolemize(if (variance < 0) lo else hi, variance, newSeen)
+ tp match {
+ case tp: NamedType =>
+ val sym = tp.symbol
+ if (sym.isSkolem)
+ if (seen contains sym) NoType
+ else approx(hi = sym.info, newSeen = seen + sym)
+ else if (sym.isStatic) tp
+ else {
+ val pre1 = deSkolemize(tp.prefix, variance, seen)
+ if (pre1.exists && !pre1.isRef(defn.NothingClass)) tp.derivedSelect(pre1)
+ else {
+ ctx.log(s"deskolem: $tp: ${tp.info}")
+ tp.info match {
+ case TypeBounds(lo, hi) => approx(lo, hi)
+ case info => approx(defn.NothingType, info)
+ }
+ }
+ }
+ case _: ThisType | _: BoundType | _: SuperType | NoType | NoPrefix =>
+ tp
+ case tp: RefinedType =>
+ val parent1 = deSkolemize(tp.parent, variance, seen)
+ if (parent1.exists) {
+ val refinedInfo1 = deSkolemize(tp.refinedInfo, variance, seen)
+ if (refinedInfo1.exists)
+ tp.derivedRefinedType(parent1, tp.refinedName, refinedInfo1)
+ else
+ approx(hi = parent1)
+ }
+ else approx()
+ case tp: TypeAlias =>
+ val alias1 = deSkolemize(tp.alias, variance * tp.variance, seen)
+ if (alias1.exists) tp.derivedTypeAlias(alias1)
+ else approx(hi = TypeBounds.empty)
+ case tp: TypeBounds =>
+ val lo1 = deSkolemize(tp.lo, -variance, seen)
+ val hi1 = deSkolemize(tp.hi, variance, seen)
+ if (lo1.exists && hi1.exists) tp.derivedTypeBounds(lo1, hi1)
+ else approx(hi =
+ if (lo1.exists) TypeBounds.lower(lo1)
+ else if (hi1.exists) TypeBounds.upper(hi1)
+ else TypeBounds.empty)
+ case tp: ClassInfo =>
+ val pre1 = deSkolemize(tp.prefix, variance, seen)
+ if (pre1.exists) tp.derivedClassInfo(pre1)
+ else NoType
+ case tp: AndOrType =>
+ val tp1d = deSkolemize(tp.tp1, variance, seen)
+ val tp2d = deSkolemize(tp.tp2, variance, seen)
+ if (tp1d.exists && tp2d.exists)
+ tp.derivedAndOrType(tp1d, tp2d)
+ else if (tp.isAnd)
+ approx(hi = tp1d & tp2d) // if one of tp1d, tp2d exists, it is the result of tp1d & tp2d
+ else
+ approx(lo = tp1d & tp2d)
+ case tp: WildcardType =>
+ val bounds1 = deSkolemize(tp.optBounds, variance, seen)
+ if (bounds1.exists) tp.derivedWildcardType(bounds1)
+ else WildcardType
+ case _ =>
+ if (tp.isInstanceOf[MethodicType]) assert(variance != 0, tp)
+ deSkolemizeMap.mapOver(tp, variance, seen)
+ }
+ }
+
+ private var deSkolemizeMapCache: DeSkolemizeMap = null
+
+ private def deSkolemizeMap = {
+ if (deSkolemizeMapCache == null || deSkolemizeMapCache.definingCtx != this)
+ deSkolemizeMapCache = new DeSkolemizeMap
+ deSkolemizeMapCache
+ }
+
+ private class DeSkolemizeMap(implicit ctx: Context) extends TypeMap {
+ def definingCtx = ctx
+ private var seen: Set[Symbol] = _
+ def apply(tp: Type) = deSkolemize(tp, variance, seen)
+ def mapOver(tp: Type, variance: Int, seen: Set[Symbol]) = {
+ val savedVariance = this.variance
+ val savedSeen = this.seen
+ this.variance = variance
+ this.seen = seen
+ try super.mapOver(tp)
+ finally {
+ this.variance = savedVariance
+ this.seen = savedSeen
+ }
+ }
+ }
/** Approximate union type by intersection of its dominators.
* See Type#approximateUnion for an explanation.