All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dotty.tools.dotc.core.NameKinds.scala Maven / Gradle / Ivy

The newest version!
package dotty.tools
package dotc
package core

import Names._
import NameOps._
import StdNames._
import NameTags._
import Contexts.Context
import collection.mutable

import scala.annotation.internal.sharable

/** Defines possible kinds of NameInfo of a derived name */
object NameKinds {

  // These are sharable since all NameKinds are created eagerly at the start of the program
  // before any concurrent threads are forked. for this to work, NameKinds should never
  // be created lazily or in modules that start running after compilers are forked.
  @sharable private val simpleNameKinds = new mutable.HashMap[Int, ClassifiedNameKind]
  @sharable private val qualifiedNameKinds = new mutable.HashMap[Int, QualifiedNameKind]
  @sharable private val numberedNameKinds = new mutable.HashMap[Int, NumberedNameKind]
  @sharable private val uniqueNameKinds = new mutable.HashMap[String, UniqueNameKind]

  /** A class for the info stored in a derived name */
  abstract class NameInfo {
    def kind: NameKind
    def mkString(underlying: TermName): String
    def map(f: SimpleName => SimpleName): NameInfo = this
  }

  /** An abstract base class of classes that define the kind of a derived name info */
  abstract class NameKind(val tag: Int) { self =>

    /** The info class defined by this kind */
    type ThisInfo <: Info

    /** A simple info type; some subclasses of Kind define more refined versions */
    class Info extends NameInfo { this: ThisInfo =>
      def kind: NameKind = self
      def mkString(underlying: TermName): String = self.mkString(underlying, this)
      override def toString: String = infoString
    }

    /** Does this kind define logically a new name (respectively qualified name)?
     *  Tested by the `replace` and `collect` combinators of class `Name`.
     */
    def definesNewName: Boolean = false
    def definesQualifiedName: Boolean = false

    /** Unmangle simple name `name` into a name of this kind, or return
     *  original name if this is not possible.
     */
    def unmangle(name: SimpleName): TermName = name

    /** Turn a name of this kind consisting of an `underlying` prefix
     *  and the given `info` into a string. Used to turn structured into
     *  simple name.
     */
    def mkString(underlying: TermName, info: ThisInfo): String

    /** A string used for displaying the structure of a name */
    def infoString: String
  }

  object SimpleNameKind extends NameKind(UTF8) { self =>
    type ThisInfo = Info
    val info: Info = new Info
    def mkString(underlying: TermName, info: ThisInfo): Nothing = unsupported("mkString")
    def infoString: Nothing = unsupported("infoString")
  }

  /** The kind of names that add a simple classification to an underlying name.
   */
  abstract class ClassifiedNameKind(tag: Int, val infoString: String) extends NameKind(tag) {
    type ThisInfo = Info
    val info: Info = new Info

    /** Build a new name of this kind from an underlying name */
    def apply(underlying: TermName): TermName = underlying.derived(info)

    /** Extractor operation for names of this kind */
    def unapply(name: DerivedName): Option[TermName] =  name match {
      case DerivedName(underlying, `info`) => Some(underlying)
      case _ => None
    }

    simpleNameKinds(tag) = this
  }

  /** The kind of names that get formed by adding a prefix to an underlying name */
  class PrefixNameKind(tag: Int, prefix: String, optInfoString: String = "")
  extends ClassifiedNameKind(tag, if (optInfoString.isEmpty) s"Prefix $prefix" else optInfoString) {
    def mkString(underlying: TermName, info: ThisInfo): String =
      underlying.qualToString(_.toString, n => prefix + n.toString)
    override def unmangle(name: SimpleName): TermName =
      if (name.startsWith(prefix)) apply(name.drop(prefix.length).asSimpleName)
      else name
  }

  /** The kind of names that get formed by appending a suffix to an underlying name */
  class SuffixNameKind(tag: Int, suffix: String, optInfoString: String = "")
  extends ClassifiedNameKind(tag, if (optInfoString.isEmpty) s"Suffix $suffix" else optInfoString) {
    def mkString(underlying: TermName, info: ThisInfo): String =
      underlying.qualToString(_.toString, n => n.toString + suffix)
    override def unmangle(name: SimpleName): TermName =
      if (name.endsWith(suffix)) apply(name.take(name.length - suffix.length).asSimpleName)
      else name
  }

  /** A base trait for infos that define an additional selector name */
  trait QualifiedInfo extends NameInfo {
    val name: SimpleName
  }

