Skip to content

Commit ac1415f

Browse files
committed
Optimized scheme for mangling strings
There's no need to add mangled qualified names in the name table. Instead we compute the mangled string directly and more efficiently. Also, bug fixes to make semantic names work: - When creating a fully qualified name, we need to convert the last part to a simple name. If the last part is not already a simple name or typename version of it, it should be mangled - Mangling needs to sanitize because a legal name such as <init> might illegal when it gets a suffix or prefix.
1 parent 06acdec commit ac1415f

File tree

3 files changed

+49
-17
lines changed

3 files changed

+49
-17
lines changed

compiler/src/dotty/tools/dotc/core/NameKinds.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ object NameKinds {
9191
class PrefixNameKind(tag: Int, prefix: String, optInfoString: String = "")
9292
extends ClassifiedNameKind(tag, if (optInfoString.isEmpty) s"Prefix $prefix" else optInfoString) {
9393
def mkString(underlying: TermName, info: ThisInfo) =
94-
underlying.mapLast(n => termName(prefix + n.toString)).toString
94+
underlying.mapLast(n => termName(prefix + str.sanitize(n.toString))).toString
9595
override def unmangle(name: SimpleName): TermName =
9696
if (name.startsWith(prefix)) apply(name.drop(prefix.length).asSimpleName)
9797
else name
@@ -100,7 +100,8 @@ object NameKinds {
100100
/** The kind of names that get formed by appending a suffix to an underlying name */
101101
class SuffixNameKind(tag: Int, suffix: String, optInfoString: String = "")
102102
extends ClassifiedNameKind(tag, if (optInfoString.isEmpty) s"Suffix $suffix" else optInfoString) {
103-
def mkString(underlying: TermName, info: ThisInfo) = underlying.toString ++ suffix
103+
def mkString(underlying: TermName, info: ThisInfo) =
104+
underlying.mapLast(n => termName(str.sanitize(n.toString) + suffix)).toString
104105
override def unmangle(name: SimpleName): TermName =
105106
if (name.endsWith(suffix)) apply(name.take(name.length - suffix.length).asSimpleName)
106107
else name

compiler/src/dotty/tools/dotc/core/Names.scala

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,20 +66,13 @@ object Names {
6666
/** This name converted to a simple term name */
6767
def toSimpleName: SimpleName
6868

69-
@sharable // because it's just a cache for performance
70-
private[this] var myMangled: Name = null
71-
72-
protected[Names] def mangle: ThisName
73-
7469
/** This name converted to a simple term name and in addition
7570
* with all symbolic operator characters expanded.
7671
*/
77-
final def mangled: ThisName = {
78-
if (myMangled == null) myMangled = mangle
79-
myMangled.asInstanceOf[ThisName]
80-
}
72+
def mangled: ThisName
8173

82-
def mangledString: String = mangled.toString
74+
/** Convert to string after mangling */
75+
def mangledString: String
8376

8477
/** Apply rewrite rule given by `f` to some part of this name, skipping and rewrapping
8578
* other decorators.
@@ -100,6 +93,11 @@ object Names {
10093
/** Apply `f` to all simple term names making up this name */
10194
def mapParts(f: SimpleName => SimpleName): ThisName
10295

96+
/** If this a qualified name, split it into underlyng, last part, and separator
97+
* Otherwise return an empty name, the name itself, and "")
98+
*/
99+
def split: (TermName, TermName, String)
100+
103101
/** A name in the same (term or type) namespace as this name and
104102
* with same characters as given `name`.
105103
*/
@@ -252,6 +250,31 @@ object Names {
252250
thisKind == kind ||
253251
!thisKind.definesNewName && thisKind.tag > kind.tag && underlying.is(kind)
254252
}
253+
254+
@sharable // because it's just a cache for performance
255+
private[Names] var myMangledString: String = null
256+
257+
@sharable // because it's just a cache for performance
258+
private[this] var myMangled: Name = null
259+
260+
protected[Names] def mangle: ThisName
261+
262+
final def mangled: ThisName = {
263+
if (myMangled == null) myMangled = mangle
264+
myMangled.asInstanceOf[ThisName]
265+
}
266+
267+
final def mangledString: String = {
268+
if (myMangledString == null) {
269+
val (prefix, suffix, separator) = split
270+
val mangledSuffix = suffix.mangled.toString
271+
myMangledString =
272+
if (prefix.isEmpty) mangledSuffix
273+
else str.sanitize(prefix.mangledString + separator + mangledSuffix)
274+
}
275+
myMangledString
276+
}
277+
255278
}
256279

257280
/** A simple name is essentiall an interned string */
@@ -317,6 +340,7 @@ object Names {
317340
override def collect[T](f: PartialFunction[Name, T]): Option[T] = f.lift(this)
318341
override def mapLast(f: SimpleName => SimpleName) = f(this)
319342
override def mapParts(f: SimpleName => SimpleName) = f(this)
343+
override def split = (EmptyTermName, this, "")
320344

321345
override def encode: SimpleName = {
322346
val dontEncode =
@@ -391,9 +415,6 @@ object Names {
391415
.contains(elem.getMethodName))
392416
}
393417

394-
def sliceToString(from: Int, end: Int) =
395-
if (end <= from) "" else new String(chrs, start + from, end - from)
396-
397418
def debugString: String = toString
398419
}
399420

@@ -409,12 +430,14 @@ object Names {
409430

410431
override def asSimpleName = toTermName.asSimpleName
411432
override def toSimpleName = toTermName.toSimpleName
412-
override final def mangle = toTermName.mangle.toTypeName
433+
override def mangled = toTermName.mangled.toTypeName
434+
override def mangledString = toTermName.mangledString
413435

414436
override def rewrite(f: PartialFunction[Name, Name]): ThisName = toTermName.rewrite(f).toTypeName
415437
override def collect[T](f: PartialFunction[Name, T]): Option[T] = toTermName.collect(f)
416438
override def mapLast(f: SimpleName => SimpleName) = toTermName.mapLast(f).toTypeName
417439
override def mapParts(f: SimpleName => SimpleName) = toTermName.mapParts(f).toTypeName
440+
override def split = toTermName.split
418441

419442
override def likeSpaced(name: Name): TypeName = name.toTypeName
420443

@@ -470,6 +493,14 @@ object Names {
470493
case _ => underlying.mapParts(f).derived(info)
471494
}
472495

496+
override def split = info match {
497+
case info: QualifiedInfo =>
498+
(underlying, info.name, info.kind.asInstanceOf[QualifiedNameKind].separator)
499+
case _ =>
500+
val (prefix, suffix, separator) = underlying.split
501+
(prefix, suffix.derived(info), separator)
502+
}
503+
473504
override def isEmpty = false
474505
override def encode: ThisName = underlying.encode.derived(info.map(_.encode))
475506
override def decode: ThisName = underlying.decode.derived(info.map(_.decode))

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ object SymDenotations {
399399
kind(prefix.toTermName, if (filler.isEmpty) n else termName(filler + n))
400400
val fn = name rewrite {
401401
case name: SimpleName => qualify(name)
402-
case name @ AnyQualifiedName(_, _) => qualify(name.toSimpleName)
402+
case name @ AnyQualifiedName(_, _) => qualify(name.mangled.toSimpleName)
403403
}
404404
if (isType) fn.toTypeName else fn.toTermName
405405
}

0 commit comments

Comments
 (0)