aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-01-08 17:52:00 +0100
committerMartin Odersky <odersky@gmail.com>2015-01-08 17:52:00 +0100
commit9f745338242524c6607fa7b2930157b0c71be939 (patch)
tree47538e766d412760b2298eaf16ab56589eb772be /src/dotty/tools
parent0bc9f680af7670985ff10b1e5fa472655745c90b (diff)
downloaddotty-9f745338242524c6607fa7b2930157b0c71be939.tar.gz
dotty-9f745338242524c6607fa7b2930157b0c71be939.tar.bz2
dotty-9f745338242524c6607fa7b2930157b0c71be939.zip
Refacttored skolemization logic
... into a new trait "Skolemization".
Diffstat (limited to 'src/dotty/tools')
-rw-r--r--src/dotty/tools/dotc/core/NameOps.scala2
-rw-r--r--src/dotty/tools/dotc/core/Skolemization.scala122
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala51
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala102
-rw-r--r--src/dotty/tools/dotc/core/Types.scala6
5 files changed, 150 insertions, 133 deletions
diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala
index 240447e6d..c15c4c4c2 100644
--- a/src/dotty/tools/dotc/core/NameOps.scala
+++ b/src/dotty/tools/dotc/core/NameOps.scala
@@ -355,5 +355,5 @@ object NameOps {
case NO_NAME => primitivePostfixMethodName
case name => name
}
- }
+ }
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/Skolemization.scala b/src/dotty/tools/dotc/core/Skolemization.scala
new file mode 100644
index 000000000..592ec860b
--- /dev/null
+++ b/src/dotty/tools/dotc/core/Skolemization.scala
@@ -0,0 +1,122 @@
+package dotty.tools.dotc
+package core
+
+import Symbols._, Types._, Contexts._, Decorators._, NameOps._, StdNames._
+import collection.mutable
+
+trait Skolemization {
+
+ protected var skolemsOutstanding = false
+
+ def ensureSingleton(tp: Type)(implicit ctx: Context): SingletonType = tp.stripTypeVar match {
+ case tp: SingletonType =>
+ tp
+ case tp: ValueType =>
+ skolemsOutstanding = true
+ tp.narrow
+ case tp: TypeProxy =>
+ ensureSingleton(tp.underlying)
+ }
+
+ /** 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)(implicit ctx: Context): Type =
+ if (skolemsOutstanding) deSkolemize(tp, if (toSuper) 1 else -1, Set()) else tp
+
+ private def deSkolemize(tp: Type, variance: Int, seen: Set[Symbol])(implicit ctx: Context): Type =
+ ctx.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(implicit ctx: Context) = {
+ if (deSkolemizeMapCache == null || deSkolemizeMapCache.definingCtx != ctx)
+ 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
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 98a0d665c..8ce1ad354 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -16,7 +16,7 @@ import scala.util.control.NonFatal
/** Provides methods to compare types.
*/
-class TypeComparer(initctx: Context) extends DotClass {
+class TypeComparer(initctx: Context) extends DotClass with Skolemization {
implicit val ctx: Context = initctx
val state = ctx.typerState
@@ -267,8 +267,7 @@ class TypeComparer(initctx: Context) extends DotClass {
}
}
- val bound = (if (false) ctx.deSkolemize(bound0, toSuper = fromBelow) else bound0)
- .dealias.stripTypeVar
+ val bound = deSkolemize(bound0, toSuper = fromBelow).dealias.stripTypeVar
def description = s"${param.show} ${if (fromBelow) ">:>" else "<:<"} ${bound.show} to ${constraint.show}"
constr.println(s"adding $description")
val res = addBi(param, bound, fromBelow)
@@ -794,24 +793,28 @@ class TypeComparer(initctx: Context) extends DotClass {
ctdSubType(orig1, orig2)
}
- def hasMatchingMember(name: Name, orig1: Type, tp2: RefinedType): Boolean = /*>|>*/ ctx.traceIndented(s"hasMatchingMember($orig1 . $name, ${tp2.refinedInfo}) ${orig1.member(name).info.show}", subtyping) /*<|<*/ {
- val base = orig1.ensureSingleton
- var rinfo2 = tp2.refinedInfo.substRefinedThis(0, base)
- def qualifies(m: SingleDenotation) = isSubType(m.info, rinfo2)
- def memberMatches(mbr: Denotation): Boolean = mbr match { // inlined hasAltWith for performance
- case mbr: SingleDenotation => qualifies(mbr)
- case _ => mbr hasAltWith qualifies
- }
- memberMatches(base member name) ||
- orig1.isInstanceOf[SingletonType] &&
- { // special case for situations like:
- // foo <: C { type T = foo.T }
- rinfo2 match {
- case rinfo2: TypeAlias =>
- !ctx.phase.erasedTypes && (base select name) =:= rinfo2.alias
- case _ => false
- }
+ def hasMatchingMember(name: Name, tp1: Type, tp2: RefinedType): Boolean = /*>|>*/ ctx.traceIndented(s"hasMatchingMember($tp1 . $name, ${tp2.refinedInfo}) ${tp1.member(name).info.show}", subtyping) /*<|<*/ {
+ val saved = skolemsOutstanding
+ try {
+ val base = ensureSingleton(tp1)
+ var rinfo2 = tp2.refinedInfo.substRefinedThis(0, base)
+ def qualifies(m: SingleDenotation) = isSubType(m.info, rinfo2)
+ def memberMatches(mbr: Denotation): Boolean = mbr match { // inlined hasAltWith for performance
+ case mbr: SingleDenotation => qualifies(mbr)
+ case _ => mbr hasAltWith qualifies
}
+ memberMatches(base member name) ||
+ tp1.isInstanceOf[SingletonType] &&
+ { // special case for situations like:
+ // foo <: C { type T = foo.T }
+ rinfo2 match {
+ case rinfo2: TypeAlias =>
+ !ctx.phase.erasedTypes && (base select name) =:= rinfo2.alias
+ case _ => false
+ }
+ }
+ }
+ finally skolemsOutstanding = saved
}
/** A type has been covered previously in subtype checking if it
@@ -864,7 +867,7 @@ class TypeComparer(initctx: Context) extends DotClass {
def narrowGADTBounds(tr: NamedType, bound: Type, fromBelow: Boolean): Boolean =
ctx.mode.is(Mode.GADTflexible) && {
val tparam = tr.symbol
- val bound1 = bound // ctx.deSkolemize(bound, toSuper = fromBelow)
+ val bound1 = deSkolemize(bound, toSuper = fromBelow)
println(s"narrow gadt bound of $tparam: ${tparam.info} from ${if (fromBelow) "below" else "above"} to $bound1 ${bound1.isRef(tparam)}")
!bound1.isRef(tparam) && {
val oldBounds = ctx.gadt.bounds(tparam)
@@ -1419,9 +1422,9 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
super.isSubType(tp1, tp2)
}
- override def hasMatchingMember(name: Name, orig1: Type, tp2: RefinedType): Boolean =
- traceIndented(s"hasMatchingMember(${show(orig1)} . $name, ${show(tp2.refinedInfo)}), member = ${show(orig1.member(name).info)}") {
- super.hasMatchingMember(name, orig1, tp2)
+ override def hasMatchingMember(name: Name, tp1: Type, tp2: RefinedType): Boolean =
+ traceIndented(s"hasMatchingMember(${show(tp1)} . $name, ${show(tp2.refinedInfo)}), member = ${show(tp1.member(name).info)}") {
+ super.hasMatchingMember(name, tp1, tp2)
}
override def lub(tp1: Type, tp2: Type) =
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index fb6ef6c09..6fc7314c2 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -87,108 +87,6 @@ trait TypeOps { this: Context =>
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.
*/
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index c6913eb0f..920c9c6f8 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -755,12 +755,6 @@ object Types {
def narrow(implicit ctx: Context): TermRef =
TermRef(NoPrefix, ctx.newSkolem(this))
- def ensureSingleton(implicit ctx: Context): SingletonType = stripTypeVar match {
- case tp: SingletonType => tp
- case tp: ValueType => narrow
- case tp: TypeProxy => tp.underlying.ensureSingleton
- }
-
// ----- Normalizing typerefs over refined types ----------------------------
/** If this is a refinement type that has a refinement for `name` (which might be followed