diff options
-rw-r--r-- | src/dotty/tools/dotc/core/Substituters.scala | 80 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeApplications.scala | 12 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeComparer.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 72 |
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) |