From 09a4bc5d099de71de824a35a67a26e7091e3bb5a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 4 Apr 2014 10:18:33 +0200 Subject: Reworked TermRef handling The main problem with TermRef handling was that signatures were not always tracked correctly. New invariant: A TermRef that points to a symbol is always a TermRefWithSig, and the signature is the one of the corresponding member. We achieve this by sometimes generating a new TermRefWithSig if a TermRef gets a denotation. One possible simplification would be to always store a signature in a TermRef. There's still a problem in TermRefWithSig#newLikeThis, which currently works only if the previously stored denotation references a symbol. We will need to generalize JointRefDenotation to contain multiple symbols for a complete fix. --- src/dotty/tools/dotc/ast/tpd.scala | 6 +- src/dotty/tools/dotc/config/Config.scala | 7 ++ src/dotty/tools/dotc/core/Denotations.scala | 2 +- src/dotty/tools/dotc/core/Signature.scala | 6 +- src/dotty/tools/dotc/core/StdNames.scala | 1 + src/dotty/tools/dotc/core/Symbols.scala | 4 +- src/dotty/tools/dotc/core/Types.scala | 138 +++++++++++++++++++++++----- 7 files changed, 137 insertions(+), 27 deletions(-) diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 3664263e6..9a9ffe243 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -29,7 +29,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { untpd.Select(qualifier, tp.name).withType(tp) def Select(qualifier: Tree, sym: Symbol)(implicit ctx: Context): Select = - untpd.Select(qualifier, sym.name).withType(qualifier.tpe select sym) + untpd.Select(qualifier, sym.name).withType( + TermRef.withSig(qualifier.tpe, sym.name.asTermName, sym.signature, sym.denot)) def SelectWithSig(qualifier: Tree, name: Name, sig: Signature)(implicit ctx: Context) = untpd.SelectWithSig(qualifier, name, sig) @@ -259,10 +260,11 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { /** new C(args) */ def New(tp: Type, args: List[Tree])(implicit ctx: Context): Apply = { val targs = tp.argTypes + val constr = tp.typeSymbol.primaryConstructor.asTerm Apply( Select( New(tp withoutArgs targs), - TermRef(tp.normalizedPrefix, tp.typeSymbol.primaryConstructor.asTerm)) + TermRef.withSig(tp.normalizedPrefix, constr)) .appliedToTypes(targs), args) } diff --git a/src/dotty/tools/dotc/config/Config.scala b/src/dotty/tools/dotc/config/Config.scala index f69566733..9b8bd27ec 100644 --- a/src/dotty/tools/dotc/config/Config.scala +++ b/src/dotty/tools/dotc/config/Config.scala @@ -13,6 +13,13 @@ object Config { final val checkConstraintsNonCyclic = true final val flagInstantiationToNothing = false + + /** Enable noDoubleDef checking if option "-YnoDoubleDefs" is set. + * The reason to have an option as well as the present global switch is + * that the noDoubleDef checking is done in a hotspot, and we do not + * want to incur the overhead of checking an option each time. + */ + final val checkTermRefs = false /** Throw an exception if a deep subtype recursion is detected */ final val flagDeepSubTypeRecursions = true diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index 0622829c5..63b94efbd 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -334,7 +334,7 @@ object Denotations { final def info(implicit ctx: Context) = infoOrCompleter final def validFor = denot1.validFor & denot2.validFor final def isType = false - def signature(implicit ctx: Context) = multiHasNot("signature") + final def signature(implicit ctx: Context) = Signature.OverloadedSignature def atSignature(sig: Signature)(implicit ctx: Context): SingleDenotation = denot1.atSignature(sig) orElse denot2.atSignature(sig) def current(implicit ctx: Context): Denotation = diff --git a/src/dotty/tools/dotc/core/Signature.scala b/src/dotty/tools/dotc/core/Signature.scala index 02b91b18e..eb85fbb99 100644 --- a/src/dotty/tools/dotc/core/Signature.scala +++ b/src/dotty/tools/dotc/core/Signature.scala @@ -1,7 +1,7 @@ package dotty.tools.dotc package core -import Names._, Types._, Contexts._ +import Names._, Types._, Contexts._, StdNames._ import transform.Erasure.sigName /** The signature of a denotation. @@ -49,6 +49,10 @@ object Signature { * a type different from PolyType, MethodType, or ExprType. */ val NotAMethod = Signature(List(), EmptyTypeName) + + /** The signature of an overloaded denotation. + */ + val OverloadedSignature = Signature(List(tpnme.OVERLOADED), EmptyTypeName) /** The signature of a method with no parameters and result type `resultType`. */ def apply(resultType: Type, isJava: Boolean)(implicit ctx: Context): Signature = diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index 3982c51f0..d01971982 100644 --- a/src/dotty/tools/dotc/core/StdNames.scala +++ b/src/dotty/tools/dotc/core/StdNames.scala @@ -109,6 +109,7 @@ object StdNames { val MODULE_VAR_SUFFIX: N = "$module" val NAME_JOIN: N = NameTransformer.NAME_JOIN_STRING val USCORE_PARAM_PREFIX: N = "_$" + val OVERLOADED: N = "" val PACKAGE: N = "package" val PACKAGE_CLS: N = "package$" val PROTECTED_PREFIX: N = "protected$" diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala index b4db26ae6..8f66830e8 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -245,7 +245,7 @@ trait Symbols { this: Context => for (name <- names) { val tparam = newNakedSymbol[TypeName](NoCoord) tparamBuf += tparam - trefBuf += TypeRef(owner.thisType, name) withSym tparam + trefBuf += TypeRef(owner.thisType, name).withSym(tparam, Signature.NotAMethod) } val tparams = tparamBuf.toList val bounds = boundsFn(trefBuf.toList) @@ -319,7 +319,7 @@ object Symbols { type ThisName <: Name private[this] var _id: Int = nextId - //assert(_id != 5859) + //assert(_id != 12325) /** The unique id of this symbol */ def id = _id diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 8799f9fd0..7561abb10 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -656,6 +656,15 @@ object Types { if (res.exists) res else TypeRef(this, name, denot) } + /** The type , reduced if possible, with given denotation if unreduced */ + def selectNonMember(name: Name, denot: Denotation)(implicit ctx: Context): Type = name match { + case name: TermName => + TermRef(this, name, denot) + case name: TypeName => + val res = lookupRefined(name) + if (res.exists) res else TypeRef(this, name, denot) + } + /** The type with given symbol, reduced if possible */ def select(sym: Symbol)(implicit ctx: Context): Type = if (sym.isTerm) TermRef(this, sym.asTerm) @@ -991,6 +1000,8 @@ object Types { val prefix: Type val name: Name + type ThisType >: this.type <: NamedType + assert(prefix.isValueType || (prefix eq NoPrefix), s"invalid prefix $prefix") private[this] var lastDenotation: Denotation = _ @@ -1049,19 +1060,48 @@ object Types { if (owner.isTerm) d else d.asSeenFrom(prefix) } - private[dotc] final def withDenot(denot: Denotation): this.type = { + private def checkSymAssign(sym: Symbol) = + assert( + (lastSymbol eq sym) || + (lastSymbol eq null) || + (lastSymbol.defRunId != sym.defRunId) || + (lastSymbol.defRunId == NoRunId), + s"data race? overwriting symbol of $this / ${this.getClass} / ${lastSymbol.id} / ${sym.id}") + + protected def sig: Signature = Signature.NotAMethod + + private[dotc] def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = + if (sig != denot.signature) + withSig(denot.signature).withDenot(denot).asInstanceOf[ThisType] + else { + setDenot(denot) + this + } + + private[dotc] final def setDenot(denot: Denotation): Unit = { + if (Config.checkTermRefs) checkSymAssign(denot.symbol) lastDenotation = denot lastSymbol = denot.symbol - this } - private[dotc] final def withSym(sym: Symbol): this.type = { + private[dotc] def withSym(sym: Symbol, signature: Signature)(implicit ctx: Context): ThisType = + if (sig != signature) + withSig(signature).withSym(sym, signature).asInstanceOf[ThisType] + else { + setSym(sym) + this + } + + private[dotc] final def setSym(sym: Symbol): Unit = { + if (Config.checkTermRefs) checkSymAssign(sym) lastDenotation = null lastSymbol = sym checkedPeriod = Nowhere - this } + private def withSig(sig: Signature)(implicit ctx: Context): NamedType = + TermRef.withSig(prefix, name.asTermName, sig) + protected def loadDenot(implicit ctx: Context) = { val d = prefix.member(name) if (d.exists || ctx.phaseId == FirstPhaseId) @@ -1136,6 +1176,9 @@ object Types { abstract case class TermRef(override val prefix: Type, name: TermName) extends NamedType with SingletonType { + type ThisType = TermRef + + //assert(name.toString != "") override def underlying(implicit ctx: Context): Type = { val d = denot if (d.isOverloaded) NoType else d.info @@ -1156,16 +1199,31 @@ object Types { } abstract case class TypeRef(override val prefix: Type, name: TypeName) extends NamedType { + + type ThisType = TypeRef + override def underlying(implicit ctx: Context): Type = info } - final class TermRefWithSignature(prefix: Type, name: TermName, val sig: Signature) extends TermRef(prefix, name) { + final class TermRefWithSignature(prefix: Type, name: TermName, override val sig: Signature) extends TermRef(prefix, name) { assert(prefix ne NoPrefix) override def signature(implicit ctx: Context) = sig - override def loadDenot(implicit ctx: Context): Denotation = - super.loadDenot.atSignature(sig) - override def newLikeThis(prefix: Type)(implicit ctx: Context): TermRef = - TermRef.withSig(prefix, name, sig) + override def loadDenot(implicit ctx: Context): Denotation = { + val d = super.loadDenot + if (sig eq Signature.OverloadedSignature) d + else d.atSignature(sig) + } + + override def newLikeThis(prefix: Type)(implicit ctx: Context): TermRef = { + if (sig != Signature.NotAMethod && + sig != Signature.OverloadedSignature && + symbol.exists) { + val ownSym = symbol + TermRef(prefix, name).withDenot(prefix.member(name).disambiguate(_ eq ownSym)) + } + else TermRef.withSig(prefix, name, sig) + } + override def equals(that: Any) = that match { case that: TermRefWithSignature => this.prefix == that.prefix && @@ -1177,15 +1235,25 @@ object Types { override def computeHash = doHash((name, sig), prefix) } - trait WithNoPrefix extends NamedType { + trait WithNonMemberSym extends NamedType { def fixedSym: Symbol assert(fixedSym ne NoSymbol) - withSym(fixedSym) + setSym(fixedSym) + + override def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = { + assert(denot.symbol eq fixedSym) + setDenot(denot) + this + } + + override def withSym(sym: Symbol, signature: Signature)(implicit ctx: Context): ThisType = + unsupported("withSym") + override def equals(that: Any) = that match { - case that: WithNoPrefix => this.fixedSym eq that.fixedSym + case that: WithNonMemberSym => this.prefix == that.prefix && (this.fixedSym eq that.fixedSym) case _ => false } - override def computeHash = doHash(fixedSym) + override def computeHash = doHash(fixedSym, prefix) } final class CachedTermRef(prefix: Type, name: TermName, hc: Int) extends TermRef(prefix, name) { @@ -1200,8 +1268,8 @@ object Types { override def computeHash = unsupported("computeHash") } - final class NoPrefixTermRef(name: TermName, val fixedSym: TermSymbol) extends TermRef(NoPrefix, name) with WithNoPrefix - final class NoPrefixTypeRef(name: TypeName, val fixedSym: TypeSymbol) extends TypeRef(NoPrefix, name) with WithNoPrefix + final class NonMemberTermRef(prefix: Type, name: TermName, val fixedSym: TermSymbol) extends TermRef(prefix, name) with WithNonMemberSym + final class NonMemberTypeRef(prefix: Type, name: TypeName, val fixedSym: TypeSymbol) extends TypeRef(prefix, name) with WithNonMemberSym object NamedType { def apply(prefix: Type, name: Name)(implicit ctx: Context) = @@ -1210,20 +1278,42 @@ object Types { def apply(prefix: Type, name: Name, denot: Denotation)(implicit ctx: Context) = if (name.isTermName) TermRef(prefix, name.asTermName, denot) else TypeRef(prefix, name.asTypeName, denot) + def withNonMemberSym(prefix: Type, sym: Symbol)(implicit ctx: Context) = + if (sym.isType) TypeRef.withNonMemberSym(prefix, sym.name.asTypeName, sym.asType) + else TermRef.withNonMemberSym(prefix, sym.name.asTermName, sym.asTerm) } object TermRef { def apply(prefix: Type, name: TermName)(implicit ctx: Context): TermRef = ctx.uniqueNamedTypes.enterIfNew(prefix, name).asInstanceOf[TermRef] + def apply(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = withSymAndName(prefix, sym, sym.name) + + def apply(prefix: Type, name: TermName, denot: Denotation)(implicit ctx: Context): TermRef = { + if (prefix eq NoPrefix) apply(prefix, denot.symbol.asTerm) + else denot match { + case denot: SymDenotation if denot.isCompleted => withSig(prefix, name, denot.signature) + case _ => apply(prefix, name) + } + } withDenot denot + + def withNonMemberSym(prefix: Type, name: TermName, sym: TermSymbol)(implicit ctx: Context): TermRef = + unique(new NonMemberTermRef(prefix, name, sym)) + def withSymAndName(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = - if (prefix eq NoPrefix) unique(new NoPrefixTermRef(name, sym)) - else apply(prefix, name) withSym sym - def apply(prefix: Type, name: TermName, denot: Denotation)(implicit ctx: Context): TermRef = - (if (prefix eq NoPrefix) apply(prefix, denot.symbol.asTerm) else apply(prefix, name)) withDenot denot + if (prefix eq NoPrefix) withNonMemberSym(prefix, name, sym) + else { + if (sym.defRunId != NoRunId && sym.isCompleted) withSig(prefix, name, sym.signature) + else apply(prefix, name) + } withSym (sym, Signature.NotAMethod) + + def withSig(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = + unique(withSig(prefix, sym.name, sym.signature).withSym(sym, sym.signature)) + def withSig(prefix: Type, name: TermName, sig: Signature)(implicit ctx: Context): TermRef = unique(new TermRefWithSignature(prefix, name, sig)) + def withSig(prefix: Type, name: TermName, sig: Signature, denot: Denotation)(implicit ctx: Context): TermRef = (if (prefix eq NoPrefix) apply(prefix, denot.symbol.asTerm) else withSig(prefix, name, sig)) withDenot denot @@ -1232,11 +1322,17 @@ object Types { object TypeRef { def apply(prefix: Type, name: TypeName)(implicit ctx: Context): TypeRef = ctx.uniqueNamedTypes.enterIfNew(prefix, name).asInstanceOf[TypeRef] + def apply(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = withSymAndName(prefix, sym, sym.name) + + def withNonMemberSym(prefix: Type, name: TypeName, sym: TypeSymbol)(implicit ctx: Context): TypeRef = + unique(new NonMemberTypeRef(prefix, name, sym)) + def withSymAndName(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef = - if (prefix eq NoPrefix) unique(new NoPrefixTypeRef(name, sym)) - else apply(prefix, name) withSym sym + if (prefix eq NoPrefix) withNonMemberSym(prefix, name, sym) + else apply(prefix, name).withSym(sym, Signature.NotAMethod) + def apply(prefix: Type, name: TypeName, denot: Denotation)(implicit ctx: Context): TypeRef = (if (prefix eq NoPrefix) apply(prefix, denot.symbol.asType) else apply(prefix, name)) withDenot denot } -- cgit v1.2.3