  /** The kind of qualified names, consisting of an underlying name as a prefix,
   *  followed by a separator, followed by a simple selector name.
   *
   *  A qualified names always constitutes a new name, different from its underlying name.
   */
  class QualifiedNameKind(tag: Int, val separator: String)
  extends NameKind(tag) {
    type ThisInfo = QualInfo
    case class QualInfo(name: SimpleName) extends Info with QualifiedInfo {
      override def map(f: SimpleName => SimpleName): NameInfo = new QualInfo(f(name))
      override def toString: String = s"$infoString $name"
    }

    def apply(qual: TermName, name: SimpleName): TermName =
      qual.derived(new QualInfo(name))

    /** Overloaded version used only for ExpandedName and TraitSetterName.
     *  Needed because the suffix of an expanded name may itself be expanded.
     *  For example, look at javap of scala.App.initCode
     */
    def apply(qual: TermName, name: TermName): TermName = name replace {
      case name: SimpleName => apply(qual, name)
      case AnyQualifiedName(_, _) => apply(qual, name.toSimpleName)
    }

    def unapply(name: DerivedName): Option[(TermName, SimpleName)] = name match {
      case DerivedName(qual, info: this.QualInfo) => Some((qual, info.name))
      case _ => None
    }

    override def definesNewName: Boolean = true
    override def definesQualifiedName: Boolean = true

    def mkString(underlying: TermName, info: ThisInfo): String =
      s"$underlying$separator${info.name}"

    def infoString: String = s"Qualified $separator"

    qualifiedNameKinds(tag) = this
  }

  /** An extractor for qualified names of an arbitrary kind */
  object AnyQualifiedName {
    def unapply(name: DerivedName): Option[(TermName, SimpleName)] = name match {
      case DerivedName(qual, info: QualifiedInfo) =>
        Some((name.underlying, info.name))
      case _ => None
    }
  }

  /** A base trait for infos that contain a number */
  trait NumberedInfo extends NameInfo {
    def num: Int
  }

  /** The kind of numbered names consisting of an underlying name and a number */
  abstract class NumberedNameKind(tag: Int, val infoString: String) extends NameKind(tag) { self =>
    type ThisInfo = NumberedInfo
    case class NumberedInfo(val num: Int) extends Info with NameKinds.NumberedInfo {
      override def toString: String = s"$infoString $num"
    }
    def apply(qual: TermName, num: Int): TermName =
      qual.derived(new NumberedInfo(num))
    def unapply(name: DerivedName): Option[(TermName, Int)] = name match {
      case DerivedName(underlying, info: this.NumberedInfo) => Some((underlying, info.num))
      case _ => None
    }
    protected def skipSeparatorAndNum(name: SimpleName, separator: String): Int = {
      var i = name.length
      while (i > 0 && name(i - 1).isDigit) i -= 1
      if (i > separator.length && i < name.length &&
          name.slice(i - separator.length, i).toString == separator) i
      else -1
    }

    numberedNameKinds(tag) = this
  }

  /** An extractor for numbered names of arbitrary kind */
  object AnyNumberedName {
    def unapply(name: DerivedName): Option[(TermName, Int)] = name match {
      case DerivedName(qual, info: NumberedInfo) => Some((qual, info.num))
      case _ => None
    }
  }

  /** The kind of unique names that consist of an underlying name (can be empty),
   *  a separator indicating the class of unique name, and a unique number.
   *
   *  A unique names always constitutes a new name, different from its underlying name.
   */
  case class UniqueNameKind(val separator: String)
  extends NumberedNameKind(UNIQUE, s"Unique $separator") {
    override def definesNewName: Boolean = true

    def mkString(underlying: TermName, info: ThisInfo): String = {
      val safePrefix = str.sanitize(underlying.toString) + separator
      safePrefix + info.num
    }

    /** Generate fresh unique term name of this kind with given prefix name */
    def fresh(prefix: TermName = EmptyTermName)(implicit ctx: Context): TermName =
      ctx.freshNames.newName(prefix, this)

    /** Generate fresh unique type name of this kind with given prefix name */
    def fresh(prefix: TypeName)(implicit ctx: Context): TypeName =
      fresh(prefix.toTermName).toTypeName

    uniqueNameKinds(separator) = this
  }

  /** An extractor for unique names of arbitrary kind */
  object AnyUniqueName {
    def unapply(name: DerivedName): Option[(TermName, String, Int)] = name match {
      case DerivedName(qual, info: NumberedInfo) =>
        info.kind match {
          case unique: UniqueNameKind => Some((qual, unique.separator, info.num))
          case _ => None
        }
      case _ => None
    }
  }

  /** Names of the form `prefix . name` */
  val QualifiedName: QualifiedNameKind = new QualifiedNameKind(QUALIFIED, ".")

