From 080ed2f3d8b5d8fd249691aacc0fe4f9596bb772 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 5 Jun 2015 18:49:36 +0200 Subject: Split RefinedThis and SkolemType SkolemTypes need to behave differently form RefinedThis types in TypeMap and TypeAccumulator. For skolem types these should follow through to the underlying type. For RefinedThis types, these need to do nothing, in order not to start an infinite recursion. --- src/dotty/tools/dotc/core/Skolemization.scala | 4 +- src/dotty/tools/dotc/core/Substituters.scala | 18 +++---- src/dotty/tools/dotc/core/TypeApplications.scala | 8 +-- src/dotty/tools/dotc/core/TypeComparer.scala | 2 +- src/dotty/tools/dotc/core/TypeOps.scala | 3 ++ src/dotty/tools/dotc/core/Types.scala | 61 ++++++++++++++++------ src/dotty/tools/dotc/core/tasty/TastyFormat.scala | 23 ++++---- src/dotty/tools/dotc/core/tasty/TreePickler.scala | 5 +- .../tools/dotc/core/tasty/TreeUnpickler.scala | 2 + .../dotc/core/unpickleScala2/Scala2Unpickler.scala | 2 +- 10 files changed, 82 insertions(+), 46 deletions(-) (limited to 'src/dotty/tools/dotc/core') diff --git a/src/dotty/tools/dotc/core/Skolemization.scala b/src/dotty/tools/dotc/core/Skolemization.scala index eef5f0e5d..8baf612ba 100644 --- a/src/dotty/tools/dotc/core/Skolemization.scala +++ b/src/dotty/tools/dotc/core/Skolemization.scala @@ -30,7 +30,7 @@ trait Skolemization { case tp: TypeProxy => ensureStableSingleton(tp.underlying) } - +/*@@@ /** If skolems were encountered, approximate a type `tp` with a type that * does not contain skolem types. * @param toSuper if true, return the smallest supertype of `tp` with this property @@ -137,7 +137,7 @@ trait Skolemization { this.seen = savedSeen } } - } + }*/ } object Skolemization extends Enumeration { diff --git a/src/dotty/tools/dotc/core/Substituters.scala b/src/dotty/tools/dotc/core/Substituters.scala index 77ecf7fba..e4bbf2305 100644 --- a/src/dotty/tools/dotc/core/Substituters.scala +++ b/src/dotty/tools/dotc/core/Substituters.scala @@ -179,21 +179,21 @@ trait Substituters { this: Context => .mapOver(tp) } - final def substSkolem(tp: Type, from: Type, to: Type, theMap: SubstSkolemMap): Type = + final def substRefinedThis(tp: Type, from: Type, to: Type, theMap: SubstRefinedThisMap): Type = tp match { - case tp @ SkolemType(binder) => + case tp @ RefinedThis(binder) => if (binder eq from) to else tp case tp: NamedType => if (tp.currentSymbol.isStatic) tp - else tp.derivedSelect(substSkolem(tp.prefix, from, to, theMap)) + else tp.derivedSelect(substRefinedThis(tp.prefix, from, to, theMap)) case _: ThisType | _: BoundType | NoPrefix => tp case tp: RefinedType => - tp.derivedRefinedType(substSkolem(tp.parent, from, to, theMap), tp.refinedName, substSkolem(tp.refinedInfo, from, to, theMap)) + tp.derivedRefinedType(substRefinedThis(tp.parent, from, to, theMap), tp.refinedName, substRefinedThis(tp.refinedInfo, from, to, theMap)) case tp: TypeAlias => - tp.derivedTypeAlias(substSkolem(tp.alias, from, to, theMap)) + tp.derivedTypeAlias(substRefinedThis(tp.alias, from, to, theMap)) case _ => - (if (theMap != null) theMap else new SubstSkolemMap(from, to)) + (if (theMap != null) theMap else new SubstRefinedThisMap(from, to)) .mapOver(tp) } @@ -222,7 +222,7 @@ trait Substituters { this: Context => case tp: NamedType => if (tp.currentSymbol.isStatic) tp else tp.derivedSelect(substParams(tp.prefix, from, to, theMap)) - case _: ThisType | NoPrefix | _: SkolemType => + case _: ThisType | NoPrefix => tp case tp: RefinedType => tp.derivedRefinedType(substParams(tp.parent, from, to, theMap), tp.refinedName, substParams(tp.refinedInfo, from, to, theMap)) @@ -266,8 +266,8 @@ trait Substituters { this: Context => def apply(tp: Type): Type = substThis(tp, from, to, this) } - final class SubstSkolemMap(from: Type, to: Type) extends DeepTypeMap { - def apply(tp: Type): Type = substSkolem(tp, from, to, this) + final class SubstRefinedThisMap(from: Type, to: Type) extends DeepTypeMap { + def apply(tp: Type): Type = substRefinedThis(tp, from, to, this) } final class SubstParamMap(from: ParamType, to: Type) extends DeepTypeMap { diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 7f3f8a446..f466cee77 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -387,9 +387,9 @@ class TypeApplications(val self: Type) extends AnyVal { case _ => firstBaseArgInfo(defn.SeqClass) } - def containsSkolemType(target: Type)(implicit ctx: Context): Boolean = { + def containsRefinedThis(target: Type)(implicit ctx: Context): Boolean = { def recur(tp: Type): Boolean = tp.stripTypeVar match { - case SkolemType(tp) => + case RefinedThis(tp) => tp eq target case tp: NamedType => tp.info match { @@ -446,7 +446,7 @@ class TypeApplications(val self: Type) extends AnyVal { def replacements(rt: RefinedType): List[Type] = for (sym <- boundSyms) - yield TypeRef(SkolemType(rt), correspondingParamName(sym)) + yield TypeRef(RefinedThis(rt), correspondingParamName(sym)) def rewrite(tp: Type): Type = tp match { case tp @ RefinedType(parent, name: TypeName) => @@ -489,7 +489,7 @@ class TypeApplications(val self: Type) extends AnyVal { val lambda = defn.lambdaTrait(boundSyms.map(_.variance)) val substitutedRHS = (rt: RefinedType) => { val argRefs = boundSyms.indices.toList.map(i => - SkolemType(rt).select(tpnme.lambdaArgName(i))) + RefinedThis(rt).select(tpnme.lambdaArgName(i))) tp.subst(boundSyms, argRefs).bounds.withVariance(1) } val res = RefinedType(lambda.typeRef, tpnme.Apply, substitutedRHS) diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index e90c30025..64faa6d93 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -536,7 +536,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi try { val rebindNeeded = tp2.refinementRefersToThis val base = if (rebindNeeded) ensureStableSingleton(tp1) else tp1 - val rinfo2 = if (rebindNeeded) tp2.refinedInfo.substSkolem(tp2, base) else tp2.refinedInfo + 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) diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala index acbd5b6f0..a01f8af9f 100644 --- a/src/dotty/tools/dotc/core/TypeOps.scala +++ b/src/dotty/tools/dotc/core/TypeOps.scala @@ -12,6 +12,9 @@ import ast.tpd._ trait TypeOps { this: Context => // TODO: Make standalone object. + final def asSeenFrom(tp: Type, pre: Type, cls: Symbol): Type = + asSeenFrom(tp, pre, cls, null) + final def asSeenFrom(tp: Type, pre: Type, cls: Symbol, theMap: AsSeenFromMap): Type = { def toPrefix(pre: Type, cls: Symbol, thiscls: ClassSymbol): Type = /*>|>*/ ctx.conditionalTraceIndented(TypeOps.track, s"toPrefix($pre, $cls, $thiscls)") /*<|<*/ { diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 6b46e475b..109f39c2f 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -48,6 +48,7 @@ object Types { * | | +--- SuperType * | | +--- ConstantType * | | +--- MethodParam + * | | +----RefinedThis * | | +--- SkolemType * | +- PolyParam * | +- RefinedType @@ -438,7 +439,7 @@ object Types { def goRefined(tp: RefinedType) = { val pdenot = go(tp.parent) val rinfo = - if (tp.refinementRefersToThis) tp.refinedInfo.substSkolem(tp, pre) + if (tp.refinementRefersToThis) tp.refinedInfo.substRefinedThis(tp, pre) else tp.refinedInfo if (name.isTypeName) { // simplified case that runs more efficiently val jointInfo = @@ -583,7 +584,7 @@ object Types { */ final def asSeenFrom(pre: Type, cls: Symbol)(implicit ctx: Context): Type = track("asSeenFrom") { if (!cls.membersNeedAsSeenFrom(pre)) this - else ctx.asSeenFrom(this, pre, cls, null) + else ctx.asSeenFrom(this, pre, cls) } // ----- Subtype-related -------------------------------------------- @@ -822,7 +823,7 @@ object Types { object instantiate extends TypeMap { var isSafe = true def apply(tp: Type): Type = tp match { - case TypeRef(SkolemType(`pre`), name) if name.isLambdaArgName => + case TypeRef(RefinedThis(`pre`), name) if name.isLambdaArgName => val TypeAlias(alias) = member(name).info alias case tp: TypeVar if !tp.inst.exists => @@ -845,13 +846,15 @@ object Types { if (pre.refinedName ne name) loop(pre.parent, pre.refinedName :: resolved) else if (!pre.refinementRefersToThis) alias else alias match { - case TypeRef(SkolemType(`pre`), aliasName) => lookupRefined(aliasName) // (1) + case TypeRef(RefinedThis(`pre`), aliasName) => lookupRefined(aliasName) // (1) case _ => if (name == tpnme.Apply) betaReduce(alias) else NoType // (2) } case _ => loop(pre.parent, resolved) } - case SkolemType(binder) => + case RefinedThis(binder) => binder.lookupRefined(name) + case SkolemType(tp) => + tp.lookupRefined(name) case pre: WildcardType => WildcardType case pre: TypeRef => @@ -1024,8 +1027,8 @@ object Types { if (cls.isStaticOwner) this else ctx.substThis(this, cls, tp, null) /** Substitute all occurrences of `SkolemType(binder)` by `tp` */ - final def substSkolem(binder: Type, tp: Type)(implicit ctx: Context): Type = - ctx.substSkolem(this, binder, tp, null) + final def substRefinedThis(binder: Type, tp: Type)(implicit ctx: Context): Type = + ctx.substRefinedThis(this, binder, tp, null) /** Substitute a bound type by some other type */ final def substParam(from: ParamType, to: Type)(implicit ctx: Context): Type = @@ -1402,7 +1405,7 @@ object Types { * to an (unbounded) wildcard type. * * (2) Reduce a type-ref `T { X = U; ... } # X` to `U` - * provided `U` does not refer with a SkolemType to the + * provided `U` does not refer with a RefinedThis to the * refinement type `T { X = U; ... }` */ def reduceProjection(implicit ctx: Context): Type = { @@ -1816,7 +1819,7 @@ object Types { def refinementRefersToThis(implicit ctx: Context): Boolean = { if (!refinementRefersToThisKnown) { - refinementRefersToThisCache = refinedInfo.containsSkolemType(this) + refinementRefersToThisCache = refinedInfo.containsRefinedThis(this) refinementRefersToThisKnown = true } refinementRefersToThisCache @@ -1852,7 +1855,7 @@ object Types { derivedRefinedType(parent.EtaExpand, refinedName, refinedInfo) else if (false) RefinedType(parent, refinedName, refinedInfo) - else RefinedType(parent, refinedName, rt => refinedInfo.substSkolem(this, SkolemType(rt))) + else RefinedType(parent, refinedName, rt => refinedInfo.substRefinedThis(this, RefinedThis(rt))) } /** Add this refinement to `parent`, provided If `refinedName` is a member of `parent`. */ @@ -2236,7 +2239,7 @@ object Types { } } - // ----- Bound types: MethodParam, PolyParam, SkolemType -------------------------- + // ----- Bound types: MethodParam, PolyParam, RefinedThis -------------------------- abstract class BoundType extends CachedProxyType with ValueType { type BT <: Type @@ -2309,20 +2312,38 @@ object Types { } } - /** A skolem type reference with underlying type `binder`. */ - case class SkolemType(binder: Type) extends BoundType with SingletonType { - type BT = Type + /** a this-reference to an enclosing refined type `binder`. */ + case class RefinedThis(binder: RefinedType) extends BoundType with SingletonType { + type BT = RefinedType override def underlying(implicit ctx: Context) = binder - def copyBoundType(bt: BT) = SkolemType(bt) + def copyBoundType(bt: BT) = RefinedThis(bt) // need to customize hashCode and equals to prevent infinite recursion for // refinements that refer to the refinement type via this override def computeHash = addDelta(binder.identityHash, 41) override def equals(that: Any) = that match { - case that: SkolemType => this.binder eq that.binder + case that: RefinedThis => this.binder eq that.binder case _ => false } - override def toString = s"SkolemType(${binder.hashCode})" + override def toString = s"RefinedThis(${binder.hashCode})" + } + + // ----- Skolem types ----------------------------------------------- + + /** A skolem type reference with underlying type `binder`. */ + abstract case class SkolemType(info: Type) extends CachedProxyType with ValueType with SingletonType { + override def underlying(implicit ctx: Context) = info + def derivedSkolemType(info: Type)(implicit ctx: Context) = + if (info eq this.info) this else SkolemType(info) + override def computeHash = doHash(info) + override def toString = s"Skolem($info)" + } + + final class CachedSkolemType(info: Type) extends SkolemType(info) + + object SkolemType { + def apply(info: Type)(implicit ctx: Context) = + unique(new CachedSkolemType(info)) } // ------------ Type variables ---------------------------------------- @@ -2883,6 +2904,9 @@ object Types { case tp: AndOrType => tp.derivedAndOrType(this(tp.tp1), this(tp.tp2)) + case tp: SkolemType => + tp.derivedSkolemType(this(tp.info)) + case tp @ AnnotatedType(annot, underlying) => val underlying1 = this(underlying) if (underlying1 eq underlying) tp else tp.derivedAnnotatedType(mapOver(annot), underlying1) @@ -3022,6 +3046,9 @@ object Types { case tp: AndOrType => this(this(x, tp.tp1), tp.tp2) + case tp: SkolemType => + this(x, tp.info) + case AnnotatedType(annot, underlying) => this(applyToAnnot(x, annot), underlying) diff --git a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 106a6510d..1022fc4da 100644 --- a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -103,10 +103,10 @@ Standard-Section: "ASTs" TopLevelStat* TERMREFpkg fullyQualified_NameRef TERMREF possiblySigned_NameRef qual_Type THIS clsRef_Type - SKOLEMtype refinedType_ASTRef + REFINEDthis refinedType_ASTRef + SKOLEMtype Type_ASTRef SHARED path_ASTRef - Constant = UNITconst FALSEconst TRUEconst @@ -262,15 +262,16 @@ object TastyFormat { final val TERMREFpkg = 67 final val TYPEREFpkg = 68 final val SKOLEMtype = 69 - final val BYTEconst = 70 - final val SHORTconst = 71 - final val CHARconst = 72 - final val INTconst = 73 - final val LONGconst = 74 - final val FLOATconst = 75 - final val DOUBLEconst = 76 - final val STRINGconst = 77 - final val IMPORTED = 78 + final val REFINEDthis = 70 + final val BYTEconst = 71 + final val SHORTconst = 72 + final val CHARconst = 73 + final val INTconst = 74 + final val LONGconst = 75 + final val FLOATconst = 76 + final val DOUBLEconst = 77 + final val STRINGconst = 78 + final val IMPORTED = 79 final val THIS = 96 final val CLASSconst = 97 diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 365b5d268..cd49f7c5a 100644 --- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -198,9 +198,12 @@ class TreePickler(pickler: TastyPickler) { case tpe: SuperType => writeByte(SUPERtype) withLength { pickleType(tpe.thistpe); pickleType(tpe.supertpe)} + case tpe: RefinedThis => + writeByte(REFINEDthis) + writeRef(pickledTypes.get(tpe.binder).asInstanceOf[Addr]) case tpe: SkolemType => writeByte(SKOLEMtype) - writeRef(pickledTypes.get(tpe.binder).asInstanceOf[Addr]) + pickleType(tpe.info) case tpe: RefinedType => val args = tpe.argInfos(interpolate = false) if (args.isEmpty) { diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index e753bdcab..d4260e679 100644 --- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -254,6 +254,8 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { } case THIS => ThisType.raw(readType().asInstanceOf[TypeRef]) + case REFINEDthis => + RefinedThis(readTypeRef().asInstanceOf[RefinedType]) case SKOLEMtype => SkolemType(readTypeRef()) case SHARED => diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index b4549a8d8..9498cf43c 100644 --- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -689,7 +689,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas else { def addRefinement(tp: Type, sym: Symbol) = { def subst(info: Type, rt: RefinedType) = - if (clazz.isClass) info.substThis(clazz.asClass, SkolemType(rt)) + if (clazz.isClass) info.substThis(clazz.asClass, RefinedThis(rt)) else info // turns out some symbols read into `clazz` are not classes, not sure why this is the case. RefinedType(tp, sym.name, subst(sym.info, _)) } -- cgit v1.2.3