aboutsummaryrefslogtreecommitdiff
path: root/src/dotty
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-06-05 15:29:15 +0200
committerMartin Odersky <odersky@gmail.com>2015-06-06 11:05:27 +0200
commit84bf5902dba61c88f1b50229bb3afa5a335ded94 (patch)
treeec2c5651bf6ff40637acac77a58b5eb2a9dd5d75 /src/dotty
parentd5ba5fb89f41432c710e253d084497658be077f8 (diff)
downloaddotty-84bf5902dba61c88f1b50229bb3afa5a335ded94.tar.gz
dotty-84bf5902dba61c88f1b50229bb3afa5a335ded94.tar.bz2
dotty-84bf5902dba61c88f1b50229bb3afa5a335ded94.zip
Move deskolemization from TypeComparer to TypeOps
It's no longer needed in TypeComparer. We now deskolemize when locally inferring types of vals and defs.
Diffstat (limited to 'src/dotty')
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala33
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala97
2 files changed, 114 insertions, 16 deletions
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 64faa6d93..1f80a8a10 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 with ConstraintHandling with Skolemization {
+class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
implicit val ctx: Context = initctx
val state = ctx.typerState
@@ -531,19 +531,16 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi
* rebase both itself and the member info of `tp` on a freshly created skolem type.
*/
protected def hasMatchingMember(name: Name, tp1: Type, tp2: RefinedType): Boolean = {
- val saved = skolemsState
- if (skolemsState == Skolemization.SkolemsDisallowed) skolemsState = Skolemization.SkolemsAllowed
- try {
- val rebindNeeded = tp2.refinementRefersToThis
- val base = if (rebindNeeded) ensureStableSingleton(tp1) else tp1
- val rinfo2 = if (rebindNeeded) tp2.refinedInfo.substRefinedThis(tp2, base) else tp2.refinedInfo
- 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
- }
- /*>|>*/ ctx.traceIndented(i"hasMatchingMember($base . $name :? ${tp2.refinedInfo}) ${base.member(name).info.show} $rinfo2", subtyping) /*<|<*/ {
- memberMatches(base member name) ||
+ val rebindNeeded = tp2.refinementRefersToThis
+ val base = if (rebindNeeded) ensureStableSingleton(tp1) else tp1
+ val rinfo2 = if (rebindNeeded) tp2.refinedInfo.substRefinedThis(tp2, base) else tp2.refinedInfo
+ 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
+ }
+ /*>|>*/ ctx.traceIndented(i"hasMatchingMember($base . $name :? ${tp2.refinedInfo}) ${base.member(name).info.show} $rinfo2", subtyping) /*<|<*/ {
+ memberMatches(base member name) ||
tp1.isInstanceOf[SingletonType] &&
{ // special case for situations like:
// class C { type T }
@@ -554,9 +551,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi
case _ => false
}
}
- }
}
- finally skolemsState = saved
+ }
+
+ final def ensureStableSingleton(tp: Type): SingletonType = tp.stripTypeVar match {
+ case tp: SingletonType if tp.isStable => tp
+ case tp: ValueType => SkolemType(tp)
+ case tp: TypeProxy => ensureStableSingleton(tp.underlying)
}
/** Skip refinements in `tp2` which match corresponding refinements in `tp1`.
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index c4673d569..fb641f247 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -76,6 +76,103 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
var unstable = false
}
+ /** Approximate a type `tp` with a type that does not contain skolem types.
+ */
+ final def deskolemize(tp: Type): Type = deskolemize(tp, 1, Set())
+
+ private def deskolemize(tp: Type, variance: Int, seen: Set[SkolemType]): Type = {
+ def approx(lo: Type = defn.NothingType, hi: Type = defn.AnyType, newSeen: Set[SkolemType] = seen) =
+ if (variance == 0) NoType
+ else deskolemize(if (variance < 0) lo else hi, variance, newSeen)
+ tp match {
+ case tp: SkolemType =>
+ if (seen contains tp) NoType
+ else approx(hi = tp.info, newSeen = seen + tp)
+ case tp: NamedType =>
+ val sym = tp.symbol
+ if (sym.isStatic) tp
+ else {
+ val pre1 = deskolemize(tp.prefix, variance, seen)
+ if (pre1 eq tp.prefix) tp
+ else {
+ val d = tp.prefix.member(tp.name)
+ d.info match {
+ case TypeAlias(alias) => deskolemize(alias, variance, seen)
+ case _ =>
+ 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)
+ }
+ }
+
+ object deskolemizeMap extends TypeMap {
+ private var seen: Set[SkolemType] = _
+ def apply(tp: Type) = deskolemize(tp, variance, seen)
+ def mapOver(tp: Type, variance: Int, seen: Set[SkolemType]) = {
+ 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
+ }
+ }
+ }
+
/** Implementation of Types#simplified */
final def simplify(tp: Type, theMap: SimplifyMap): Type = tp match {
case tp: NamedType =>