  /** Names of the form `prefix $ name` that are constructed as a result of flattening */
  val FlatName: QualifiedNameKind = new QualifiedNameKind(FLATTENED, "$")

  /** Names of the form `prefix $ name` that are prefixes of expanded names */
  val ExpandPrefixName: QualifiedNameKind = new QualifiedNameKind(EXPANDPREFIX, "$")

  /** Expanded names of the form `prefix $$ name`. */
  val ExpandedName: QualifiedNameKind = new QualifiedNameKind(EXPANDED, str.EXPAND_SEPARATOR) {
    private val FalseSuper = termName("$$super")
    private val FalseSuperLength = FalseSuper.length

    override def unmangle(name: SimpleName): TermName = {
      var i = name.lastIndexOfSlice(str.EXPAND_SEPARATOR)
      if (i < 0) name
      else {
        // Hack to make super accessors from traits work. They would otherwise fail because of #765
        // The problem is that in `x$$super$$plus` the expansion prefix needs to be `x`
        // instead of `x$$super`.
        if (i > FalseSuperLength && name.slice(i - FalseSuperLength, i) == FalseSuper)
          i -= FalseSuper.length

        apply(name.take(i).asTermName, name.drop(i + str.EXPAND_SEPARATOR.length).asSimpleName)
      }
    }
  }

  /** Expanded names of the form `prefix $_setter_$ name`. These only occur in Scala2. */
  val TraitSetterName: QualifiedNameKind = new QualifiedNameKind(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR)

  /** Unique names of the form `prefix $ n` or `$ n $` */
  val UniqueName: UniqueNameKind = new UniqueNameKind("$") {
    override def mkString(underlying: TermName, info: ThisInfo) =
      if (underlying.isEmpty) "$" + info.num + "$" else super.mkString(underlying, info)
  }

  /** Other unique names */
  val TempResultName: UniqueNameKind         = new UniqueNameKind("ev$")
  val EvidenceParamName: UniqueNameKind      = new UniqueNameKind("evidence$")
  val DepParamName: UniqueNameKind           = new UniqueNameKind("(param)")
  val LazyImplicitName: UniqueNameKind       = new UniqueNameKind("$_lazy_implicit_$")
  val LazyLocalName: UniqueNameKind          = new UniqueNameKind("$lzy")
  val LazyLocalInitName: UniqueNameKind      = new UniqueNameKind("$lzyINIT")
  val LazyFieldOffsetName: UniqueNameKind    = new UniqueNameKind("$OFFSET")
  val LazyBitMapName: UniqueNameKind         = new UniqueNameKind(nme.BITMAP_PREFIX.toString)
  val NonLocalReturnKeyName: UniqueNameKind  = new UniqueNameKind("nonLocalReturnKey")
  val WildcardParamName: UniqueNameKind      = new UniqueNameKind("_$")
  val TailLabelName: UniqueNameKind          = new UniqueNameKind("tailLabel")
  val TailLocalName: UniqueNameKind          = new UniqueNameKind("$tailLocal")
  val TailTempName: UniqueNameKind           = new UniqueNameKind("$tmp")
  val ExceptionBinderName: UniqueNameKind    = new UniqueNameKind("ex")
  val SkolemName: UniqueNameKind             = new UniqueNameKind("?")
  val LiftedTreeName: UniqueNameKind         = new UniqueNameKind("liftedTree")
  val SuperArgName: UniqueNameKind           = new UniqueNameKind("$superArg$")
  val DocArtifactName: UniqueNameKind        = new UniqueNameKind("$doc")
  val UniqueInlineName: UniqueNameKind       = new UniqueNameKind("$i")
  val InlineScrutineeName: UniqueNameKind    = new UniqueNameKind("$scrutinee")
  val InlineBinderName: UniqueNameKind       = new UniqueNameKind("$elem")

  /** A kind of unique extension methods; Unlike other unique names, these can be
   *  unmangled.
   */
  val UniqueExtMethName: UniqueNameKind = new UniqueNameKind("$extension") {
    override def unmangle(name: SimpleName): TermName = {
      val i = skipSeparatorAndNum(name, separator)
      if (i > 0) {
        val index = name.drop(i).toString.toInt
        val original = name.take(i - separator.length).asTermName
        apply(original, index)
      }
      else name
    }
  }

  /** Kinds of unique names generated by the pattern matcher */
  val PatMatStdBinderName: UniqueNameKind    = new UniqueNameKind("x")
  val PatMatAltsName: UniqueNameKind         = new UniqueNameKind("matchAlts")
  val PatMatResultName: UniqueNameKind       = new UniqueNameKind("matchResult")

