From bfb328ff64dcfa103c91dd0cd55a617e370d6ef3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 27 Aug 2014 10:48:16 +0200 Subject: Make ThisTypes take TypeRefs instead of ClassSymbols This avoids stale symbol errors and does not need the somewhat unsystematic symbol rebinding of the last commit. --- src/dotty/tools/dotc/core/Substituters.scala | 4 +-- src/dotty/tools/dotc/core/SymDenotations.scala | 21 ++++++++---- src/dotty/tools/dotc/core/TypeComparer.scala | 18 +++++----- src/dotty/tools/dotc/core/TypeOps.scala | 6 ++-- src/dotty/tools/dotc/core/Types.scala | 39 +++++++++------------- src/dotty/tools/dotc/core/pickling/UnPickler.scala | 8 ++--- 6 files changed, 47 insertions(+), 49 deletions(-) (limited to 'src/dotty/tools/dotc/core') diff --git a/src/dotty/tools/dotc/core/Substituters.scala b/src/dotty/tools/dotc/core/Substituters.scala index e05f76cd9..fdcc077b3 100644 --- a/src/dotty/tools/dotc/core/Substituters.scala +++ b/src/dotty/tools/dotc/core/Substituters.scala @@ -163,8 +163,8 @@ trait Substituters { this: Context => final def substThis(tp: Type, from: ClassSymbol, to: Type, theMap: SubstThisMap): Type = tp match { - case tp @ ThisType(clazz) => - if (clazz eq from) to else tp + case tp: ThisType => + if (tp.cls eq from) to else tp case tp: NamedType => if (tp.symbol.isStaticOwner) tp else tp.derivedSelect(substThis(tp.prefix, from, to, theMap)) diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index cb457bd73..660287089 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -471,9 +471,8 @@ object SymDenotations { * or, if this symbol is protected, a subclass of the owner? */ def isCorrectThisType(pre: Type): Boolean = pre match { - case ThisType(pclazz) => - (pclazz eq owner) || - (this is Protected) && pclazz.derivesFrom(owner) + case pre: ThisType => + (pre.cls eq owner) || (this is Protected) && pre.cls.derivesFrom(owner) case pre: TermRef => pre.symbol.moduleClass == owner case _ => @@ -1000,18 +999,26 @@ object SymDenotations { private[this] var myThisType: Type = null + /** The this-type depends on the kind of class: + * - for a package class `p`: ThisType(TypeRef(Noprefix, p)) + * - for a module class `m`: A term ref to m's source module. + * - for all other classes `c` with owner `o`: ThisType(TypeRef(o.thisType, c)) + */ override def thisType(implicit ctx: Context): Type = { if (myThisType == null) myThisType = computeThisType myThisType } private def computeThisType(implicit ctx: Context): Type = - if (this.is(Module, butNot = Package)) { + if (this is Package) + ThisType.raw(TypeRef(NoPrefix, symbol.asType)) + else { val pre = owner.thisType - if ((pre eq NoPrefix) || ctx.erasedTypes) pre select sourceModule - else TermRef.withSig(pre, name.sourceModuleName, Signature.NotAMethod) + if (this is Module) + if (isMissing(pre)) TermRef(pre, sourceModule.asTerm) + else TermRef.withSig(pre, name.sourceModuleName, Signature.NotAMethod) + else ThisType.raw(TypeRef(pre, symbol.asType)) } - else ThisType.raw(classSymbol) private[this] var myTypeRef: TypeRef = null diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 29f6dda69..fda9667e9 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -323,7 +323,7 @@ class TypeComparer(initctx: Context) extends DotClass { } tp.prefix match { case RefinedThis(rt) => rebaseFrom(rt) - case ThisType(cls) => rebaseFrom(cls.info) + case pre: ThisType => rebaseFrom(pre.cls.info) case _ => tp } } @@ -443,11 +443,11 @@ class TypeComparer(initctx: Context) extends DotClass { // We treat two prefixes A.this, B.this as equivalent if // A's selftype derives from B and B's selftype derives from A. def equivalentThisTypes(tp1: Type, tp2: Type) = tp1 match { - case ThisType(cls1) => + case tp1: ThisType => tp2 match { - case ThisType(cls2) => - cls1.classInfo.selfType.derivesFrom(cls2) && - cls2.classInfo.selfType.derivesFrom(cls1) + case tp2: ThisType => + tp1.cls.classInfo.selfType.derivesFrom(tp2.cls) && + tp2.cls.classInfo.selfType.derivesFrom(tp1.cls) case _ => false } case _ => false @@ -483,8 +483,8 @@ class TypeComparer(initctx: Context) extends DotClass { ) else (tp1.name eq tp2.name) && isSameType(tp1.prefix, tp2.prefix) ) || isHKSubType || secondTryNamed(tp1, tp2) - case ThisType(cls) if cls eq tp2.symbol.moduleClass => - isSubType(cls.owner.thisType, tp2.prefix) + case tp1: ThisType if tp1.cls eq tp2.symbol.moduleClass => + isSubType(tp1.cls.owner.thisType, tp2.prefix) case _ => isHKSubType || secondTry(tp1, tp2) } @@ -529,8 +529,8 @@ class TypeComparer(initctx: Context) extends DotClass { def secondTry(tp1: Type, tp2: Type): Boolean = tp1 match { case tp1: NamedType => tp2 match { - case ThisType(cls) if cls eq tp1.symbol.moduleClass => - isSubType(tp1.prefix, cls.owner.thisType) + case tp2: ThisType if tp2.cls eq tp1.symbol.moduleClass => + isSubType(tp1.prefix, tp2.cls.owner.thisType) case _ => secondTryNamed(tp1, tp2) } diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala index f9ff42709..efd7fcca3 100644 --- a/src/dotty/tools/dotc/core/TypeOps.scala +++ b/src/dotty/tools/dotc/core/TypeOps.scala @@ -30,8 +30,8 @@ trait TypeOps { this: Context => val sym = tp.symbol if (sym.isStatic) tp else tp.derivedSelect(asSeenFrom(tp.prefix, pre, cls, theMap)) - case ThisType(thiscls) => - toPrefix(pre, cls, thiscls) + case tp: ThisType => + toPrefix(pre, cls, tp.cls) case _: BoundType | NoPrefix => tp case tp: RefinedType => @@ -224,7 +224,7 @@ trait TypeOps { this: Context => */ def forwardRef(argSym: Symbol, from: Symbol, to: TypeBounds, cls: ClassSymbol, decls: Scope) = argSym.info match { - case info @ TypeBounds(lo2 @ TypeRef(ThisType(_), name), hi2) => + case info @ TypeBounds(lo2 @ TypeRef(_: ThisType, name), hi2) => if (name == from.name && (lo2 eq hi2) && info.variance == to.variance && diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 787c7c4e9..e09d54a23 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -1416,7 +1416,7 @@ object Types { if (ctx.phase.erasedTypes) NoPrefix else prefix /** Is the prefix seen at current phase the same as NoPrefix? */ - private def isMissing(prefix: Type)(implicit ctx: Context) = + def isMissing(prefix: Type)(implicit ctx: Context) = (prefix eq NoPrefix) || ctx.phase.erasedTypes /** Assert current phase does not have erasure semantics */ @@ -1534,33 +1534,24 @@ object Types { // --- Other SingletonTypes: ThisType/SuperType/ConstantType --------------------------- - /** The type cls.this */ - abstract case class ThisType(private var myCls: ClassSymbol) extends CachedProxyType with SingletonType { - def cls(implicit ctx: Context): ClassSymbol = - try myCls.denot.symbol.asClass - catch { - case ex: StaleSymbol => - def prevDenot(implicit ctx: Context) = myCls.denot - val prev = prevDenot(ctx.fresh.setPeriod(Period(myCls.defRunId, ctx.phaseId))) - myCls = prev.owner.info.member(prev.name).symbol.asClass - cls - } - override def underlying(implicit ctx: Context) = - try cls.classInfo.selfType - catch { - case ex: StaleSymbol => - println(i"stale symbol when deref ${cls.id}") - throw ex - } - override def computeHash = doHash(myCls) + /** The type cls.this + * @param tref A type ref which indicates the class `cls`. + * Note: we do not pass a class symbol directly, because symbols + * do not survive runs whereas typerefs do. + */ + abstract case class ThisType(tref: TypeRef) extends CachedProxyType with SingletonType { + def cls(implicit ctx: Context): ClassSymbol = tref.symbol.asClass + override def underlying(implicit ctx: Context): Type = + if (ctx.erasedTypes) tref else cls.classInfo.selfType + override def computeHash = doHash(tref) } - final class CachedThisType(cls: ClassSymbol) extends ThisType(cls) + final class CachedThisType(tref: TypeRef) extends ThisType(tref) - // TODO: consider hash before constructing types? object ThisType { - def raw(cls: ClassSymbol)(implicit ctx: Context) = - unique(new CachedThisType(cls)) + /** Normally one should use ClassSymbol#thisType instead */ + def raw(tref: TypeRef)(implicit ctx: Context) = + unique(new CachedThisType(tref)) } /** The type of a super reference cls.super where diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index e82002c9f..b80e2322a 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -629,18 +629,18 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: var pre = readTypeRef() val sym = readSymbolRef() pre match { - case ThisType(cls) => + case thispre: ThisType => // The problem is that class references super.C get pickled as // this.C. Dereferencing the member might then get an overriding class // instance. The problem arises for instance for LinkedHashMap#MapValues // and also for the inner Transform class in all views. We fix it by // replacing the this with the appropriate super. - if (sym.owner != cls) { - val overriding = cls.decls.lookup(sym.name) + if (sym.owner != thispre.cls) { + val overriding = thispre.cls.decls.lookup(sym.name) if (overriding.exists && overriding != sym) { val base = pre.baseTypeWithArgs(sym.owner) assert(base.exists) - pre = SuperType(pre, base) + pre = SuperType(thispre, base) } } case _ => -- cgit v1.2.3