Skip to content

More robust way to refer to private definitions in types #3167

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Sep 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 =>
Expand Down Expand Up @@ -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)
}
Expand All @@ -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 = {
Expand All @@ -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(" <and> ")

private def multiHasNot(op: String): Nothing =
Expand Down
50 changes: 49 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Designators.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ 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
* Designators are used in reference type to identity what is referred to.
*/
object Designators {

abstract class Designator extends util.DotClass {
abstract class Designator extends util.DotClass { self =>

type ThisName <: Name

Expand All @@ -23,8 +26,53 @@ 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 } =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this function be defined in Name instead of Designator?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because it is overridden in LocalName.

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 }

/** Names that come with the namespace where they are defined.
* Used to give a stable reference to private names, and also to
* Scala 2x inner classes.
*/
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 }]
}
9 changes: 5 additions & 4 deletions compiler/src/dotty/tools/dotc/core/NameKinds.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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"
}
Expand Down Expand Up @@ -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_$")
Expand All @@ -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
Expand Down
2 changes: 0 additions & 2 deletions compiler/src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,5 @@ object NameOps {
case raw.BANG => UNARY_!
case _ => name
}

def withSig(sig: Signature) = SignedName(name.exclude(SignedName), sig)
}
}
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "$"
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Substituters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
16 changes: 14 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 = _
Expand Down Expand Up @@ -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)))
Expand Down Expand Up @@ -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
}
Expand Down
Loading