aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/core/Substituters.scala80
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala12
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala4
-rw-r--r--src/dotty/tools/dotc/core/Types.scala72
4 files changed, 145 insertions, 23 deletions
diff --git a/src/dotty/tools/dotc/core/Substituters.scala b/src/dotty/tools/dotc/core/Substituters.scala
index 119aca569..9fd01ab56 100644
--- a/src/dotty/tools/dotc/core/Substituters.scala
+++ b/src/dotty/tools/dotc/core/Substituters.scala
@@ -1,6 +1,6 @@
package dotty.tools.dotc.core
-import Types._, Symbols._, Contexts._
+import Types._, Symbols._, Contexts._, Names._
/** Substitution operations on types. See the corresponding `subst` and
* `substThis` methods on class Type for an explanation.
@@ -179,7 +179,9 @@ trait Substituters { this: Context =>
.mapOver(tp)
}
- final def substThis(tp: Type, from: RefinedType, to: Type, theMap: SubstRefinedThisMap): Type =
+ // !!! TODO remove once we are sure new RefinedThis scheme works and we drop the ref to
+ // the target type from RefinedThis.
+ final def substThis0(tp: Type, from: RefinedType, to: Type, theMap: SubstRefinedThisMap0): Type =
tp match {
case tp @ RefinedThis(rt, level) =>
if (rt eq from)
@@ -190,16 +192,39 @@ trait Substituters { this: Context =>
else tp
case tp: NamedType =>
if (tp.currentSymbol.isStatic) tp
- else tp.derivedSelect(substThis(tp.prefix, from, to, theMap))
+ else tp.derivedSelect(substThis0(tp.prefix, from, to, theMap))
case _: ThisType | _: BoundType | NoPrefix =>
tp
case tp: RefinedType =>
- tp.derivedRefinedType(substThis(tp.parent, from, to, theMap), tp.refinedName, substThis(tp.refinedInfo, from, to, theMap))
+ tp.derivedRefinedType(substThis0(tp.parent, from, to, theMap), tp.refinedName, substThis0(tp.refinedInfo, from, to, theMap))
case tp: TypeAlias =>
- tp.derivedTypeAlias(substThis(tp.alias, from, to, theMap))
+ tp.derivedTypeAlias(substThis0(tp.alias, from, to, theMap))
case _ =>
- (if (theMap != null) theMap else new SubstRefinedThisMap(from, to))
+ (if (theMap != null) theMap else new SubstRefinedThisMap0(from, to))
.mapOver(tp)
+ }
+
+ final def substRefinedThis(tp: Type, level: Int, to: Type, theMap: SubstRefinedThisMap): Type =
+ tp match {
+ case tp @ RefinedThis(rt, l) if l == level =>
+ to
+ case tp: NamedType =>
+ if (tp.currentSymbol.isStatic) tp
+ else tp.derivedSelect(substRefinedThis(tp.prefix, level, to, theMap))
+ case _: ThisType | _: BoundType | NoPrefix =>
+ tp
+ case tp: RefinedType =>
+ tp.derivedRefinedType(
+ substRefinedThis(tp.parent, level, to, theMap), tp.refinedName,
+ substRefinedThis(tp.refinedInfo, level + 1, to, theMap))
+ case tp: TypeAlias =>
+ tp.derivedTypeAlias(substRefinedThis(tp.alias, level, to, theMap))
+ case _ =>
+ val m = if (theMap != null) theMap else new SubstRefinedThisMap(to)
+ val saved = m.level
+ m.level = level
+ try m.mapOver(tp)
+ finally m.level = saved
}
final def substParam(tp: Type, from: ParamType, to: Type, theMap: SubstParamMap): Type =
@@ -271,8 +296,13 @@ trait Substituters { this: Context =>
def apply(tp: Type): Type = substThis(tp, from, to, this)
}
- final class SubstRefinedThisMap(from: RefinedType, to: Type) extends DeepTypeMap {
- def apply(tp: Type): Type = substThis(tp, from, to, this)
+ final class SubstRefinedThisMap0(from: RefinedType, to: Type) extends DeepTypeMap {
+ def apply(tp: Type): Type = substThis0(tp, from, to, this)
+ }
+
+ final class SubstRefinedThisMap(to: Type) extends DeepTypeMap {
+ var level: Int = 0
+ def apply(tp: Type): Type = substRefinedThis(tp, level, to, this)
}
final class SubstParamMap(from: ParamType, to: Type) extends DeepTypeMap {
@@ -282,4 +312,38 @@ trait Substituters { this: Context =>
final class SubstParamsMap(from: BindingType, to: List[Type]) extends DeepTypeMap {
def apply(tp: Type) = substParams(tp, from, to, this)
}
+
+ /** Substitute every occurrence of symbol `from_i` with `RefinedThis(leve).select(to_i)`
+ * where level represents the nesting level of the occurrence (i.e. number
+ * of refinedInfos between substituted type and the occurrence.
+ * TODO: Drop `rt` once it is dropped from RefinedThis
+ * TODO: Apply to enclosing refined type instead of refined info. That way we
+ * can optimize for types not containing any RefinedThis
+ */
+ final class SubstWithRefinedSelectMap(rt: RefinedType, from: List[Symbol], to: List[TypeName]) extends DeepTypeMap {
+ private var level = 0
+ def apply(tp: Type): Type = tp match {
+ case tp: NamedType =>
+ val sym = tp.symbol
+ var fs = from
+ var ts = to
+ while (fs.nonEmpty) {
+ if (fs.head eq sym)
+ return RefinedThis(rt, level).select(ts.head)
+ fs = fs.tail
+ ts = ts.tail
+ }
+ if (sym.isStatic && !existsStatic(from)) tp
+ else tp.derivedSelect(apply(tp.prefix))
+ case tp: RefinedType =>
+ val parent1 = apply(tp.parent)
+ level += 1
+ try tp.derivedRefinedType(parent1, tp.refinedName, apply(tp.refinedInfo))
+ finally level -= 1
+ case tp: TypeAlias =>
+ tp.derivedTypeAlias(apply(tp.alias))
+ case _ =>
+ mapOver(tp)
+ }
+ }
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index 21aa5960e..0a3884ded 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -407,17 +407,14 @@ class TypeApplications(val self: Type) extends AnyVal {
if (bsyms.isEmpty) {
val correspondingNames = correspondingParamName.values.toSet
- def replacements(rt: RefinedType): List[Type] =
- for (sym <- boundSyms)
- yield TypeRef(RefinedThis(rt, 0), correspondingParamName(sym))
-
def rewrite(tp: Type): Type = tp match {
case tp @ RefinedType(parent, name: TypeName) =>
if (correspondingNames contains name) rewrite(parent)
else RefinedType(
rewrite(parent),
name,
- rt => tp.refinedInfo.subst(boundSyms, replacements(rt)))
+ new ctx.SubstWithRefinedSelectMap(
+ _, boundSyms, boundSyms map correspondingParamName)(tp.refinedInfo))
case tp =>
tp
}
@@ -452,9 +449,8 @@ class TypeApplications(val self: Type) extends AnyVal {
def expand(tp: Type) = {
val lambda = defn.lambdaTrait(boundSyms.map(_.variance))
val substitutedRHS = (rt: RefinedType) => {
- val argRefs = boundSyms.indices.toList.map(i =>
- RefinedThis(rt, 0).select(tpnme.lambdaArgName(i)))
- tp.subst(boundSyms, argRefs).bounds.withVariance(1)
+ val argNames = boundSyms.indices.toList.map(tpnme.lambdaArgName)
+ new ctx.SubstWithRefinedSelectMap(rt, boundSyms, argNames)(tp).bounds.withVariance(1)
}
val res = RefinedType(lambda.typeRef, tpnme.Apply, substitutedRHS)
//println(i"lambda abstract $self wrt $boundSyms%, % --> $res")
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 3a4a2305d..9807af901 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -372,6 +372,8 @@ class TypeComparer(initctx: Context) extends DotClass {
else {
val saved = constraint
val savedSuccessCount = successCount
+ val savedRLC = Types.reverseLevelCheck // !!! TODO: remove
+ Types.reverseLevelCheck = false
try {
recCount = recCount + 1
val result =
@@ -413,6 +415,8 @@ class TypeComparer(initctx: Context) extends DotClass {
constraint = saved
successCount = savedSuccessCount
throw ex
+ } finally {
+ Types.reverseLevelCheck = savedRLC
}
}
}
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 68deae176..c6913eb0f 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -436,7 +436,15 @@ object Types {
}
def goRefined(tp: RefinedType) = {
val pdenot = go(tp.parent)
- val rinfo = tp.refinedInfo.substThis(tp, pre)
+ val rinfo = pre match {
+ case pre: RefinedType => tp.refinedInfo.substThis0(tp, RefinedThis(pre, -1))
+ case _ => tp.refinedInfo.substRefinedThis(0, pre)
+ }
+ if (Types.goRefinedCheck) {
+ val rinfo0 = tp.refinedInfo.substThis0(tp, pre)
+ if ((rinfo0 ne rinfo) && (rinfo0.show != rinfo.show))
+ println(s"findMember discrepancy for $tp , $name, pre = $pre, old = $rinfo0, new = $rinfo")
+ }
if (name.isTypeName) { // simplified case that runs more efficiently
val jointInfo = if (rinfo.isAlias) rinfo else pdenot.info & rinfo
pdenot.asSingleDenotation.derivedSingleDenotation(pdenot.symbol, jointInfo)
@@ -747,6 +755,12 @@ 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
@@ -931,9 +945,13 @@ object Types {
final def substThisUnlessStatic(cls: ClassSymbol, tp: Type)(implicit ctx: Context): Type =
if (cls.isStaticOwner) this else ctx.substThis(this, cls, tp, null)
- /** Substitute all occurrences of `RefinedThis(rt)` by `tp` */
- final def substThis(rt: RefinedType, tp: Type)(implicit ctx: Context): Type =
- ctx.substThis(this, rt, tp, null)
+ /** Substitute all occurrences of `RefinedThis(rt)` by `tp` !!! TODO remove */
+ final def substThis0(rt: RefinedType, tp: Type)(implicit ctx: Context): Type =
+ ctx.substThis0(this, rt, tp, null)
+
+ /** Substitute all occurrences of `RefinedThis(level)` by `tp` */
+ final def substRefinedThis(level: Int, to: Type)(implicit ctx: Context): Type =
+ ctx.substRefinedThis(this, level, to, null)
/** Substitute a bound type by some other type */
final def substParam(from: ParamType, to: Type)(implicit ctx: Context): Type =
@@ -1760,10 +1778,47 @@ object Types {
}
refinementRefersToThisCache
}
+
+ def checkLevel(implicit ctx: Context): Unit = {
+ val checkAccu = new TypeAccumulator[Unit] {
+ var level = 0
+ def apply(x: Unit, tp: Type) = tp.stripTypeVar match {
+ case RefinedThis(rt, l) =>
+ def dominates(tp: Type, rt: RefinedType): Boolean =
+ (tp eq rt) || {
+ tp match {
+ case RefinedType(parent, _) => dominates(parent, rt)
+ case _ => false
+ }
+ }
+ if (rt eq RefinedType.this) assert(l == level, RefinedType.this)
+ if (Types.reverseLevelCheck && l == level)
+ assert(dominates(rt, RefinedType.this) || dominates(RefinedType.this, rt),
+ RefinedType.this)
+ case tp: RefinedType =>
+ level += 1
+ apply(x, tp.refinedInfo)
+ level -= 1
+ apply(x, tp.parent)
+ case tp: TypeBounds =>
+ apply(x, tp.lo)
+ apply(x, tp.hi)
+ case tp: AnnotatedType =>
+ apply(x, tp.underlying)
+ case tp: AndOrType =>
+ apply(x, tp.tp1)
+ apply(x, tp.tp2)
+ case _ =>
+ foldOver(x, tp)
+ }
+ }
+ checkAccu((), refinedInfo)
+ }
override def underlying(implicit ctx: Context) = parent
private def checkInst(implicit ctx: Context): this.type = {
+ checkLevel
if (Config.checkLambdaVariance)
refinedInfo match {
case refinedInfo: TypeBounds if refinedInfo.variance != 0 && refinedName.isLambdaArgName =>
@@ -1790,7 +1845,7 @@ object Types {
&& !parent.isLambda)
derivedRefinedType(parent.EtaExpand, refinedName, refinedInfo)
else
- RefinedType(parent, refinedName, rt => refinedInfo.substThis(this, RefinedThis(rt, -1))) // !!! TODO: replace with simply `refinedInfo`
+ RefinedType(parent, refinedName, rt => refinedInfo.substThis0(this, RefinedThis(rt, -1))) // !!! TODO: replace with simply `refinedInfo`
}
override def equals(that: Any) = that match {
@@ -1802,7 +1857,7 @@ object Types {
false
}
override def computeHash = doHash(refinedName, refinedInfo, parent)
- override def toString = s"RefinedType($parent, $refinedName, $refinedInfo)"
+ override def toString = s"RefinedType($parent, $refinedName, $refinedInfo | $hashCode)" // !!! TODO: remove
}
class CachedRefinedType(parent: Type, refinedName: Name, infoFn: RefinedType => Type) extends RefinedType(parent, refinedName) {
@@ -2202,7 +2257,7 @@ object Types {
case that: RefinedThis => this.binder eq that.binder
case _ => false
}
- override def toString = s"RefinedThis(${binder.hashCode})"
+ override def toString = s"RefinedThis($level, ${binder.hashCode})"
}
// ------------ Type variables ----------------------------------------
@@ -3011,6 +3066,9 @@ object Types {
// ----- Debug ---------------------------------------------------------
var debugTrace = false
+
+ var reverseLevelCheck = false
+ var goRefinedCheck = false
val watchList = List[String](
) map (_.toTypeName)