Skip to content

Rename @alpha to @targetName #10149

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 20 commits into from
Nov 10, 2020
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
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -882,16 +882,16 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}

/** A select node with the given selector name and signature and a computed type */
def selectWithSig(name: Name, sig: Signature)(using Context): Tree =
untpd.SelectWithSig(tree, name, sig).withType(tree.tpe.select(name.asTermName, sig))
def selectWithSig(name: Name, sig: Signature, target: Name)(using Context): Tree =
untpd.SelectWithSig(tree, name, sig).withType(tree.tpe.select(name.asTermName, sig, target))

/** A select node with selector name and signature taken from `sym`.
* Note: Use this method instead of select(sym) if the referenced symbol
* might be overridden in the type of the qualifier prefix. See note
* on select(sym: Symbol).
*/
def selectWithSig(sym: Symbol)(using Context): Tree =
selectWithSig(sym.name, sym.signature)
selectWithSig(sym.name, sym.signature, sym.targetName)

/** A unary apply node with given argument: `tree(arg)` */
def appliedTo(arg: Tree)(using Context): Apply =
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/config/Printers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ object Printers {
val pickling = noPrinter
val quotePickling = noPrinter
val plugins = noPrinter
val refcheck = noPrinter
val simplify = noPrinter
val staging = noPrinter
val subtyping = noPrinter
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ class ScalaSettings extends Settings.SettingGroup {
val YexplicitNulls: Setting[Boolean] = BooleanSetting("-Yexplicit-nulls", "Make reference types non-nullable. Nullable types can be expressed with unions: e.g. String|Null.")
val YerasedTerms: Setting[Boolean] = BooleanSetting("-Yerased-terms", "Allows the use of erased terms.")
val YcheckInit: Setting[Boolean] = BooleanSetting("-Ycheck-init", "Check initialization of objects")
val YrequireAlpha: Setting[Boolean] = BooleanSetting("-Yrequire-alpha", "Warn if an operator is defined without an @alpha annotation")
val YrequireTargetName: Setting[Boolean] = BooleanSetting("-Yrequire-targetName", "Warn if an operator is defined without a @targetName annotation")

/** Area-specific debug output */
val YexplainLowlevel: Setting[Boolean] = BooleanSetting("-Yexplain-lowlevel", "When explaining type errors, show types at a lower level.")
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,7 @@ class Definitions {
@tu lazy val ShowAsInfixAnnot: ClassSymbol = requiredClass("scala.annotation.showAsInfix")
@tu lazy val FunctionalInterfaceAnnot: ClassSymbol = requiredClass("java.lang.FunctionalInterface")
@tu lazy val InfixAnnot: ClassSymbol = requiredClass("scala.annotation.infix")
@tu lazy val AlphaAnnot: ClassSymbol = requiredClass("scala.annotation.alpha")
@tu lazy val TargetNameAnnot: ClassSymbol = requiredClass("scala.annotation.targetName")
@tu lazy val VarargsAnnot: ClassSymbol = requiredClass("scala.annotation.varargs")

// A list of annotations that are commonly used to indicate that a field/method argument or return
Expand Down
36 changes: 21 additions & 15 deletions compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ object Denotations {
* when seen from prefix `site`.
* @param relaxed When true, consider only parameter signatures for a match.
*/
def atSignature(sig: Signature, site: Type = NoPrefix, relaxed: Boolean = false)(using Context): Denotation
def atSignature(sig: Signature, targetName: Name, site: Type = NoPrefix, relaxed: Boolean = false)(using Context): Denotation

/** The variant of this denotation that's current in the given context.
* If no such denotation exists, returns the denotation with each alternative
Expand Down Expand Up @@ -347,13 +347,15 @@ object Denotations {
}

/** The alternative of this denotation that has a type matching `targetType` when seen
* as a member of type `site`, `NoDenotation` if none exists.
* as a member of type `site` and that has a target name matching `targetName`, or
* `NoDenotation` if none exists.
*/
def matchingDenotation(site: Type, targetType: Type)(using Context): SingleDenotation = {
def qualifies(sym: Symbol) = site.memberInfo(sym).matchesLoosely(targetType)
def matchingDenotation(site: Type, targetType: Type, targetName: Name)(using Context): SingleDenotation = {
def qualifies(sym: Symbol) =
site.memberInfo(sym).matchesLoosely(targetType) && sym.hasTargetName(targetName)
if (isOverloaded)
atSignature(targetType.signature, site, relaxed = true) match {
case sd: SingleDenotation => sd.matchingDenotation(site, targetType)
atSignature(targetType.signature, targetName, site, relaxed = true) match {
case sd: SingleDenotation => sd.matchingDenotation(site, targetType, targetName)
case md => md.suchThat(qualifies(_))
}
else if (exists && !qualifies(symbol)) NoDenotation
Expand Down Expand Up @@ -610,9 +612,9 @@ object Denotations {
def accessibleFrom(pre: Type, superAccess: Boolean)(using Context): Denotation =
if (!symbol.exists || symbol.isAccessibleFrom(pre, superAccess)) this else NoDenotation

def atSignature(sig: Signature, site: Type, relaxed: Boolean)(using Context): SingleDenotation =
def atSignature(sig: Signature, targetName: Name, site: Type, relaxed: Boolean)(using Context): SingleDenotation =
val situated = if site == NoPrefix then this else asSeenFrom(site)
val matches = sig.matchDegree(situated.signature) match
val sigMatches = sig.matchDegree(situated.signature) match
case FullMatch =>
true
case MethodNotAMethodMatch =>
Expand All @@ -622,7 +624,7 @@ object Denotations {
relaxed
case noMatch =>
false
if matches then this else NoDenotation
if sigMatches && symbol.hasTargetName(targetName) then this else NoDenotation

def matchesImportBound(bound: Type)(using Context): Boolean =
if bound.isRef(defn.NothingClass) then false
Expand Down Expand Up @@ -983,8 +985,12 @@ object Denotations {
final def last: SingleDenotation = this

def matches(other: SingleDenotation)(using Context): Boolean =
val d = signature.matchDegree(other.signature)
symbol.hasTargetName(other.symbol.targetName)
&& matchesLoosely(other)

/** matches without a target name check */
def matchesLoosely(other: SingleDenotation)(using Context): Boolean =
val d = signature.matchDegree(other.signature)
d match
case FullMatch =>
true
Expand All @@ -1006,11 +1012,10 @@ object Denotations {
other.symbol.is(Method)
}
case ParamMatch =>
// The signatures do not tell us enough to be sure about matching
// The signatures do not tell us enough to be sure about matching
!ctx.erasedTypes && info.matches(other.info)
case noMatch =>
false
end matches

def mapInherited(ownDenots: PreDenotation, prevDenots: PreDenotation, pre: Type)(using Context): SingleDenotation =
if hasUniqueSym && prevDenots.containsSym(symbol) then NoDenotation
Expand Down Expand Up @@ -1164,9 +1169,11 @@ object Denotations {
final def hasUniqueSym: Boolean = false
final def name(using Context): Name = denot1.name
final def signature(using Context): Signature = Signature.OverloadedSignature
def atSignature(sig: Signature, site: Type, relaxed: Boolean)(using Context): Denotation =
def atSignature(sig: Signature, targetName: Name, site: Type, relaxed: Boolean)(using Context): Denotation =
if (sig eq Signature.OverloadedSignature) this
else derivedUnionDenotation(denot1.atSignature(sig, site, relaxed), denot2.atSignature(sig, site, relaxed))
else derivedUnionDenotation(
denot1.atSignature(sig, targetName, site, relaxed),
denot2.atSignature(sig, targetName, site, relaxed))
def current(using Context): Denotation =
derivedUnionDenotation(denot1.current, denot2.current)
def altsWith(p: Symbol => Boolean): List[SingleDenotation] =
Expand Down Expand Up @@ -1263,7 +1270,6 @@ object Denotations {
else ctx.run.staticRefs.getOrElseUpdate(path, recur(path))
}


/** If we are looking for a non-existing term name in a package,
* assume it is a package for which we do not have a directory and
* enter it.
Expand Down
14 changes: 8 additions & 6 deletions compiler/src/dotty/tools/dotc/core/NameKinds.scala
Original file line number Diff line number Diff line change
Expand Up @@ -371,17 +371,19 @@ object NameKinds {
/** A name together with a signature. Used in Tasty trees. */
object SignedName extends NameKind(SIGNED) {

case class SignedInfo(sig: Signature) extends Info {
case class SignedInfo(sig: Signature, target: TermName) extends Info {
assert(sig ne Signature.NotAMethod)
override def toString: String = s"$infoString $sig"
override def toString: String =
val targetStr = if target.isEmpty then "" else s" @$target"
s"$infoString $sig$targetStr"
override def hashCode = scala.runtime.ScalaRunTime._hashCode(this) * 31 + kind.hashCode
}
type ThisInfo = SignedInfo

def apply(qual: TermName, sig: Signature): TermName =
qual.derived(new SignedInfo(sig))
def unapply(name: DerivedName): Option[(TermName, Signature)] = name match {
case DerivedName(underlying, info: SignedInfo) => Some((underlying, info.sig))
def apply(qual: TermName, sig: Signature, target: TermName): TermName =
qual.derived(new SignedInfo(sig, target))
def unapply(name: DerivedName): Option[(TermName, Signature, TermName)] = name match {
case DerivedName(underlying, info: SignedInfo) => Some((underlying, info.sig, info.target))
case _ => None
}

Expand Down
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ object NameOps {
}
}

/** Do two target names match? An empty target name matchws any other name. */
def matchesTargetName(other: Name) =
name == other || name.isEmpty || other.isEmpty

private def functionSuffixStart: Int =
val first = name.firstPart
var idx = first.length - 1
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/NameTags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@ object NameTags extends TastyFormat.NameTags {
case OBJECTCLASS => "OBJECTCLASS"

case SIGNED => "SIGNED"
case TARGETSIGNED => "TARGETSIGNED"
}
}
51 changes: 33 additions & 18 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -495,26 +495,40 @@ object SymDenotations {
/** `fullName` where `.' is the separator character */
def fullName(using Context): Name = fullNameSeparated(QualifiedName)

/** The name given in an `@alpha` annotation if one is present, `name` otherwise */
final def erasedName(using Context): Name =
val alphaAnnot =
if isAllOf(ModuleClass | Synthetic) then companionClass.getAnnotation(defn.AlphaAnnot)
else getAnnotation(defn.AlphaAnnot)
alphaAnnot match {
private var myTargetName: Name = null

private def computeTargetName(targetNameAnnot: Option[Annotation])(using Context): Name =
targetNameAnnot match
case Some(ann) =>
ann.arguments match {
ann.arguments match
case Literal(Constant(str: String)) :: Nil =>
if (isType)
if (is(ModuleClass))
str.toTypeName.moduleClassName
else
str.toTypeName
else
str.toTermName
if isType then
if is(ModuleClass) then str.toTypeName.moduleClassName
else str.toTypeName
else str.toTermName
case _ => name
}
case _ => name
}

def setTargetName(name: Name): Unit =
myTargetName = name

def hasTargetName(name: Name)(using Context): Boolean =
targetName.matchesTargetName(name)

/** The name given in a `@targetName` annotation if one is present, `name` otherwise */
def targetName(using Context): Name =
if myTargetName == null then
val carrier: SymDenotation =
if isAllOf(ModuleClass | Synthetic) then companionClass else this
val targetNameAnnot =
if carrier.isCompleting // annotations have been set already in this case
then carrier.unforcedAnnotation(defn.TargetNameAnnot)
else carrier.getAnnotation(defn.TargetNameAnnot)
myTargetName = computeTargetName(targetNameAnnot)
if name.is(SuperAccessorName) then
myTargetName = myTargetName.unmangle(List(ExpandedName, SuperAccessorName, ExpandPrefixName))

myTargetName

// ----- Tests -------------------------------------------------

Expand Down Expand Up @@ -1243,7 +1257,7 @@ object SymDenotations {
final def matchingDecl(inClass: Symbol, site: Type)(using Context): Symbol = {
var denot = inClass.info.nonPrivateDecl(name)
if (denot.isTerm) // types of the same name always match
denot = denot.matchingDenotation(site, site.memberInfo(symbol))
denot = denot.matchingDenotation(site, site.memberInfo(symbol), symbol.targetName)
denot.symbol
}

Expand All @@ -1252,7 +1266,7 @@ object SymDenotations {
final def matchingMember(site: Type)(using Context): Symbol = {
var denot = site.nonPrivateMember(name)
if (denot.isTerm) // types of the same name always match
denot = denot.matchingDenotation(site, site.memberInfo(symbol))
denot = denot.matchingDenotation(site, site.memberInfo(symbol), symbol.targetName)
denot.symbol
}

Expand Down Expand Up @@ -2323,6 +2337,7 @@ object SymDenotations {
override def mapInfo(f: Type => Type)(using Context): SingleDenotation = this

override def matches(other: SingleDenotation)(using Context): Boolean = false
override def targetName(using Context): Name = EmptyTermName
override def mapInherited(ownDenots: PreDenotation, prevDenots: PreDenotation, pre: Type)(using Context): SingleDenotation = this
override def filterWithPredicate(p: SingleDenotation => Boolean): SingleDenotation = this
override def filterDisjoint(denots: PreDenotation)(using Context): SingleDenotation = this
Expand Down
15 changes: 8 additions & 7 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1457,8 +1457,8 @@ object Types {
def select(name: TermName)(using Context): TermRef =
TermRef(this, name, member(name))

def select(name: TermName, sig: Signature)(using Context): TermRef =
TermRef(this, name, member(name).atSignature(sig, relaxed = !ctx.erasedTypes))
def select(name: TermName, sig: Signature, target: Name)(using Context): TermRef =
TermRef(this, name, member(name).atSignature(sig, target, relaxed = !ctx.erasedTypes))

// ----- Access to parts --------------------------------------------

Expand Down Expand Up @@ -2084,14 +2084,14 @@ object Types {
}

private def disambiguate(d: Denotation)(using Context): Denotation =
disambiguate(d, currentSignature)
disambiguate(d, currentSignature, currentSymbol.targetName)

private def disambiguate(d: Denotation, sig: Signature)(using Context): Denotation =
private def disambiguate(d: Denotation, sig: Signature, target: Name)(using Context): Denotation =
if (sig != null)
d.atSignature(sig, relaxed = !ctx.erasedTypes) match {
d.atSignature(sig, target, relaxed = !ctx.erasedTypes) match {
case d1: SingleDenotation => d1
case d1 =>
d1.atSignature(sig, relaxed = false) match {
d1.atSignature(sig, target, relaxed = false) match {
case d2: SingleDenotation => d2
case d2 => d2.suchThat(currentSymbol.eq).orElse(d2)
}
Expand Down Expand Up @@ -2395,7 +2395,8 @@ object Types {
if (d.isOverloaded && lastSymbol.exists)
d = disambiguate(d,
if (lastSymbol.signature == Signature.NotAMethod) Signature.NotAMethod
else lastSymbol.asSeenFrom(prefix).signature)
else lastSymbol.asSeenFrom(prefix).signature,
lastSymbol.targetName)
NamedType(prefix, name, d)
}
if (prefix eq this.prefix) this
Expand Down
23 changes: 18 additions & 5 deletions compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import TastyBuffer._
import collection.mutable
import Names.{Name, chrs, SimpleName, DerivedName, TypeName}
import NameKinds._
import NameOps._
import Decorators._
import scala.io.Codec
import NameTags.{SIGNED, TARGETSIGNED}

class NameBuffer extends TastyBuffer(10000) {
import NameBuffer._
Expand All @@ -24,8 +26,9 @@ class NameBuffer extends TastyBuffer(10000) {
ref
case None =>
name1 match {
case SignedName(original, Signature(params, result)) =>
case SignedName(original, Signature(params, result), target) =>
nameIndex(original)
if !original.matchesTargetName(target) then nameIndex(target)
nameIndex(result)
params.foreach {
case param: TypeName =>
Expand Down Expand Up @@ -70,29 +73,39 @@ class NameBuffer extends TastyBuffer(10000) {

def pickleNameContents(name: Name): Unit = {
val tag = name.toTermName.info.kind.tag
writeByte(tag)
name.toTermName match {
case name: SimpleName =>
writeByte(tag)
val bytes =
if (name.length == 0) new Array[Byte](0)
else Codec.toUTF8(chrs, name.start, name.length)
writeNat(bytes.length)
writeBytes(bytes, bytes.length)
case AnyQualifiedName(prefix, name) =>
writeByte(tag)
withLength { writeNameRef(prefix); writeNameRef(name) }
case AnyUniqueName(original, separator, num) =>
writeByte(tag)
withLength {
writeNameRef(separator)
writeNat(num)
if (!original.isEmpty) writeNameRef(original)
}
case AnyNumberedName(original, num) =>
writeByte(tag)
withLength { writeNameRef(original); writeNat(num) }
case SignedName(original, Signature(paramsSig, result)) =>
case SignedName(original, Signature(paramsSig, result), target) =>
val needsTarget = !original.matchesTargetName(target)
writeByte(if needsTarget then TARGETSIGNED else SIGNED)
withLength(
{ writeNameRef(original); writeNameRef(result); paramsSig.foreach(writeParamSig) },
if ((paramsSig.length + 2) * maxIndexWidth <= maxNumInByte) 1 else 2)
{ writeNameRef(original)
if needsTarget then writeNameRef(target)
writeNameRef(result)
paramsSig.foreach(writeParamSig)
},
if ((paramsSig.length + 3) * maxIndexWidth <= maxNumInByte) 1 else 2)
case DerivedName(original, _) =>
writeByte(tag)
withLength { writeNameRef(original) }
}
}
Expand Down
Loading