diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index aded86d6975f..9efa9cfe9a79 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -342,10 +342,10 @@ object Denotations { def mergeDenot(denot1: Denotation, denot2: SingleDenotation): Denotation = denot1 match { case denot1 @ MultiDenotation(denot11, denot12) => val d1 = mergeDenot(denot11, denot2) - if (d1.exists) denot1.derivedMultiDenotation(d1, denot12) + if (d1.exists) denot1.derivedUnionDenotation(d1, denot12) else { val d2 = mergeDenot(denot12, denot2) - if (d2.exists) denot1.derivedMultiDenotation(denot11, d2) + if (d2.exists) denot1.derivedUnionDenotation(denot11, d2) else NoDenotation } case denot1: SingleDenotation => @@ -532,11 +532,11 @@ object Denotations { else if (!that.exists) that else this match { case denot1 @ MultiDenotation(denot11, denot12) => - denot1.derivedMultiDenotation(denot11 | (that, pre), denot12 | (that, pre)) + denot1.derivedUnionDenotation(denot11 | (that, pre), denot12 | (that, pre)) case denot1: SingleDenotation => that match { case denot2 @ MultiDenotation(denot21, denot22) => - denot2.derivedMultiDenotation(this | (denot21, pre), this | (denot22, pre)) + denot2.derivedUnionDenotation(this | (denot21, pre), this | (denot22, pre)) case denot2: SingleDenotation => unionDenot(denot1, denot2) } @@ -558,9 +558,10 @@ object Denotations { final def isType = false final def signature(implicit ctx: Context) = Signature.OverloadedSignature def atSignature(sig: Signature, site: Type, relaxed: Boolean)(implicit ctx: Context): Denotation = - derivedMultiDenotation(denot1.atSignature(sig, site, relaxed), denot2.atSignature(sig, site, relaxed)) + if (sig eq Signature.OverloadedSignature) this + else derivedUnionDenotation(denot1.atSignature(sig, site, relaxed), denot2.atSignature(sig, site, relaxed)) def current(implicit ctx: Context): Denotation = - derivedMultiDenotation(denot1.current, denot2.current) + derivedUnionDenotation(denot1.current, denot2.current) def altsWith(p: Symbol => Boolean): List[SingleDenotation] = denot1.altsWith(p) ++ denot2.altsWith(p) def suchThat(p: Symbol => Boolean)(implicit ctx: Context): SingleDenotation = { @@ -580,12 +581,15 @@ object Denotations { val d2 = denot2 accessibleFrom (pre, superAccess) if (!d1.exists) d2 else if (!d2.exists) d1 - else derivedMultiDenotation(d1, d2) + else derivedUnionDenotation(d1, d2) } def mapInfo(f: Type => Type)(implicit ctx: Context): Denotation = - derivedMultiDenotation(denot1.mapInfo(f), denot2.mapInfo(f)) - def derivedMultiDenotation(d1: Denotation, d2: Denotation) = - if ((d1 eq denot1) && (d2 eq denot2)) this else MultiDenotation(d1, d2) + derivedUnionDenotation(denot1.mapInfo(f), denot2.mapInfo(f)) + def derivedUnionDenotation(d1: Denotation, d2: Denotation): Denotation = + if ((d1 eq denot1) && (d2 eq denot2)) this + else if (!d1.exists) d2 + else if (!d2.exists) d1 + else MultiDenotation(d1, d2) override def toString = alternatives.mkString(" ") private def multiHasNot(op: String): Nothing = diff --git a/compiler/src/dotty/tools/dotc/core/Designators.scala b/compiler/src/dotty/tools/dotc/core/Designators.scala index 73a4705fbb49..f09394c0b869 100644 --- a/compiler/src/dotty/tools/dotc/core/Designators.scala +++ b/compiler/src/dotty/tools/dotc/core/Designators.scala @@ -3,6 +3,9 @@ package dotc package core import Names._ +import NameKinds.SignedName +import Types.{TypeRef, NameSpace, noNameSpace} +import Symbols.Symbol import Contexts.Context /** Defines a common superclass of Name and Symbol and its Term/Type variants @@ -10,7 +13,7 @@ import Contexts.Context */ object Designators { - abstract class Designator extends util.DotClass { + abstract class Designator extends util.DotClass { self => type ThisName <: Name @@ -23,8 +26,49 @@ object Designators { def asTerm(implicit ctx: Context): TermDesignator = unsupported("asTerm") def asType(implicit ctx: Context): TypeDesignator = unsupported("asType") + + def withNameSpace(space: NameSpace)(implicit ctx: Context): Designator { type ThisName = self.ThisName } = + if (space == noNameSpace) this + else localName(this.asInstanceOf[ThisName], space) + + /** Localize this name to the owner of `sym` if `sym` is private */ + def localizeIfPrivate(sym: Symbol)(implicit ctx: Context): Designator { type ThisName = self.ThisName } = + if (sym.isPrivate) withNameSpace(sym.owner.typeRef) else this + + def withSig(sig: Signature): Designator{ type ThisName = TermName } = { + val unsigned = this.asInstanceOf[TermName].exclude(SignedName) + if (sig eq Signature.NotAMethod) unsigned else SignedName(unsigned, sig) + } } type TermDesignator = Designator { type ThisName = TermName } type TypeDesignator = Designator { type ThisName = TypeName } + + case class LocalName[N <: Name](name: N, nameSpace: TypeRef) extends Designator { + type ThisName = N + + override def isTerm(implicit ctx: Context) = name.isTermName + override def isType(implicit ctx: Context) = name.isTypeName + + override def asTerm(implicit ctx: Context): TermDesignator = { + name.asTermName + this.asInstanceOf[TermDesignator] + } + override def asType(implicit ctx: Context): TypeDesignator = { + name.asTypeName + this.asInstanceOf[TypeDesignator] + } + + override def withNameSpace(space: NameSpace)(implicit ctx: Context) = + name.withNameSpace(space).asInstanceOf[Designator { type ThisName = N }] + + override def withSig(sig: Signature) = + LocalName(name.withSig(sig).asInstanceOf[TermName], nameSpace) + } + + /** Introduced to overcome shortcoming with refined type inference of case classes: + * LocalName's result type is always Designator, without a refinement. + */ + def localName[N <: Name](name: N, nameSpace: TypeRef): Designator { type ThisName = N } = + LocalName(name, nameSpace).asInstanceOf[Designator { type ThisName = N }] } \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index 89f907e8943f..54729efcbcaa 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -54,7 +54,8 @@ object NameKinds { def unmangle(name: SimpleName): TermName = name /** Turn a name of this kind consisting of an `underlying` prefix - * and the given `info` into a string. + * and the given `info` into a string. Used to turn structured into + * simple name. */ def mkString(underlying: TermName, info: ThisInfo): String @@ -120,7 +121,7 @@ object NameKinds { class QualifiedNameKind(tag: Int, val separator: String) extends NameKind(tag) { type ThisInfo = QualInfo - case class QualInfo(val name: SimpleName) extends Info with QualifiedInfo { + case class QualInfo(name: SimpleName) extends Info with QualifiedInfo { override def map(f: SimpleName => SimpleName): NameInfo = new QualInfo(f(name)) override def toString = s"$infoString $name" } @@ -349,7 +350,6 @@ object NameKinds { val SuperAccessorName = new PrefixNameKind(SUPERACCESSOR, "super$") val InitializerName = new PrefixNameKind(INITIALIZER, "initial$") - val ShadowedName = new PrefixNameKind(SHADOWED, "(shadowed)") val ProtectedAccessorName = new PrefixNameKind(PROTECTEDACCESSOR, "protected$") val ProtectedSetterName = new PrefixNameKind(PROTECTEDSETTER, "protected$set") // dubious encoding, kept for Scala2 compatibility val AvoidClashName = new SuffixNameKind(AVOIDCLASH, "$_avoid_name_clash_$") @@ -363,9 +363,10 @@ object NameKinds { val ImplMethName = new SuffixNameKind(IMPLMETH, "$") /** A name together with a signature. Used in Tasty trees. */ - object SignedName extends NameKind(63) { + object SignedName extends NameKind(SIGNED) { case class SignedInfo(sig: Signature) extends Info { + assert(sig ne Signature.NotAMethod) override def toString = s"$infoString $sig" } type ThisInfo = SignedInfo diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index c429f4e32882..3377ef0bda23 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -305,7 +305,5 @@ object NameOps { case raw.BANG => UNARY_! case _ => name } - - def withSig(sig: Signature) = SignedName(name.exclude(SignedName), sig) } } diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index b4fd1efa745a..be886b2b3bd7 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -21,7 +21,6 @@ object StdNames { final val TRAIT_SETTER_SEPARATOR = "$_setter_$" final val SUPER_PREFIX = "super$" final val INITIALIZER_PREFIX = "initial$" - final val SHADOWED_PREFIX = "(shadowed)" final val AVOID_CLASH_SUFFIX = "$_avoid_name_clash_$" final val MODULE_SUFFIX = "$" final val NAME_JOIN = "$" diff --git a/compiler/src/dotty/tools/dotc/core/Substituters.scala b/compiler/src/dotty/tools/dotc/core/Substituters.scala index ce4d4337a1b3..b279afb4bd19 100644 --- a/compiler/src/dotty/tools/dotc/core/Substituters.scala +++ b/compiler/src/dotty/tools/dotc/core/Substituters.scala @@ -295,7 +295,7 @@ trait Substituters { this: Context => fs = fs.tail ts = ts.tail } - tp.newLikeThis(apply(tp.prefix)) + tp.withPrefix(apply(tp.prefix)) } catch { case ex: CyclicReference => tp.derivedSelect(apply(tp.prefix)) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index d68af9f1c8ca..78e3ceae1014 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -394,7 +394,7 @@ object Symbols { type ThisName <: Name - //assert(id != 4285) + //assert(id != 723) /** The last denotation of this symbol */ private[this] var lastDenot: SymDenotation = _ @@ -446,11 +446,23 @@ object Symbols { final def isClass: Boolean = isInstanceOf[ClassSymbol] final def asClass: ClassSymbol = asInstanceOf[ClassSymbol] + /** Test whether symbol is referenced symbolically. This + * conservatively returns `false` if symbol does not yet have a denotation + */ final def isReferencedSymbolically(implicit ctx: Context) = { val d = lastDenot d != null && (d.is(NonMember) || d.isTerm && ctx.phase.symbolicRefs) } + /** Test whether symbol is private. This + * conservatively returns `false` if symbol does not yet have a denotation, or denotation + * is a class that is not yet read. + */ + final def isPrivate(implicit ctx: Context) = { + val d = lastDenot + d != null && d.flagsUNSAFE.is(Private) + } + /** The symbol's signature if it is completed or a method, NotAMethod otherwise. */ final def signature(implicit ctx: Context) = if (lastDenot != null && (lastDenot.isCompleted || lastDenot.is(Method))) @@ -489,7 +501,7 @@ object Symbols { if (this is Module) this.moduleClass.validFor |= InitialPeriod } else this.owner.asClass.ensureFreshScopeAfter(phase) - if (!this.flagsUNSAFE.is(Private)) + if (!isPrivate) assert(phase.changesMembers, i"$this entered in ${this.owner} at undeclared phase $phase") entered } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index bd854af3810b..8f5e1c22d7a1 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -7,7 +7,7 @@ import Symbols._ import Flags._ import Names._ import StdNames._, NameOps._ -import NameKinds.{ShadowedName, SkolemName, SignedName} +import NameKinds.{SkolemName, SignedName} import Scopes._ import Constants._ import Contexts._ @@ -823,7 +823,7 @@ object Types { (this eq thisResult) != (that eq thatResult) && (thisResult matchesLoosely thatResult) } - /** The basetype of this type with given class symbol, NoType is `base` is not a class. */ + /** The basetype of this type with given class symbol, NoType if `base` is not a class. */ final def baseType(base: Symbol)(implicit ctx: Context): Type = /*ctx.traceIndented(s"$this baseType $base")*/ /*>|>*/ track("base type") /*<|<*/ { base.denot match { case classd: ClassDenotation => classd.baseTypeOf(this) @@ -1480,6 +1480,9 @@ object Types { // --- NamedTypes ------------------------------------------------------------------ + type NameSpace = TypeRef /* | Null */ + @sharable val noNameSpace: NameSpace = null + /** A NamedType of the form Prefix # name */ abstract class NamedType extends CachedProxyType with ValueType { self => @@ -1497,18 +1500,23 @@ object Types { private[this] var myName: ThisName = _ private[this] var mySig: Signature = null + private[this] var myNameSpace: NameSpace = noNameSpace private[dotc] def init()(implicit ctx: Context): this.type = { - (designator: Designator) match { // dotty shortcoming: need the upcast + def decompose(designator: Designator): Unit = designator match { case DerivedName(underlying, info: SignedName.SignedInfo) => - myName = underlying.asInstanceOf[ThisName] mySig = info.sig - assert(mySig ne Signature.OverloadedSignature) + decompose(underlying) case designator: Name => myName = designator.asInstanceOf[ThisName] + if (mySig == null) mySig = Signature.NotAMethod case designator: Symbol => uncheckedSetSym(designator) + case LocalName(underlying, space) => + myNameSpace = space + decompose(underlying) } + decompose(designator) this } @@ -1517,10 +1525,12 @@ object Types { myName } - final override def signature(implicit ctx: Context): Signature = - if (mySig != null) mySig - else if (isType || lastDenotation == null) Signature.NotAMethod - else denot.signature + final override def signature(implicit ctx: Context): Signature = { + if (mySig == null) mySig = denot.signature + mySig + } + + final def nameSpace: NameSpace = myNameSpace private[this] var lastDenotation: Denotation = _ private[this] var lastSymbol: Symbol = _ @@ -1602,8 +1612,11 @@ object Types { case d: SymDenotation => if (hasFixedSym) d.current else if (d.validFor.runId == ctx.runId || ctx.stillValid(d)) - if (d.exists && prefix.isTightPrefix(d.owner) || d.isConstructor) d.current - else recomputeMember(d) // symbol could have been overridden, recompute membership + if (nameSpace != noNameSpace || + d.exists && prefix.isTightPrefix(d.owner) || + d.isConstructor) d.current + else + recomputeMember(d) // symbol could have been overridden, recompute membership else { val newd = loadDenot if (newd.exists) newd @@ -1685,15 +1698,22 @@ object Types { |period = ${ctx.phase} at run ${ctx.runId}""") } - private[dotc] def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = - if (!hasFixedSym && - signature != denot.signature && - denot.signature.ne(Signature.OverloadedSignature)) - withSig(denot.signature).withDenot(denot).asInstanceOf[ThisType] + private[dotc] def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = { + val adapted = + if (hasFixedSym) + this + else if (signature != denot.signature) + withSig(denot.signature) + else if (denot.symbol.isPrivate) + withNameSpace(denot.symbol.owner.typeRef) + else + this + if (adapted ne this) adapted.withDenot(denot).asInstanceOf[ThisType] else { setDenot(denot) this } + } private[dotc] final def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { if (Config.checkNoDoubleBindings) @@ -1727,12 +1747,12 @@ object Types { } private def withSig(sig: Signature)(implicit ctx: Context): NamedType = - TermRef(prefix, name.asTermName.withSig(sig)) + TermRef(prefix, designator.withSig(sig)) protected def loadDenot(implicit ctx: Context): Denotation = { - val d = asMemberOf(prefix, allowPrivate = true) + val d = asMemberOf(prefix, allowPrivate = false) if (d.exists || ctx.phaseId == FirstPhaseId || !lastDenotation.isInstanceOf[SymDenotation]) - if (mySig != null) d.atSignature(mySig).checkUnique + if (mySig != null && mySig.ne(Signature.OverloadedSignature)) d.atSignature(mySig).checkUnique else d else { // name has changed; try load in earlier phase and make current val d = loadDenot(ctx.withPhase(ctx.phaseId - 1)).current @@ -1744,9 +1764,9 @@ object Types { def reloadDenot()(implicit ctx: Context) = setDenot(loadDenot) protected def asMemberOf(prefix: Type, allowPrivate: Boolean)(implicit ctx: Context): Denotation = - if (name.is(ShadowedName)) prefix.nonPrivateMember(name.exclude(ShadowedName)) - else if (!allowPrivate) prefix.nonPrivateMember(name) - else prefix.member(name) + if (nameSpace != noNameSpace) nameSpace.findMember(name, prefix, EmptyFlags) + else if (allowPrivate) prefix.member(name) + else prefix.nonPrivateMember(name) /** (1) Reduce a type-ref `W # X` or `W { ... } # U`, where `W` is a wildcard type * to an (unbounded) wildcard type. @@ -1769,7 +1789,6 @@ object Types { else denot.symbol - /** Retrieves currently valid symbol without necessarily updating denotation. * Assumes that symbols do not change between periods in the same run. * Used to get the class underlying a ThisType. @@ -1879,46 +1898,31 @@ object Types { val derived2 = derivedSelect(prefix.tp2) return prefix.derivedOrType(derived1, derived2) case _ => - newLikeThis(prefix) + withPrefix(prefix) } - else newLikeThis(prefix) + else withPrefix(prefix) } else prefix match { case _: WildcardType => WildcardType - case _ => newLikeThis(prefix) + case _ => withPrefix(prefix) } /** Create a NamedType of the same kind as this type, but with a new prefix. */ - def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType + def withPrefix(prefix: Type)(implicit ctx: Context): NamedType - /** Create a NamedType of the same kind as this type, but with a "inherited name". - * This is necessary to in situations like the following: - * - * class B { def m: T1 } - * class C extends B { private def m: T2; ... C.m } - * object C extends C - * object X { ... C.m } - * - * The two references of C.m in class C and object X refer to different - * definitions: The one in C refers to C#m whereas the one in X refers to B#m. - * But the type C.m must have only one denotation, so it can't refer to two - * members depending on context. - * - * In situations like this, the reference in X would get the type - * `.shadowed` to make clear that we mean the inherited member, not - * the private one. - * - * Note: An alternative, possibly more robust scheme would be to give - * private members special names. A private definition would have a special - * name (say m' in the example above), but would be entered in its enclosing - * under both private and public names, so it could still be found by looking up - * the public name. + /** Create a NamedType of the same kind as this type, but with a new namespace. */ - def shadowed(implicit ctx: Context): NamedType = - designator match { - case designator: Symbol => this - case designator: Name => NamedType(prefix, designator.derived(ShadowedName)) + def withNameSpace(nameSpace: NameSpace)(implicit ctx: Context): NamedType = + if (nameSpace == this.nameSpace) this + else NamedType(prefix, designator.withNameSpace(nameSpace)) + + /** Create a NamedType of the same kind as this type, but without a namespace + */ + def withoutNameSpace(implicit ctx: Context): NamedType = + (designator: Designator) match { // Dotty deviation: need the widening + case LocalName(underlying, _) => NamedType(prefix, underlying) + case _ => this } override def equals(that: Any) = that match { @@ -1971,29 +1975,29 @@ object Types { } else candidate - def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = designator match { + def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = designator match { case designator: TermSymbol => TermRef(prefix, designator) - case designator: TermName => + case _ => // If symbol exists, the new signature is the symbol's signature as seen // from the new prefix, modulo consistency val curSig = signature val newSig = - if (curSig == Signature.NotAMethod || !symbol.exists) + if (curSig.eq(Signature.NotAMethod) || !symbol.exists) curSig else curSig.updateWith(symbol.info.asSeenFrom(prefix, symbol.owner).signature) - val candidate = + val designator1 = if (newSig ne curSig) { core.println(i"sig change at ${ctx.phase} for $this, pre = $prefix, sig: $curSig --> $newSig") - TermRef(prefix, name.withSig(newSig)) + designator.withSig(newSig) } - else TermRef(prefix, designator) - fixDenot(candidate, prefix) + else designator + fixDenot(TermRef(prefix, designator1), prefix) } - override def shadowed(implicit ctx: Context): NamedType = - fixDenot(super.shadowed.asInstanceOf[TermRef], prefix) + override def withoutNameSpace(implicit ctx: Context): NamedType = + fixDenot(super.withoutNameSpace.asInstanceOf[TermRef], prefix) } abstract case class TypeRef(override val prefix: Type, designator: TypeDesignator) extends NamedType { @@ -2003,7 +2007,7 @@ object Types { override def underlying(implicit ctx: Context): Type = info - def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = + def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = TypeRef(prefix, designator) } @@ -2022,12 +2026,9 @@ object Types { if (Config.checkUnerased) assert(!ctx.phase.erasedTypes) object NamedType { - def apply(prefix: Type, designator: Name)(implicit ctx: Context) = - if (designator.isTermName) TermRef(prefix, designator.asTermName) - else TypeRef(prefix, designator.asTypeName) - def apply(prefix: Type, sym: Symbol)(implicit ctx: Context) = - if (sym.isType) TypeRef(prefix, sym.asType) - else TermRef(prefix, sym.asTerm) + def apply(prefix: Type, designator: Designator)(implicit ctx: Context) = + if (designator.isType) TypeRef(prefix, designator.asType) + else TermRef(prefix, designator.asTerm) def apply(prefix: Type, designator: Name, denot: Denotation)(implicit ctx: Context) = if (designator.isTermName) TermRef(prefix, designator.asTermName, denot) else TypeRef(prefix, designator.asTypeName, denot) @@ -2052,7 +2053,8 @@ object Types { def apply(prefix: Type, name: TermName, denot: Denotation)(implicit ctx: Context): TermRef = { if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asTerm) else denot match { - case denot: SingleDenotation => apply(prefix, name.withSig(denot.signature)) + case denot: SingleDenotation => + apply(prefix, name.withSig(denot.signature).localizeIfPrivate(denot.symbol)) case _ => apply(prefix, name) } } withDenot denot @@ -2064,7 +2066,7 @@ object Types { */ def withSym(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) apply(prefix, sym) - else apply(prefix, name.withSig(sym.signature)).withSym(sym) + else apply(prefix, name.withSig(sym.signature).localizeIfPrivate(sym)).withSym(sym) def withSym(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = withSym(prefix, sym, sym.name) @@ -2079,7 +2081,7 @@ object Types { /** Create a type ref with given name and initial denotation */ def apply(prefix: Type, name: TypeName, denot: Denotation)(implicit ctx: Context): TypeRef = { if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asType) - else apply(prefix, name) + else apply(prefix, name.localizeIfPrivate(denot.symbol)) } withDenot denot /** Create a type ref referring to either a given symbol or its name. @@ -2089,7 +2091,7 @@ object Types { */ def withSym(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef = if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) apply(prefix, sym) - else apply(prefix, name).withSym(sym) + else apply(prefix, name.localizeIfPrivate(sym)).withSym(sym) def withSym(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = withSym(prefix, sym, sym.name) @@ -2169,7 +2171,7 @@ object Types { } def evaluating = computed && myRef == null override def underlying(implicit ctx: Context) = ref - override def toString = s"LazyRef(...)" + override def toString = s"LazyRef(${if (computed) myRef else "..."})" override def equals(other: Any) = this eq other.asInstanceOf[AnyRef] override def hashCode = System.identityHashCode(this) } diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index b0c5b722d281..d47d9f967303 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -300,7 +300,7 @@ class ClassfileParser( case 'L' => def processInner(tp: Type): Type = tp match { case tp: TypeRef if !(tp.symbol.owner is Flags.ModuleClass) => - TypeRef(processInner(tp.prefix.widen), tp.name) + TypeRef.withSym(processInner(tp.prefix.widen), tp.symbol.asType, tp.name) case _ => tp } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index e1547a958a59..1725df947b48 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -44,7 +44,6 @@ Macro-format: PROTECTEDACCESSOR Length underlying_NameRef PROTECTEDSETTER Length underlying_NameRef INITIALIZER Length underlying_NameRef - SHADOWED Length underlying_NameRef AVOIDCLASH Length underlying_NameRef DIRECT Length underlying_NameRef FIELD Length underlying_NameRef @@ -127,6 +126,7 @@ Standard-Section: "ASTs" TopLevelStat* TERMREFdirect sym_ASTRef TERMREFsymbol sym_ASTRef qual_Type TERMREFpkg fullyQualified_NameRef + TERMREFin Length possiblySigned_NameRef qual_Type namespace_Type TERMREF possiblySigned_NameRef qual_Type THIS clsRef_Type RECthis recType_ASTRef @@ -151,7 +151,8 @@ Standard-Section: "ASTs" TopLevelStat* TYPEREFdirect sym_ASTRef TYPEREFsymbol sym_ASTRef qual_Type TYPEREFpkg fullyQualified_NameRef - TYPEREF possiblySigned_NameRef qual_Type + TYPEREFin Length NameRef qual_Type namespace_Type + TYPEREF NameRef qual_Type RECtype parent_Type TYPEALIAS alias_Type SUPERtype Length this_Type underlying_Type @@ -248,7 +249,6 @@ object TastyFormat { final val PROTECTEDACCESSOR = 21 final val PROTECTEDSETTER = 22 final val INITIALIZER = 23 - final val SHADOWED = 24 final val AVOIDCLASH = 30 final val DIRECT = 31 final val FIELD = 32 @@ -262,6 +262,7 @@ object TastyFormat { final val IMPLMETH = 64 // AST tags + // Cat. 1: tag final val UNITconst = 2 final val FALSEconst = 3 @@ -294,6 +295,8 @@ object TastyFormat { final val DEFAULTparameterized = 30 final val STABLE = 31 + // Cat. 2: tag Nat + final val SHARED = 64 final val TERMREFdirect = 65 final val TYPEREFdirect = 66 @@ -311,6 +314,8 @@ object TastyFormat { final val IMPORTED = 78 final val RENAMED = 79 + // Cat. 3: tag AST + final val THIS = 96 final val QUALTHIS = 97 final val CLASSconst = 98 @@ -325,6 +330,8 @@ object TastyFormat { final val TYPEALIAS = 107 final val SINGLETONtpt = 108 + // Cat. 4: tag Nat AST + final val IDENT = 112 final val IDENTtpt = 113 final val SELECT = 114 @@ -335,6 +342,8 @@ object TastyFormat { final val TYPEREF = 119 final val SELFDEF = 120 + // Cat. 5: tag Length ... + final val PACKAGE = 128 final val VALDEF = 129 final val DEFDEF = 130 @@ -382,6 +391,8 @@ object TastyFormat { final val PARAMtype = 174 final val ANNOTATION = 175 final val TYPEARGtype = 176 + final val TERMREFin = 177 + final val TYPEREFin = 178 final val firstSimpleTreeTag = UNITconst final val firstNatTreeTag = SHARED @@ -456,7 +467,6 @@ object TastyFormat { case PROTECTEDACCESSOR => "PROTECTEDACCESSOR" case PROTECTEDSETTER => "PROTECTEDSETTER" case INITIALIZER => "INITIALIZER" - case SHADOWED => "SHADOWED" case AVOIDCLASH => "AVOIDCLASH" case DIRECT => "DIRECT" case FIELD => "FIELD" @@ -565,6 +575,8 @@ object TastyFormat { case SINGLETONtpt => "SINGLETONtpt" case SUPERtype => "SUPERtype" case TYPEARGtype => "TYPEARGtype" + case TERMREFin => "TERMREFin" + case TYPEREFin => "TYPEREFin" case REFINEDtype => "REFINEDtype" case REFINEDtpt => "REFINEDtpt" case APPLIEDtype => "APPLIEDtype" @@ -593,7 +605,7 @@ object TastyFormat { */ def numRefs(tag: Int) = tag match { case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM | NAMEDARG | RETURN | BIND | - SELFDEF | REFINEDtype => 1 + SELFDEF | REFINEDtype | TERMREFin | TYPEREFin => 1 case RENAMED | PARAMtype => 2 case POLYtype | METHODtype | TYPELAMBDAtype => -1 case _ => 0 diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala index 67f0c763755f..29d06408a6d5 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala @@ -64,8 +64,8 @@ class TastyUnpickler(reader: TastyReader) { val result = readName().toTypeName val params = until(end)(readName().toTypeName) var sig = Signature(params, result) - if (sig == Signature.NotAMethod) sig = Signature.NotAMethod - SignedName(original, sig) + if (sig == Signature.NotAMethod) sig = Signature.NotAMethod // needed temporarily, as long as we read old tasty + original.withSig(sig).asInstanceOf[TermName] case _ => simpleNameKindOfTag(tag)(readName()) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 96a44f638958..4563ac84de1e 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -9,7 +9,7 @@ import TastyFormat._ import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annotations._, StdNames.tpnme, NameOps._ import collection.mutable import typer.Inliner -import NameOps._, NameKinds._ +import NameOps._, NameKinds._, Designators._ import StdNames.nme import TastyBuffer._ import TypeApplications._ @@ -144,15 +144,19 @@ class TreePickler(pickler: TastyPickler) { pickleConstant(value) case tpe: NamedType => val sym = tpe.symbol + def pickleStdRef(name: Name) = { + writeByte(if (tpe.isType) TYPEREF else TERMREF) + pickleName(name); pickleType(tpe.prefix) + } + def pickleDirectRef() = { + writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect) + pickleSymRef(sym) + } if (sym.is(Flags.Package)) { writeByte(if (tpe.isType) TYPEREFpkg else TERMREFpkg) pickleName(sym.fullName) } - else if (tpe.prefix == NoPrefix) { - def pickleDirectRef() = { - writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect) - pickleSymRef(sym) - } + else if (tpe.prefix == NoPrefix) if (sym is Flags.BindDefinedType) { registerDef(sym) writeByte(BIND) @@ -163,22 +167,24 @@ class TreePickler(pickler: TastyPickler) { } } else pickleDirectRef() - } else if (isLocallyDefined(sym)) { writeByte(if (tpe.isType) TYPEREFsymbol else TERMREFsymbol) pickleSymRef(sym); pickleType(tpe.prefix) } - else { - val name = tpe.designator match { - case designator: Symbol => - assert(tpe.symbol.isClass && tpe.symbol.is(Flags.Scala2x), tpe.symbol.showLocated) - // Note: vulnerability here, since Scala2x allows several classes with same name and prefix - designator.name - case designator: Name => - designator - } - writeByte(if (tpe.isType) TYPEREF else TERMREF) - pickleName(name); pickleType(tpe.prefix) + else tpe.designator match { + case sym: Symbol => + assert(tpe.symbol.isClass && tpe.symbol.is(Flags.Scala2x), tpe.symbol.showLocated) + // Note: vulnerability here, since Scala2x allows several classes with same name and prefix + pickleStdRef(sym.name) + case name: Name => + pickleStdRef(name) + case LocalName(name, space) => + writeByte(if (tpe.isType) TYPEREFin else TERMREFin) + withLength { + pickleName(name) + pickleType(tpe.prefix) + pickleType(space) + } } case tpe: ThisType => if (tpe.cls.is(Flags.Package) && !tpe.cls.isEffectiveRoot) { @@ -327,14 +333,10 @@ class TreePickler(pickler: TastyPickler) { } case Select(qual, name) => writeByte(if (name.isTypeName) SELECTtpt else SELECT) - val realName = tree.tpe match { - case tp: NamedType if tp.name.is(ShadowedName) => tp.name - case _ => name - } val sig = tree.tpe.signature pickleName( - if (name.isTypeName || sig == Signature.NotAMethod) realName - else SignedName(realName.toTermName, sig)) + if (sig eq Signature.NotAMethod) name + else SignedName(name.toTermName, sig)) pickleTree(qual) case Apply(fun, args) => writeByte(APPLY) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 029c4c106dc9..85d4ffb666eb 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -220,6 +220,16 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val result = (tag: @switch) match { + case TERMREFin => + var name = readName() + val prefix = readType() + val space = readType().asInstanceOf[TypeRef] + TermRef(prefix, name.withNameSpace(space)) + case TYPEREFin => + val name = readName().toTypeName + val prefix = readType() + val space = readType().asInstanceOf[TypeRef] + TypeRef(prefix, name.withNameSpace(space)) case REFINEDtype => var name: Name = readName() val parent = readType() @@ -710,7 +720,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val cls = ctx.owner.asClass val assumedSelfType = if (cls.is(Module) && cls.owner.isClass) - TermRef(cls.owner.thisType, cls.name.sourceModuleName.withSig(Signature.NotAMethod)) + TermRef(cls.owner.thisType, cls.name.sourceModuleName.localizeIfPrivate(cls)) else NoType cls.info = new TempClassInfo(cls.owner.thisType, cls, cls.unforcedDecls, assumedSelfType) val localDummy = symbolAtCurrent() @@ -849,12 +859,11 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi } } - def completeSelect(name: Name, tpf: Type => Type): Select = { + def completeSelect(name: Name, tpf: Type => NamedType): Select = { val localCtx = if (name == nme.CONSTRUCTOR) ctx.addMode(Mode.InSuperCall) else ctx val qual = readTerm()(localCtx) - val unshadowed = name.exclude(ShadowedName) - untpd.Select(qual, unshadowed).withType(tpf(qual.tpe.widenIfUnstable)) + untpd.Select(qual, name).withType(tpf(qual.tpe.widenIfUnstable)) } def readQualId(): (untpd.Ident, TypeRef) = { @@ -862,6 +871,12 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi (untpd.Ident(qual.name).withPos(qual.pos), qual.tpe.asInstanceOf[TypeRef]) } + def accessibleDenot(pre: Type, name: Name, sig: Signature) = { + val d = pre.member(name).atSignature(sig) + if (!d.symbol.exists || d.symbol.isAccessibleFrom(pre)) d + else pre.nonPrivateMember(name).atSignature(sig) + } + def readSimpleTerm(): Tree = tag match { case SHARED => forkAt(readAddr()).readTerm() @@ -870,15 +885,15 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi case IDENTtpt => untpd.Ident(readName().toTypeName).withType(readType()) case SELECT => - def readRest(name: Name, sig: Signature) = - completeSelect(name, TermRef(_, name.asTermName.withSig(sig))) + def readRest(name: TermName, sig: Signature): Tree = + completeSelect(name, pre => TermRef(pre, name, accessibleDenot(pre, name, sig))) readName() match { case SignedName(name, sig) => readRest(name, sig) case name => readRest(name, Signature.NotAMethod) } case SELECTtpt => val name = readName().toTypeName - completeSelect(name, TypeRef(_, name)) + completeSelect(name, pre => TypeRef(pre, name, accessibleDenot(pre, name, Signature.NotAMethod))) case QUALTHIS => val (qual, tref) = readQualId() untpd.This(qual).withType(ThisType.raw(tref)) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index f0346a17d37c..487d33f53bb5 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -705,7 +705,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas val pre = readTypeRef() val sym = readDisambiguatedSymbolRef(_.info.isParameterless) if (isLocal(sym) || (pre eq NoPrefix)) pre select sym - else TermRef(pre, sym.name.asTermName.withSig(Signature.NotAMethod)) // !!! should become redundant + else TermRef(pre, sym.name.asTermName) case SUPERtpe => val thistpe = readTypeRef() val supertpe = readTypeRef() diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index ef839ea82578..4900fad30962 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -11,7 +11,6 @@ import core.Types._ import core.Names._ import core.StdNames._ import core.NameOps._ -import core.NameKinds.ShadowedName import core.Decorators._ import core.Constants._ import core.Definitions._ @@ -385,14 +384,8 @@ object Erasure { val sym = if (owner eq origSym.owner) origSym else owner.info.decl(origSym.name).symbol assert(sym.exists, origSym.showLocated) - def select(qual: Tree, sym: Symbol): Tree = { - val name = tree.typeOpt match { - case tp: NamedType if tp.name.is(ShadowedName) => sym.name.derived(ShadowedName) - case _ => sym.name - } - untpd.cpy.Select(tree)(qual, sym.name) - .withType(NamedType(qual.tpe, sym)) - } + def select(qual: Tree, sym: Symbol): Tree = + untpd.cpy.Select(tree)(qual, sym.name).withType(NamedType(qual.tpe, sym)) def selectArrayMember(qual: Tree, erasedPre: Type): Tree = if (erasedPre isRef defn.ObjectClass) diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala b/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala index e5f34e60e2af..16d119035e0f 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala @@ -89,8 +89,10 @@ class ExpandPrivate extends MiniPhaseTransform with IdentityDenotTransformer { t (i < 0 || p1(i) == separatorChar) && (j < 0 || p1(j) == separatorChar) } - assert(isSimilar(d.symbol.sourceFile.path, ctx.source.file.path), - i"private ${d.symbol.showLocated} in ${d.symbol.sourceFile} accessed from ${ctx.owner.showLocated} in ${ctx.source.file}") + + assert(d.symbol.sourceFile != null && + isSimilar(d.symbol.sourceFile.path, ctx.source.file.path), + s"private ${d.symbol.showLocated} in ${d.symbol.sourceFile} accessed from ${ctx.owner.showLocated} in ${ctx.source.file}") d.ensureNotPrivate.installAfter(thisTransform) } diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index fb1ae1cf6748..d2125be00af2 100644 --- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala +++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala @@ -72,7 +72,7 @@ class ParamForwarding(thisTransformer: DenotTransformer) { if (alias.owner != currentClass.superClass) // need to use shadowed in order not to accidentally address an // intervening private forwarder in the superclass - superAcc = superAcc.withType(superAcc.tpe.asInstanceOf[TermRef].shadowed) + superAcc = superAcc.withType(superAcc.tpe.asInstanceOf[TermRef].withoutNameSpace) typr.println(i"adding param forwarder $superAcc") DefDef(sym, superAcc.ensureConforms(sym.info.widen)) } @@ -92,11 +92,13 @@ class ParamForwarding(thisTransformer: DenotTransformer) { def adaptRef[T <: RefTree](tree: T)(implicit ctx: Context): T = tree.tpe match { case tpe: TermRef - if tpe.prefix.ne(NoPrefix) && tpe.signature == Signature.NotAMethod && tpe.symbol.is(Method) => + if tpe.prefix.ne(NoPrefix) && tpe.signature.eq(Signature.NotAMethod) && tpe.symbol.is(Method) => // It could be a param forwarder; adapt the signature val newSig = tpe.prefix.memberInfo(tpe.symbol).signature - if (newSig == Signature.NotAMethod) tree - else tree.withType(TermRef(tpe.prefix, tpe.name.withSig(newSig))).asInstanceOf[T] + if (newSig.eq(Signature.NotAMethod)) tree + else tree.withType( + TermRef(tpe.prefix, tpe.name.withSig(newSig).localizeIfPrivate(tpe.symbol))) + .asInstanceOf[T] case _ => tree } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 6ee57d5cd220..d3ff717a9f39 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -244,7 +244,7 @@ object Checking { locked += tp try checkInfo(tp.info) finally locked -= tp - if (pre1 eq pre) tp else tp.newLikeThis(pre1) + if (pre1 eq pre) tp else tp.withPrefix(pre1) } else tp } catch { diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 11ac5b3b98fa..a75a7bfc1c4e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -428,7 +428,7 @@ trait ImplicitRunInfo { self: RunInfo => def addRef(companion: TermRef): Unit = { val compSym = companion.symbol if (compSym is Package) - addRef(TermRef(companion, nme.PACKAGE.withSig(Signature.NotAMethod))) + addRef(TermRef(companion, nme.PACKAGE)) else if (compSym.exists) comps += companion.asSeenFrom(pre, compSym.owner).asInstanceOf[TermRef] } diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 69bce45b1c3e..d8ba1b9d8bd5 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -188,7 +188,7 @@ trait TypeAssigner { // an inherited non-private member with the same name and signature. val d2 = pre.nonPrivateMember(name) if (reallyExists(d2) && firstTry) - test(tpe.shadowed.withDenot(d2), false) + test(tpe.withoutNameSpace.withDenot(d2), false) else if (pre.derivesFrom(defn.DynamicClass)) { TryDynamicCallType } else { diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index d94a5851574e..7947a21a2b2d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -663,7 +663,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val ptDefined = isFullyDefined(pt, ForceDegree.none) if (ptDefined && !(avoidingType <:< pt)) avoidingType = pt val tree1 = ascribeType(tree, avoidingType) - assert(ptDefined || noLeaks(tree1), // `ptDefined` needed because of special case of anonymous classes + assert(ptDefined || noLeaks(tree1) || tree1.tpe.widen.isErroneous, + // `ptDefined` needed because of special case of anonymous classes i"leak: ${escapingRefs(tree1, localSyms).toList}%, % in $tree1") tree1 }