aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/core/NameOps.scala
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/src/dotty/tools/dotc/core/NameOps.scala')
-rw-r--r--compiler/src/dotty/tools/dotc/core/NameOps.scala409
1 files changed, 95 insertions, 314 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala
index 240ad359b..915bd52ab 100644
--- a/compiler/src/dotty/tools/dotc/core/NameOps.scala
+++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala
@@ -4,11 +4,12 @@ package core
import java.security.MessageDigest
import scala.annotation.switch
import scala.io.Codec
-import Names._, StdNames._, Contexts._, Symbols._, Flags._
+import Names._, StdNames._, Contexts._, Symbols._, Flags._, NameKinds._
import Decorators.PreNamedString
import util.{Chars, NameTransformer}
import Chars.isOperatorPart
import Definitions._
+import config.Config
object NameOps {
@@ -48,212 +49,97 @@ object NameOps {
}
}
- class PrefixNameExtractor(pre: TermName) {
- def apply(name: TermName): TermName = pre ++ name
- def unapply(name: TermName): Option[TermName] =
- if (name startsWith pre) Some(name.drop(pre.length).asTermName) else None
- }
-
- object SuperAccessorName extends PrefixNameExtractor(nme.SUPER_PREFIX)
- object InitializerName extends PrefixNameExtractor(nme.INITIALIZER_PREFIX)
-
implicit class NameDecorator[N <: Name](val name: N) extends AnyVal {
import nme._
- def likeTyped(n: PreName): N =
+ def testSimple(f: SimpleTermName => Boolean): Boolean = name match {
+ case name: SimpleTermName => f(name)
+ case name: TypeName => name.toTermName.testSimple(f)
+ case _ => false
+ }
+
+ def likeSpaced(n: PreName): N =
(if (name.isTermName) n.toTermName else n.toTypeName).asInstanceOf[N]
def isConstructorName = name == CONSTRUCTOR || name == TRAIT_CONSTRUCTOR
def isStaticConstructorName = name == STATIC_CONSTRUCTOR
- def isExceptionResultName = name startsWith EXCEPTION_RESULT_PREFIX
- def isImplClassName = name endsWith IMPL_CLASS_SUFFIX
- def isLocalDummyName = name startsWith LOCALDUMMY_PREFIX
- def isLoopHeaderLabel = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX)
- def isProtectedAccessorName = name startsWith PROTECTED_PREFIX
- def isReplWrapperName = name containsSlice INTERPRETER_IMPORT_WRAPPER
- def isTraitSetterName = name containsSlice TRAIT_SETTER_SEPARATOR
- def isSetterName = name endsWith SETTER_SUFFIX
- def isSingletonName = name endsWith SINGLETON_SUFFIX
- def isModuleClassName = name endsWith MODULE_SUFFIX
- def isAvoidClashName = name endsWith AVOID_CLASH_SUFFIX
- def isImportName = name startsWith IMPORT
- def isFieldName = name endsWith LOCAL_SUFFIX
- def isShadowedName = name.length > 0 && name.head == '(' && name.startsWith(nme.SHADOWED)
- def isDefaultGetterName = name.isTermName && name.asTermName.defaultGetterIndex >= 0
- def isScala2LocalSuffix = name.endsWith(" ")
- def isModuleVarName(name: Name): Boolean =
- name.stripAnonNumberSuffix endsWith MODULE_VAR_SUFFIX
- def isSelectorName = name.startsWith(" ") && name.tail.forall(_.isDigit)
- def isLazyLocal = name.endsWith(nme.LAZY_LOCAL)
- def isOuterSelect = name.endsWith(nme.OUTER_SELECT)
- def isInlineAccessor = name.startsWith(nme.INLINE_ACCESSOR_PREFIX)
+ def isLocalDummyName = name startsWith str.LOCALDUMMY_PREFIX
+ def isReplWrapperName = name.toString contains str.INTERPRETER_IMPORT_WRAPPER
+ def isSetterName = name endsWith str.SETTER_SUFFIX
+ def isScala2LocalSuffix = testSimple(_.endsWith(" "))
+ def isSelectorName = testSimple(n => n.startsWith("_") && n.drop(1).forall(_.isDigit))
/** Is name a variable name? */
- def isVariableName: Boolean = name.length > 0 && {
- val first = name.head
- (((first.isLower && first.isLetter) || first == '_')
- && (name != false_)
- && (name != true_)
- && (name != null_))
+ def isVariableName: Boolean = testSimple { n =>
+ n.length > 0 && {
+ val first = n.head
+ (((first.isLower && first.isLetter) || first == '_')
+ && (n != false_)
+ && (n != true_)
+ && (n != null_))
+ }
}
def isOpAssignmentName: Boolean = name match {
case raw.NE | raw.LE | raw.GE | EMPTY =>
false
- case _ =>
+ case name: SimpleTermName =>
name.length > 0 && name.last == '=' && name.head != '=' && isOperatorPart(name.head)
- }
-
- /** If the name ends with $nn where nn are
- * all digits, strip the $ and the digits.
- * Otherwise return the argument.
- */
- def stripAnonNumberSuffix: Name = {
- var pos = name.length
- while (pos > 0 && name(pos - 1).isDigit)
- pos -= 1
-
- if (pos > 0 && pos < name.length && name(pos - 1) == '$')
- name take (pos - 1)
- else
- name
+ case _ =>
+ false
}
/** Convert this module name to corresponding module class name */
- def moduleClassName: TypeName = (name ++ tpnme.MODULE_SUFFIX).toTypeName
+ def moduleClassName: TypeName = name.derived(ModuleClassName).toTypeName
/** Convert this module class name to corresponding source module name */
- def sourceModuleName: TermName = stripModuleClassSuffix.toTermName
-
- /** If name ends in module class suffix, drop it */
- def stripModuleClassSuffix: Name =
- if (isModuleClassName) name dropRight MODULE_SUFFIX.length else name
-
- /** Append a suffix so that this name does not clash with another name in the same scope */
- def avoidClashName: TermName = (name ++ AVOID_CLASH_SUFFIX).toTermName
+ def sourceModuleName: TermName = name.toTermName.exclude(ModuleClassName)
- /** If name ends in "avoid clash" suffix, drop it */
- def stripAvoidClashSuffix: Name =
- if (isAvoidClashName) name dropRight AVOID_CLASH_SUFFIX.length else name
+ /** If name ends in module class suffix, drop it. This
+ * method needs to work on mangled as well as unmangled names because
+ * it is also called from the backend.
+ */
+ def stripModuleClassSuffix: N = likeSpaced {
+ val semName =
+ if (name.isSimple && name.endsWith("$")) name.unmangleClassName else name
+ semName.exclude(ModuleClassName)
+ }
/** If flags is a ModuleClass but not a Package, add module class suffix */
- def adjustIfModuleClass(flags: Flags.FlagSet): N = {
+ def adjustIfModuleClass(flags: Flags.FlagSet): N = likeSpaced {
if (flags is (ModuleClass, butNot = Package)) name.asTypeName.moduleClassName
- else stripAvoidClashSuffix
- }.asInstanceOf[N]
-
- /** The superaccessor for method with given name */
- def superName: TermName = (nme.SUPER_PREFIX ++ name).toTermName
-
- /** The expanded name of `name` relative to given class `base`.
- */
- def expandedName(base: Symbol, separator: Name)(implicit ctx: Context): N =
- expandedName(if (base is Flags.ExpandedName) base.name else base.fullNameSeparated("$"), separator)
-
- def expandedName(base: Symbol)(implicit ctx: Context): N = expandedName(base, nme.EXPAND_SEPARATOR)
-
- /** The expanded name of `name` relative to `basename` with given `separator`
- */
- def expandedName(prefix: Name, separator: Name = nme.EXPAND_SEPARATOR): N =
- name.fromName(prefix ++ separator ++ name).asInstanceOf[N]
-
- def expandedName(prefix: Name): N = expandedName(prefix, nme.EXPAND_SEPARATOR)
-
- /** Revert the expanded name. Note: This currently gives incorrect results
- * if the normal name contains `nme.EXPAND_SEPARATOR`, i.e. two consecutive '$'
- * signs. This can happen for instance if a super accessor is paired with
- * an encoded name, e.g. super$$plus$eq. See #765.
- */
- def unexpandedName: N = {
- var idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR)
-
- // Hack to make super accessors from traits work. They would otherwise fail because of #765
- // TODO: drop this once we have more robust name handling
- if (idx > FalseSuperLength && name.slice(idx - FalseSuperLength, idx) == FalseSuper)
- idx -= FalseSuper.length
-
- if (idx < 0) name else (name drop (idx + nme.EXPAND_SEPARATOR.length)).asInstanceOf[N]
+ else name.toTermName.exclude(AvoidClashName)
}
- def expandedPrefix: N = {
- val idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR)
- assert(idx >= 0)
- name.take(idx).asInstanceOf[N]
+ def expandedName(base: Symbol, kind: QualifiedNameKind = ExpandedName)(implicit ctx: Context): N = {
+ val prefix =
+ if (base.name.is(ExpandedName)) base.name else base.fullNameSeparated(ExpandPrefixName)
+ likeSpaced { kind(prefix.toTermName, name.toTermName) }
}
- def shadowedName: N = likeTyped(nme.SHADOWED ++ name)
-
- def revertShadowed: N = likeTyped(name.drop(nme.SHADOWED.length))
-
- def implClassName: N = likeTyped(name ++ tpnme.IMPL_CLASS_SUFFIX)
+ /** Revert the expanded name. */
+ def unexpandedName: N = likeSpaced {
+ name.rewrite { case ExpandedName(_, unexp) => unexp }
+ }
- def errorName: N = likeTyped(name ++ nme.ERROR)
+ def implClassName: N = likeSpaced(name ++ tpnme.IMPL_CLASS_SUFFIX)
- def directName: N = likeTyped(name ++ DIRECT_SUFFIX)
+ def errorName: N = likeSpaced(name ++ nme.ERROR)
- def freshened(implicit ctx: Context): N =
- likeTyped(
- if (name.isModuleClassName) name.stripModuleClassSuffix.freshened.moduleClassName
- else likeTyped(ctx.freshName(name ++ NameTransformer.NAME_JOIN_STRING)))
/** Name with variance prefix: `+` for covariant, `-` for contravariant */
def withVariance(v: Int): N =
- if (hasVariance) dropVariance.withVariance(v)
- else v match {
- case -1 => likeTyped('-' +: name)
- case 1 => likeTyped('+' +: name)
- case 0 => name
- }
-
- /** Does name have a `+`/`-` variance prefix? */
- def hasVariance: Boolean =
- name.nonEmpty && name.head == '+' || name.head == '-'
-
- /** Drop variance prefix if name has one */
- def dropVariance: N = if (hasVariance) likeTyped(name.tail) else name
+ likeSpaced { VariantName(name.exclude(VariantName).toTermName, v) }
/** The variance as implied by the variance prefix, or 0 if there is
* no variance prefix.
*/
- def variance = name.head match {
- case '-' => -1
- case '+' => 1
- case _ => 0
- }
+ def variance = name.collect { case VariantName(_, n) => n }.getOrElse(0)
- /** Translate a name into a list of simple TypeNames and TermNames.
- * In all segments before the last, type/term is determined by whether
- * the following separator char is '.' or '#'. The last segment
- * is of the same type as the original name.
- *
- * Examples:
- *
- * package foo {
- * object Lorax { object Wog ; class Wog }
- * class Lorax { object Zax ; class Zax }
- * }
- *
- * f("foo.Lorax".toTermName) == List("foo": Term, "Lorax": Term) // object Lorax
- * f("foo.Lorax".toTypeName) == List("foo": Term, "Lorax": Type) // class Lorax
- * f("Lorax.Wog".toTermName) == List("Lorax": Term, "Wog": Term) // object Wog
- * f("Lorax.Wog".toTypeName) == List("Lorax": Term, "Wog": Type) // class Wog
- * f("Lorax#Zax".toTermName) == List("Lorax": Type, "Zax": Term) // object Zax
- * f("Lorax#Zax".toTypeName) == List("Lorax": Type, "Zax": Type) // class Zax
- *
- * Note that in actual scala syntax you cannot refer to object Zax without an
- * instance of Lorax, so Lorax#Zax could only mean the type. One might think
- * that Lorax#Zax.type would work, but this is not accepted by the parser.
- * For the purposes of referencing that object, the syntax is allowed.
- */
- def segments: List[Name] = {
- def mkName(name: Name, follow: Char): Name =
- if (follow == '.') name.toTermName else name.toTypeName
-
- name.indexWhere(ch => ch == '.' || ch == '#') match {
- case -1 =>
- if (name.isEmpty) scala.Nil else name :: scala.Nil
- case idx =>
- mkName(name take idx, name(idx)) :: (name drop (idx + 1)).segments
+ def freshened(implicit ctx: Context): N = likeSpaced {
+ name.toTermName match {
+ case ModuleClassName(original) => ModuleClassName(original.freshened)
+ case name => UniqueName.fresh(name)
}
}
@@ -263,7 +149,7 @@ object NameOps {
* - (-1) otherwise
*/
def functionArity: Int =
- functionArityFor(tpnme.Function) max functionArityFor(tpnme.ImplicitFunction)
+ functionArityFor(str.Function) max functionArityFor(str.ImplicitFunction)
/** Is a function name
* - FunctionN for N >= 0
@@ -276,7 +162,7 @@ object NameOps {
* - ImplicitFunctionN for N >= 0
* - false otherwise
*/
- def isImplicitFunction: Boolean = functionArityFor(tpnme.ImplicitFunction) >= 0
+ def isImplicitFunction: Boolean = functionArityFor(str.ImplicitFunction) >= 0
/** Is a synthetic function name
* - FunctionN for N > 22
@@ -284,24 +170,18 @@ object NameOps {
* - false otherwise
*/
def isSyntheticFunction: Boolean = {
- functionArityFor(tpnme.Function) > MaxImplementedFunctionArity ||
- functionArityFor(tpnme.ImplicitFunction) >= 0
+ functionArityFor(str.Function) > MaxImplementedFunctionArity ||
+ functionArityFor(str.ImplicitFunction) >= 0
}
/** Parsed function arity for function with some specific prefix */
- private def functionArityFor(prefix: Name): Int = {
+ private def functionArityFor(prefix: String): Int = {
if (name.startsWith(prefix))
try name.toString.substring(prefix.length).toInt
catch { case _: NumberFormatException => -1 }
else -1
}
- /** The number of hops specified in an outer-select name */
- def outerSelectHops: Int = {
- require(isOuterSelect)
- name.dropRight(nme.OUTER_SELECT.length).toString.toInt
- }
-
/** The name of the generic runtime operation corresponding to an array operation */
def genericArrayOp: TermName = name match {
case nme.apply => nme.array_apply
@@ -338,100 +218,61 @@ object NameOps {
val methodTags: Seq[Name] = (methodTargs zip methodTarsNames).sortBy(_._2).map(x => typeToTag(x._1))
val classTags: Seq[Name] = (classTargs zip classTargsNames).sortBy(_._2).map(x => typeToTag(x._1))
- name.fromName(name ++ nme.specializedTypeNames.prefix ++
+ name.likeSpaced(name ++ nme.specializedTypeNames.prefix ++
methodTags.fold(nme.EMPTY)(_ ++ _) ++ nme.specializedTypeNames.separator ++
classTags.fold(nme.EMPTY)(_ ++ _) ++ nme.specializedTypeNames.suffix)
}
/** If name length exceeds allowable limit, replace part of it by hash */
def compactified(implicit ctx: Context): TermName = termName(compactify(name.toString))
- }
- // needed???
- private val Boxed = Map[TypeName, TypeName](
- tpnme.Boolean -> jtpnme.BoxedBoolean,
- tpnme.Byte -> jtpnme.BoxedByte,
- tpnme.Char -> jtpnme.BoxedCharacter,
- tpnme.Short -> jtpnme.BoxedShort,
- tpnme.Int -> jtpnme.BoxedInteger,
- tpnme.Long -> jtpnme.BoxedLong,
- tpnme.Float -> jtpnme.BoxedFloat,
- tpnme.Double -> jtpnme.BoxedDouble)
+ def unmangleClassName: N = name.toTermName match {
+ case name: SimpleTermName
+ if name.endsWith(str.MODULE_SUFFIX) && !nme.falseModuleClassNames.contains(name) =>
+ likeSpaced(name.dropRight(str.MODULE_SUFFIX.length).moduleClassName)
+ case _ => name
+ }
+
+ def unmangle(kind: NameKind): N = likeSpaced {
+ name rewrite {
+ case unmangled: SimpleTermName =>
+ kind.unmangle(unmangled)
+ case ExpandedName(prefix, last) =>
+ kind.unmangle(last) rewrite {
+ case kernel: SimpleTermName =>
+ ExpandedName(prefix, kernel)
+ }
+ }
+ }
+
+ def unmangle(kinds: List[NameKind]): N = {
+ val unmangled = (name /: kinds)(_.unmangle(_))
+ if (unmangled eq name) name else unmangled.unmangle(kinds)
+ }
+ }
implicit class TermNameDecorator(val name: TermName) extends AnyVal {
import nme._
- def setterName: TermName =
- if (name.isFieldName) name.fieldToGetter.setterName
- else name ++ SETTER_SUFFIX
+ def setterName: TermName = name.exclude(FieldName) ++ str.SETTER_SUFFIX
def getterName: TermName =
- if (name.isFieldName) fieldToGetter
- else setterToGetter
+ name.exclude(FieldName).mapLast(n =>
+ if (n.endsWith(str.SETTER_SUFFIX)) n.take(n.length - str.SETTER_SUFFIX.length).asSimpleName
+ else n)
def fieldName: TermName =
if (name.isSetterName) {
- if (name.isTraitSetterName) {
- // has form <$-separated-trait-name>$_setter_$ `name`_$eq
- val start = name.indexOfSlice(TRAIT_SETTER_SEPARATOR) + TRAIT_SETTER_SEPARATOR.length
- val end = name.indexOfSlice(SETTER_SUFFIX)
- name.slice(start, end) ++ LOCAL_SUFFIX
- } else getterName.fieldName
+ if (name.is(TraitSetterName)) {
+ val TraitSetterName(_, original) = name
+ original.fieldName
+ }
+ else getterName.fieldName
}
- else name ++ LOCAL_SUFFIX
-
- private def setterToGetter: TermName = {
- assert(name.endsWith(SETTER_SUFFIX), name + " is referenced as a setter but has wrong name format")
- name.take(name.length - SETTER_SUFFIX.length).asTermName
- }
-
- def fieldToGetter: TermName = {
- assert(name.isFieldName)
- name.take(name.length - LOCAL_SUFFIX.length).asTermName
- }
-
- /** Nominally, name$default$N, encoded for <init>
- * @param Post the parameters position.
- * @note Default getter name suffixes start at 1, so `pos` has to be adjusted by +1
- */
- def defaultGetterName(pos: Int): TermName = {
- val prefix = if (name.isConstructorName) DEFAULT_GETTER_INIT else name
- prefix ++ DEFAULT_GETTER ++ (pos + 1).toString
- }
-
- /** Nominally, name from name$default$N, CONSTRUCTOR for <init> */
- def defaultGetterToMethod: TermName = {
- val p = name.indexOfSlice(DEFAULT_GETTER)
- if (p >= 0) {
- val q = name.take(p).asTermName
- // i.e., if (q.decoded == CONSTRUCTOR.toString) CONSTRUCTOR else q
- if (q == DEFAULT_GETTER_INIT) CONSTRUCTOR else q
- } else name
- }
-
- /** If this is a default getter, its index (starting from 0), else -1 */
- def defaultGetterIndex: Int = {
- var i = name.length
- while (i > 0 && name(i - 1).isDigit) i -= 1
- if (i > 0 && i < name.length && name.take(i).endsWith(DEFAULT_GETTER))
- name.drop(i).toString.toInt - 1
- else
- -1
- }
+ else FieldName(name)
def stripScala2LocalSuffix: TermName =
- if (name.isScala2LocalSuffix) name.init.asTermName else name
-
- /** The name of an accessor for protected symbols. */
- def protectedAccessorName: TermName =
- PROTECTED_PREFIX ++ name.unexpandedName
-
- /** The name of a setter for protected symbols. Used for inherited Java fields. */
- def protectedSetterName: TermName =
- PROTECTED_SET_PREFIX ++ name.unexpandedName
-
- def moduleVarName: TermName =
- name ++ MODULE_VAR_SUFFIX
+ if (name.isScala2LocalSuffix) name.asSimpleName.dropRight(1) else name
/** The name unary_x for a prefix operator x */
def toUnaryName: TermName = name match {
@@ -441,65 +282,5 @@ object NameOps {
case raw.BANG => UNARY_!
case _ => name
}
-
- /** The name of a method which stands in for a primitive operation
- * during structural type dispatch.
- */
- def primitiveInfixMethodName: TermName = name match {
- case OR => takeOr
- case XOR => takeXor
- case AND => takeAnd
- case EQ => testEqual
- case NE => testNotEqual
- case ADD => add
- case SUB => subtract
- case MUL => multiply
- case DIV => divide
- case MOD => takeModulo
- case LSL => shiftSignedLeft
- case LSR => shiftLogicalRight
- case ASR => shiftSignedRight
- case LT => testLessThan
- case LE => testLessOrEqualThan
- case GE => testGreaterOrEqualThan
- case GT => testGreaterThan
- case ZOR => takeConditionalOr
- case ZAND => takeConditionalAnd
- case _ => NO_NAME
- }
-
- /** Postfix/prefix, really.
- */
- def primitivePostfixMethodName: TermName = name match {
- case UNARY_! => takeNot
- case UNARY_+ => positive
- case UNARY_- => negate
- case UNARY_~ => complement
- case `toByte` => toByte
- case `toShort` => toShort
- case `toChar` => toCharacter
- case `toInt` => toInteger
- case `toLong` => toLong
- case `toFloat` => toFloat
- case `toDouble` => toDouble
- case _ => NO_NAME
- }
-
- def primitiveMethodName: TermName =
- primitiveInfixMethodName match {
- case NO_NAME => primitivePostfixMethodName
- case name => name
- }
-
- def lazyLocalName = name ++ nme.LAZY_LOCAL
- def nonLazyName = {
- assert(name.isLazyLocal)
- name.dropRight(nme.LAZY_LOCAL.length)
- }
-
- def inlineAccessorName = nme.INLINE_ACCESSOR_PREFIX ++ name ++ "$"
}
-
- private final val FalseSuper = "$$super".toTermName
- private val FalseSuperLength = FalseSuper.length
}