From 21ded6ee9f727bd5a1c3975809c06868fe1b5536 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 30 Mar 2017 13:44:02 +0200 Subject: Revise qualified names 1. Fix problem in fullNameSeparated 2. Revise expandedName operations --- compiler/src/dotty/tools/dotc/core/NameKinds.scala | 28 ++++++++---- compiler/src/dotty/tools/dotc/core/NameOps.scala | 50 ++++++-------------- compiler/src/dotty/tools/dotc/core/StdNames.scala | 1 - .../src/dotty/tools/dotc/core/SymDenotations.scala | 53 +++++++++------------- .../dotty/tools/dotc/core/tasty/TastyFormat.scala | 3 +- .../tools/dotc/core/tasty/TastyUnpickler.scala | 8 +--- 6 files changed, 60 insertions(+), 83 deletions(-) (limited to 'compiler/src/dotty/tools/dotc/core') diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index eea5aefe3..381bb3fc0 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -14,8 +14,8 @@ import collection.mutable object NameKinds { @sharable private val simpleNameKinds = new mutable.HashMap[Int, ClassifiedNameKind] + @sharable private val qualifiedNameKinds = new mutable.HashMap[Int, QualifiedNameKind] @sharable private val uniqueNameKinds = new mutable.HashMap[String, UniqueNameKind] - @sharable private val qualifiedNameKinds = new mutable.HashMap[String, QualifiedNameKind] abstract class NameInfo extends DotClass { def kind: NameKind @@ -83,8 +83,18 @@ object NameKinds { override def map(f: SimpleTermName => SimpleTermName): NameInfo = new QualInfo(f(name)) override def toString = s"$infoString $name" } - def apply(qual: TermName, name: SimpleTermName) = + def apply(qual: TermName, name: SimpleTermName): 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 rewrite { + case name: SimpleTermName => apply(qual, name) + case AnyQualifiedName(_, _) => apply(qual, name.toSimpleName) + } + def unapply(name: DerivedTermName): Option[(TermName, SimpleTermName)] = name match { case DerivedTermName(qual, info: this.QualInfo) => Some((qual, info.name)) case _ => None @@ -96,7 +106,7 @@ object NameKinds { s"$underlying$separator${info.name}" def infoString = s"Qualified $separator" - qualifiedNameKinds(separator) = this + qualifiedNameKinds(tag) = this } object AnyQualifiedName { @@ -150,8 +160,8 @@ object NameKinds { } val QualifiedName = new QualifiedNameKind(QUALIFIED, ".") - val FlattenedName = new QualifiedNameKind(FLATTENED, "$") - val TraitSetterName = new QualifiedNameKind(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR) + val FlatName = new QualifiedNameKind(FLATTENED, "$") + val ExpandPrefixName = new QualifiedNameKind(EXPANDPREFIX, "$") val ExpandedName = new QualifiedNameKind(EXPANDED, str.EXPAND_SEPARATOR) { private val FalseSuper = "$$super".toTermName @@ -172,6 +182,8 @@ object NameKinds { } } + val TraitSetterName = new QualifiedNameKind(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR) + val UniqueName = new UniqueNameKind("$") { override def mkString(underlying: TermName, info: ThisInfo) = if (underlying.isEmpty) "$" + info.num + "$" else super.mkString(underlying, info) @@ -260,7 +272,7 @@ object NameKinds { val Scala2MethodNameKinds: List[NameKind] = List(DefaultGetterName, ProtectedAccessorName, ProtectedSetterName) - def simpleNameKindOfTag : collection.Map[Int, ClassifiedNameKind] = simpleNameKinds - def qualifiedNameKindOfSeparator: collection.Map[String, QualifiedNameKind] = qualifiedNameKinds - def uniqueNameKindOfSeparator : collection.Map[String, UniqueNameKind] = uniqueNameKinds + def simpleNameKindOfTag : collection.Map[Int, ClassifiedNameKind] = simpleNameKinds + def qualifiedNameKindOfTag : collection.Map[Int, QualifiedNameKind] = qualifiedNameKinds + def uniqueNameKindOfSeparator: collection.Map[String, UniqueNameKind] = uniqueNameKinds } \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 8d5344d8a..01ce4807c 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -59,10 +59,8 @@ object NameOps { def isStaticConstructorName = name == STATIC_CONSTRUCTOR 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 isReplWrapperName = name.toSimpleName containsSlice INTERPRETER_IMPORT_WRAPPER def isSetterName = name endsWith SETTER_SUFFIX - def isSingletonName = name endsWith SINGLETON_SUFFIX def isImportName = name startsWith IMPORT def isFieldName = name endsWith LOCAL_SUFFIX def isScala2LocalSuffix = name.endsWith(" ") @@ -110,8 +108,16 @@ object NameOps { /** Convert this module class name to corresponding source module name */ def sourceModuleName: TermName = name.toTermName.exclude(ModuleClassName) - /** If name ends in module class suffix, drop it */ - def stripModuleClassSuffix: Name = name.exclude(ModuleClassName) + /** 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: Name = name match { + case name: SimpleTermName if name.endsWith("$") => + name.unmangleClassName.exclude(ModuleClassName) + case _ => + name.exclude(ModuleClassName) + } /** If flags is a ModuleClass but not a Package, add module class suffix */ def adjustIfModuleClass(flags: Flags.FlagSet): N = likeTyped { @@ -122,43 +128,17 @@ object NameOps { /** The superaccessor for method with given name */ def superName: TermName = SuperAccessorName(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.name.is(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 = - likeTyped { - def qualify(name: SimpleTermName) = - qualifiedNameKindOfSeparator(separator.toString)(prefix.toTermName, name) - name rewrite { - case name: SimpleTermName => - qualify(name) - case AnyQualifiedName(_, _) => - // Note: an expanded name may itself be expanded. For example, look at javap of scala.App.initCode - qualify(name.toSimpleName) - } - } - - def expandedName(prefix: Name): N = expandedName(prefix, nme.EXPAND_SEPARATOR) + def expandedName(base: Symbol, kind: QualifiedNameKind = ExpandedName)(implicit ctx: Context): N = { + val prefix = + if (base.name.is(ExpandedName)) base.name else base.fullNameSeparated(ExpandPrefixName) + likeTyped { kind(prefix.toTermName, name.toTermName) } + } /** Revert the expanded name. */ def unexpandedName: N = likeTyped { name.rewrite { case ExpandedName(_, unexp) => unexp } } - def expandedPrefix: N = likeTyped { name.exclude(ExpandedName) } - - def expandedPrefixOfMangled: N = { - val idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) - assert(idx >= 0) - likeTyped(name.take(idx)) - } - def implClassName: N = likeTyped(name ++ tpnme.IMPL_CLASS_SUFFIX) def errorName: N = likeTyped(name ++ nme.ERROR) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 7dd569d04..51821c51b 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -124,7 +124,6 @@ object StdNames { val PACKAGE: N = "package" val PACKAGE_CLS: N = "package$" val ROOT: N = "" - val SINGLETON_SUFFIX: N = ".type" val SPECIALIZED_SUFFIX: N = "$sp" val SUPER_PREFIX: N = "super$" val WHILE_PREFIX: N = "while$" diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 3d0b306c0..f4682bf7d 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -383,20 +383,18 @@ object SymDenotations { /** The encoded full path name of this denotation, where outer names and inner names * are separated by `separator` strings. * Never translates expansions of operators back to operator symbol. - * Drops package objects. Represents terms in the owner chain by a simple `~`. + * Drops package objects. Represents each term in the owner chain by a simple `~`. * (Note: scalac uses nothing to represent terms, which can cause name clashes * between same-named definitions in different enclosing methods. Before this commit * we used `$' but this can cause ambiguities with the class separator '$'). * A separator "" means "flat name"; the real separator in this case is "$" and * enclosing packages do not form part of the name. */ - def fullNameSeparated(separator: String)(implicit ctx: Context): Name = { - val stopAtPackage = separator.isEmpty - val sep = if (stopAtPackage) "$" else separator + def fullNameSeparated(kind: QualifiedNameKind)(implicit ctx: Context): Name = if (symbol == NoSymbol || owner == NoSymbol || owner.isEffectiveRoot || - stopAtPackage && owner.is(PackageClass)) name + kind == FlatName && owner.is(PackageClass)) name else { var filler = "" var encl = owner @@ -404,34 +402,25 @@ object SymDenotations { encl = encl.owner filler += "~" } - var prefix = encl.fullNameSeparated(separator) - val fn = - if (qualifiedNameKindOfSeparator.contains(sep)) { - if (sep == "$") - // duplicate scalac's behavior: don't write a double '$$' for module class members. - prefix = prefix.exclude(ModuleClassName) - name rewrite { - case n: SimpleTermName => - val n1 = if (filler.isEmpty) n else termName(filler ++ n) - qualifiedNameKindOfSeparator(sep)(prefix.toTermName, n1) - } - } - else { - val sep1 = - if (owner.is(ModuleClass, butNot = Package) && sep == "$") "" - else sep - // duplicate scalac's behavior: don't write a double '$$' for module class members. - prefix ++ sep1 ++ name - } + var prefix = encl.fullNameSeparated(kind) + if (kind.separator == "$") + // duplicate scalac's behavior: don't write a double '$$' for module class members. + prefix = prefix.exclude(ModuleClassName) + def qualify(n: SimpleTermName) = + kind(prefix.toTermName, if (filler.isEmpty) n else termName(filler ++ n)) + val fn = name rewrite { + case name: SimpleTermName => qualify(name) + case name @ AnyQualifiedName(_, _) => qualify(name.toSimpleName) + } if (isType) fn.toTypeName else fn.toTermName } - } + /** The encoded flat name of this denotation, where joined names are separated by `separator` characters. */ - def flatName(implicit ctx: Context): Name = fullNameSeparated("") + def flatName(implicit ctx: Context): Name = fullNameSeparated(FlatName) /** `fullName` where `.' is the separator character */ - def fullName(implicit ctx: Context): Name = fullNameSeparated(".") + def fullName(implicit ctx: Context): Name = fullNameSeparated(QualifiedName) // ----- Tests ------------------------------------------------- @@ -1763,13 +1752,13 @@ object SymDenotations { } } - private[this] var fullNameCache: SimpleMap[String, Name] = SimpleMap.Empty - override final def fullNameSeparated(separator: String)(implicit ctx: Context): Name = { - val cached = fullNameCache(separator) + private[this] var fullNameCache: SimpleMap[QualifiedNameKind, Name] = SimpleMap.Empty + override final def fullNameSeparated(kind: QualifiedNameKind)(implicit ctx: Context): Name = { + val cached = fullNameCache(kind) if (cached != null) cached else { - val fn = super.fullNameSeparated(separator) - fullNameCache = fullNameCache.updated(separator, fn) + val fn = super.fullNameSeparated(kind) + fullNameCache = fullNameCache.updated(kind, fn) fn } } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index f7e61c924..ec59e711a 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -223,8 +223,9 @@ object TastyFormat { final val UTF8 = 1 final val QUALIFIED = 2 final val FLATTENED = 3 + final val EXPANDPREFIX = 5 final val EXPANDED = 4 - final val TRAITSETTER = 5 + final val TRAITSETTER = 6 final val UNIQUE = 10 final val DEFAULTGETTER = 11 final val VARIANT = 12 diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala index a14691ed5..835222727 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala @@ -49,12 +49,8 @@ class TastyUnpickler(reader: TastyReader) { case UTF8 => goto(end) termName(bytes, start.index, length) - case QUALIFIED => - QualifiedName(readName(), readName().asSimpleName) - case FLATTENED => - FlattenedName(readName(), readName().asSimpleName) - case EXPANDED => - ExpandedName(readName(), readName().asSimpleName) + case QUALIFIED | FLATTENED | EXPANDED | EXPANDPREFIX => + qualifiedNameKindOfTag(tag)(readName(), readName().asSimpleName) case UNIQUE => val separator = readName().toString val num = readNat() -- cgit v1.2.3