  val LocalOptInlineLocalObj: UniqueNameKind = new UniqueNameKind("ilo")

  /** The kind of names of default argument getters */
  val DefaultGetterName: NumberedNameKind = new NumberedNameKind(DEFAULTGETTER, "DefaultGetter") {
    def mkString(underlying: TermName, info: ThisInfo) = {
      val prefix = if (underlying.isConstructorName) nme.DEFAULT_GETTER_INIT else underlying
      prefix.toString + str.DEFAULT_GETTER + (info.num + 1)
    }
    // TODO: Reduce code duplication with UniqueExtMethName
    override def unmangle(name: SimpleName): TermName = {
      val i = skipSeparatorAndNum(name, str.DEFAULT_GETTER)
      if (i > 0) {
        val index = name.drop(i).toString.toInt - 1
        var original = name.take(i - str.DEFAULT_GETTER.length).asTermName
        if (original == nme.DEFAULT_GETTER_INIT) original = nme.CONSTRUCTOR
        apply(original, index)
      }
      else name
    }
  }

  /** The kind of names that also encode a variance: 0 for contravariance, 1 for covariance. */
  val VariantName: NumberedNameKind = new NumberedNameKind(VARIANT, "Variant") {
    def mkString(underlying: TermName, info: ThisInfo) = "-+"(info.num).toString + underlying
  }

  /** Names of the form N_. Emitted by inliner, replaced by outer path
   *  in ExplicitOuter.
   */
  val OuterSelectName: NumberedNameKind = new NumberedNameKind(OUTERSELECT, "OuterSelect") {
    def mkString(underlying: TermName, info: ThisInfo) = {
      assert(underlying.isEmpty)
      info.num + "_"
    }
  }

  val SuperAccessorName: PrefixNameKind = new PrefixNameKind(SUPERACCESSOR, "super$")
  val InitializerName: PrefixNameKind = new PrefixNameKind(INITIALIZER, "initial$")
  val ProtectedAccessorName: PrefixNameKind = new PrefixNameKind(PROTECTEDACCESSOR, "protected$")
  val InlineAccessorName: PrefixNameKind = new PrefixNameKind(INLINEACCESSOR, "inline$")

  val AvoidClashName: SuffixNameKind = new SuffixNameKind(AVOIDCLASH, "$_avoid_name_clash_$")
  val CacheName = new SuffixNameKind(CACHE, "$_cache")
  val DirectMethodName: SuffixNameKind = new SuffixNameKind(DIRECT, "$direct") { override def definesNewName = true }
  val FieldName: SuffixNameKind = new SuffixNameKind(FIELD, "$$local") {
      override def mkString(underlying: TermName, info: ThisInfo) = underlying.toString
  }
  val ExtMethName: SuffixNameKind = new SuffixNameKind(EXTMETH, "$extension")
  val ModuleClassName: SuffixNameKind = new SuffixNameKind(OBJECTCLASS, "$", optInfoString = "ModuleClass")
  val ImplMethName: SuffixNameKind = new SuffixNameKind(IMPLMETH, "$")
  val AdaptedClosureName: SuffixNameKind = new SuffixNameKind(ADAPTEDCLOSURE, "$adapted") { override def definesNewName = true }

  /** A name together with a signature. Used in Tasty trees. */
  object SignedName extends NameKind(SIGNED) {

    case class SignedInfo(sig: Signature) extends Info {
      assert(sig ne Signature.NotAMethod)
      override def toString: String = s"$infoString $sig"
    }
    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))
      case _ => None
    }

    def mkString(underlying: TermName, info: ThisInfo): String = s"$underlying[with sig ${info.sig}]"
    def infoString: String = "Signed"
  }

  /** Possible name kinds of a method that comes from Scala2 pickling info.
   *  and that need to be unmangled. Note: Scala2 protected accessors and setters
   *  can be left mangled, so they are not included in thus list.
   */
  val Scala2MethodNameKinds: List[NameKind] =
    List(DefaultGetterName, ExtMethName, UniqueExtMethName)

  def simpleNameKindOfTag      : collection.Map[Int, ClassifiedNameKind] = simpleNameKinds
  def qualifiedNameKindOfTag   : collection.Map[Int, QualifiedNameKind]  = qualifiedNameKinds
  def numberedNameKindOfTag    : collection.Map[Int, NumberedNameKind]   = numberedNameKinds
  def uniqueNameKindOfSeparator: collection.Map[String, UniqueNameKind]  = uniqueNameKinds
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy