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/ast/Trees.scala | 2 +- src/dotty/tools/dotc/ast/tpd.scala | 8 ++--- 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 ++--- src/dotty/tools/dotc/printing/PlainPrinter.scala | 4 +-- src/dotty/tools/dotc/printing/RefinedPrinter.scala | 10 +++--- src/dotty/tools/dotc/transform/Splitter.scala | 4 +-- .../tools/dotc/transform/SuperAccessors.scala | 2 +- src/dotty/tools/dotc/typer/Checking.scala | 2 +- src/dotty/tools/dotc/typer/TypeAssigner.scala | 2 +- 14 files changed, 64 insertions(+), 66 deletions(-) (limited to 'src/dotty/tools/dotc') diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index 554517cd7..49294718b 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -387,7 +387,7 @@ object Trees { type ThisTree[-T >: Untyped] <: DenotingTree[T] override def denot(implicit ctx: Context) = tpe match { case tpe: NamedType => tpe.denot - case ThisType(cls) => cls.denot + case tpe: ThisType => tpe.cls.denot case _ => NoDenotation } } diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 7bddd49f4..7208d4560 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -255,9 +255,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def prefixIsElidable(tp: NamedType)(implicit ctx: Context) = tp.prefix match { case NoPrefix => true - case ThisType(cls) => - cls.isStaticOwner || - tp.symbol.is(ParamOrAccessor) && tp.symbol.maybeOwner.enclosingClass == cls + case pre: ThisType => + pre.cls.isStaticOwner || + tp.symbol.is(ParamOrAccessor) && tp.symbol.maybeOwner.enclosingClass == pre.cls case pre: TermRef => pre.symbol.is(Module) && pre.symbol.isStatic case _ => @@ -283,7 +283,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def singleton(tp: Type)(implicit ctx: Context): Tree = tp match { case tp: TermRef => ref(tp) - case ThisType(cls) => This(cls) + case tp: ThisType => This(tp.cls) case SuperType(qual, _) => singleton(qual) case ConstantType(value) => Literal(value) } 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 _ => diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala index 94b325996..f4eb8606c 100644 --- a/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -190,8 +190,8 @@ class PlainPrinter(_ctx: Context) extends Printer { tp match { case tp: TermRef => toTextPrefix(tp.prefix) ~ selectionString(tp) - case ThisType(cls) => - nameString(cls) + ".this" + case tp: ThisType => + nameString(tp.cls) + ".this" case SuperType(thistpe: SingletonType, _) => toTextRef(thistpe).map(_.replaceAll("""\bthis$""", "super")) case SuperType(thistpe, _) => diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index c5ae129ed..7669b1a3a 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -45,9 +45,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { override def toTextRef(tp: SingletonType): Text = controlled { tp match { - case ThisType(cls) => - if (cls.isAnonymousClass) return "this" - if (cls is ModuleClass) return fullNameString(cls.sourceModule) + case tp: ThisType => + if (tp.cls.isAnonymousClass) return "this" + if (tp.cls is ModuleClass) return fullNameString(tp.cls.sourceModule) case _ => } super.toTextRef(tp) @@ -56,8 +56,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { override def toTextPrefix(tp: Type): Text = controlled { def isOmittable(sym: Symbol) = isOmittablePrefix(sym) && !ctx.settings.verbose.value tp match { - case ThisType(cls) => - if (isOmittable(cls)) return "" + case tp: ThisType => + if (isOmittable(tp.cls)) return "" case tp @ TermRef(pre, _) => val sym = tp.symbol if (sym.isPackageObject) return toTextPrefix(pre) diff --git a/src/dotty/tools/dotc/transform/Splitter.scala b/src/dotty/tools/dotc/transform/Splitter.scala index d9c1c5e5e..823485af9 100644 --- a/src/dotty/tools/dotc/transform/Splitter.scala +++ b/src/dotty/tools/dotc/transform/Splitter.scala @@ -19,9 +19,9 @@ class Splitter extends MiniPhaseTransform { /** Replace self referencing idents with ThisTypes. */ override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo) = tree.tpe match { - case ThisType(cls) => + case tp: ThisType => ctx.debuglog(s"owner = ${ctx.owner}, context = ${ctx}") - This(cls) withPos tree.pos + This(tp.cls) withPos tree.pos case _ => tree } diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala index 2ef104db4..7cb4c5825 100644 --- a/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -551,7 +551,7 @@ class SuperAccessors extends MacroTransform with IdentityDenotTransformer { this /** Is 'tpe' the type of a member of an enclosing class? */ private def isThisType(tpe: Type)(implicit ctx: Context): Boolean = tpe match { - case ThisType(cls) => !cls.is(PackageClass) + case tpe: ThisType => !tpe.cls.is(PackageClass) case tpe: TypeProxy => isThisType(tpe.underlying) case _ => false } diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala index 22129bde2..6ecfee4e3 100644 --- a/src/dotty/tools/dotc/typer/Checking.scala +++ b/src/dotty/tools/dotc/typer/Checking.scala @@ -119,7 +119,7 @@ object Checking { // global symbols when doing the cyclicity check. def isInteresting(prefix: Type): Boolean = prefix.stripTypeVar match { case NoPrefix => true - case ThisType(cls) => sym.owner.isClass && cls.isContainedIn(sym.owner) + case prefix: ThisType => sym.owner.isClass && prefix.cls.isContainedIn(sym.owner) case prefix: NamedType => !prefix.symbol.isStaticOwner && isInteresting(prefix.prefix) case SuperType(thistp, _) => isInteresting(thistp) case AndType(tp1, tp2) => isInteresting(tp1) || isInteresting(tp2) diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index c9f838c0b..4d996fd61 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -107,7 +107,7 @@ trait TypeAssigner { else tpe } else tpe tpe.prefix match { - case ThisType(cls) if cls is Package => tryInsert + case pre: ThisType if pre.cls is Package => tryInsert case pre: TermRef if pre.symbol is Package => tryInsert case _ => tpe } -- cgit v1.2.3