Skip to content

Commit c5eca49

Browse files
committed
Add default getter names
Plus various bug fixes and filling in missing functionality
1 parent e8a3d7d commit c5eca49

File tree

9 files changed

+169
-57
lines changed

9 files changed

+169
-57
lines changed

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dotty.tools.dotc
22
package core
33

44
import Names._
5+
import NameOps._
56
import StdNames._
67

78
/** Additional info associated with a name. At a minimum its kind and
@@ -20,6 +21,7 @@ object NameInfo {
2021
val TermNameKind = 0
2122
val QualifiedKind = 1
2223
val ModuleClassKind = 2
24+
val DefaultGetterKind = 3
2325

2426
val qualifier: Map[String, SimpleTermName => Qualified] =
2527
Map("." -> Select,
@@ -43,7 +45,7 @@ object NameInfo {
4345
def kind = QualifiedKind
4446
override def map(f: SimpleTermName => SimpleTermName): NameInfo = newLikeThis(f(name))
4547
def mkString(underlying: TermName) = s"$underlying$separator$name"
46-
override def toString = s"$getClass($name)"
48+
override def toString = s"${getClass.getSimpleName}($name)"
4749
}
4850

4951
case class Select(val name: SimpleTermName) extends Qualified {
@@ -66,6 +68,19 @@ object NameInfo {
6668
def newLikeThis(name: SimpleTermName) = TraitSetter(name)
6769
}
6870

71+
trait Numbered extends NameInfo {
72+
def num: Int
73+
override def toString = s"${getClass.getSimpleName}($num)"
74+
}
75+
76+
case class DefaultGetter(val num: Int) extends Numbered {
77+
def kind = DefaultGetterKind
78+
def mkString(underlying: TermName) = {
79+
val prefix = if (underlying.isConstructorName) nme.DEFAULT_GETTER_INIT else underlying
80+
prefix.toString + nme.DEFAULT_GETTER + (num + 1)
81+
}
82+
}
83+
6984
val ModuleClass = new NameInfo {
7085
def kind = ModuleClassKind
7186
def mkString(underlying: TermName) = underlying + "$"

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

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,10 @@ object NameOps {
102102
def isOpAssignmentName: Boolean = name match {
103103
case raw.NE | raw.LE | raw.GE | EMPTY =>
104104
false
105-
case _ =>
105+
case name: SimpleTermName =>
106106
name.length > 0 && name.last == '=' && name.head != '=' && isOperatorPart(name.head)
107+
case _ =>
108+
false
107109
}
108110

109111
/** If the name ends with $nn where nn are
@@ -164,7 +166,8 @@ object NameOps {
164166
def expandedName(prefix: Name, separator: Name = nme.EXPAND_SEPARATOR): N =
165167
likeTyped(
166168
if (Config.semanticNames)
167-
prefix.derived(NameInfo.qualifier(separator.toString)(name.asSimpleName))
169+
prefix.derived(NameInfo.qualifier(separator.toString)(name.toSimpleName))
170+
// note: expanded name may itself be expanded. For example, look at javap of scala.App.initCode
168171
else prefix ++ separator ++ name)
169172

170173
def expandedName(prefix: Name): N = expandedName(prefix, nme.EXPAND_SEPARATOR)
@@ -221,7 +224,7 @@ object NameOps {
221224

222225
def unmangleClassName: N =
223226
if (Config.semanticNames && name.isSimple && name.isTypeName)
224-
if (name.endsWith(MODULE_SUFFIX))
227+
if (name.endsWith(MODULE_SUFFIX) && !tpnme.falseModuleClassNames.contains(name.asTypeName))
225228
likeTyped(name.dropRight(MODULE_SUFFIX.length).moduleClassName)
226229
else name
227230
else name
@@ -378,44 +381,60 @@ object NameOps {
378381
if (name.isSetterName) {
379382
if (name.isTraitSetterName) {
380383
// has form <$-separated-trait-name>$_setter_$ `name`_$eq
381-
val start = name.indexOfSlice(TRAIT_SETTER_SEPARATOR) + TRAIT_SETTER_SEPARATOR.length
382-
val end = name.indexOfSlice(SETTER_SUFFIX)
383-
(name.slice(start, end) ++ LOCAL_SUFFIX).asTermName
384+
val start = name.lastPart.indexOfSlice(TRAIT_SETTER_SEPARATOR) + TRAIT_SETTER_SEPARATOR.length
385+
val end = name.lastPart.indexOfSlice(SETTER_SUFFIX)
386+
name.mapLast(n => (n.slice(start, end) ++ LOCAL_SUFFIX).asSimpleName)
384387
} else getterName.fieldName
385388
}
386-
else name ++ LOCAL_SUFFIX
389+
else name.mapLast(n => (n ++ LOCAL_SUFFIX).asSimpleName)
387390

388391
private def setterToGetter: TermName = {
389392
assert(name.endsWith(SETTER_SUFFIX), name + " is referenced as a setter but has wrong name format")
390-
name.take(name.length - SETTER_SUFFIX.length).asTermName
393+
name.mapLast(n => n.take(n.length - SETTER_SUFFIX.length).asSimpleName)
391394
}
392395

393396
def fieldToGetter: TermName = {
394397
assert(name.isFieldName)
395-
name.take(name.length - LOCAL_SUFFIX.length).asTermName
398+
name.mapLast(n => n.take(n.length - LOCAL_SUFFIX.length).asSimpleName)
396399
}
397400

398401
/** Nominally, name$default$N, encoded for <init>
399402
* @param Post the parameters position.
400403
* @note Default getter name suffixes start at 1, so `pos` has to be adjusted by +1
401404
*/
402-
def defaultGetterName(pos: Int): TermName = {
403-
val prefix = if (name.isConstructorName) DEFAULT_GETTER_INIT else name
404-
prefix ++ DEFAULT_GETTER ++ (pos + 1).toString
405-
}
405+
def defaultGetterName(pos: Int): TermName =
406+
if (Config.semanticNames) name.derived(NameInfo.DefaultGetter(pos))
407+
else {
408+
val prefix = if (name.isConstructorName) DEFAULT_GETTER_INIT else name
409+
prefix ++ DEFAULT_GETTER ++ (pos + 1).toString
410+
}
406411

407412
/** Nominally, name from name$default$N, CONSTRUCTOR for <init> */
408-
def defaultGetterToMethod: TermName = {
409-
val p = name.indexOfSlice(DEFAULT_GETTER)
410-
if (p >= 0) {
411-
val q = name.take(p).asTermName
412-
// i.e., if (q.decoded == CONSTRUCTOR.toString) CONSTRUCTOR else q
413-
if (q == DEFAULT_GETTER_INIT) CONSTRUCTOR else q
414-
} else name
413+
def defaultGetterToMethod: TermName =
414+
if (Config.semanticNames)
415+
name rewrite {
416+
case DerivedTermName(methName, NameInfo.DefaultGetter(_)) => methName
417+
}
418+
else mangledDefaultGetterToMethod
419+
420+
def mangledDefaultGetterToMethod: TermName = {
421+
val p = name.indexOfSlice(DEFAULT_GETTER)
422+
if (p >= 0) {
423+
val q = name.take(p).asTermName
424+
// i.e., if (q.decoded == CONSTRUCTOR.toString) CONSTRUCTOR else q
425+
if (q == DEFAULT_GETTER_INIT) CONSTRUCTOR else q
426+
} else name
415427
}
416428

417429
/** If this is a default getter, its index (starting from 0), else -1 */
418-
def defaultGetterIndex: Int = {
430+
def defaultGetterIndex: Int =
431+
if (Config.semanticNames)
432+
name collect {
433+
case DerivedTermName(methName, NameInfo.DefaultGetter(num)) => num
434+
} getOrElse -1
435+
else mangledDefaultGetterIndex
436+
437+
def mangledDefaultGetterIndex: Int = {
419438
var i = name.length
420439
while (i > 0 && name(i - 1).isDigit) i -= 1
421440
if (i > 0 && i < name.length && name.take(i).endsWith(DEFAULT_GETTER))
@@ -503,6 +522,14 @@ object NameOps {
503522
}
504523

505524
def inlineAccessorName = nme.INLINE_ACCESSOR_PREFIX ++ name ++ "$"
525+
526+
def unmangleMethodName: TermName =
527+
if (Config.semanticNames && name.isSimple) {
528+
val idx = name.mangledDefaultGetterIndex
529+
if (idx >= 0) name.mangledDefaultGetterToMethod.defaultGetterName(idx)
530+
else name
531+
}
532+
else name
506533
}
507534

508535
private final val FalseSuper = "$$super".toTermName

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

Lines changed: 84 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ object Names {
6666
def asSimpleName: SimpleTermName
6767
def toSimpleName: SimpleTermName
6868
def rewrite(f: PartialFunction[Name, Name]): ThisName
69+
def collect[T](f: PartialFunction[Name, T]): Option[T]
70+
def mapLast(f: SimpleTermName => SimpleTermName): ThisName
71+
def mapParts(f: SimpleTermName => SimpleTermName): ThisName
6972

7073
/** A name of the same kind as this name and with same characters as given `name` */
7174
def likeKinded(name: Name): ThisName
@@ -88,9 +91,8 @@ object Names {
8891

8992
/** A more efficient version of concatenation */
9093
def ++ (other: Name): ThisName = ++ (other.toString)
91-
def ++ (other: String): ThisName
92-
93-
def replace(from: Char, to: Char): ThisName = likeKinded(asSimpleName.replace(from, to))
94+
def ++ (other: String): ThisName = mapLast(n => termName(n.toString + other))
95+
def replace(from: Char, to: Char): ThisName = mapParts(_.replace(from, to))
9496

9597
def isEmpty: Boolean
9698

@@ -198,8 +200,6 @@ object Names {
198200

199201
def apply(n: Int) = chrs(start + n)
200202

201-
def ++ (other: String): SimpleTermName = termName(toString + other)
202-
203203
private def contains(ch: Char): Boolean = {
204204
var i = 0
205205
while (i < length && chrs(start + i) != ch) i += 1
@@ -220,19 +220,29 @@ object Names {
220220
i > str.length
221221
}
222222

223-
override def replace(from: Char, to: Char): ThisName = {
223+
override def replace(from: Char, to: Char): SimpleTermName = {
224224
val cs = new Array[Char](length)
225225
Array.copy(chrs, start, cs, 0, length)
226226
for (i <- 0 until length) {
227227
if (cs(i) == from) cs(i) = to
228228
}
229-
likeKinded(termName(cs, 0, length))
229+
termName(cs, 0, length)
230230
}
231231

232232
def isSimple = true
233233
def asSimpleName = this
234234
def toSimpleName = this
235-
def rewrite(f: PartialFunction[Name, Name]): ThisName = likeKinded(f(this))
235+
def rewrite(f: PartialFunction[Name, Name]): ThisName =
236+
if (f.isDefinedAt(this)) likeKinded(f(this)) else this
237+
def collect[T](f: PartialFunction[Name, T]): Option[T] = f.lift(this)
238+
def mapLast(f: SimpleTermName => SimpleTermName) = f(this)
239+
def mapParts(f: SimpleTermName => SimpleTermName) = f(this)
240+
241+
/*def exists(p: Char => Boolean): Boolean = {
242+
var i = 0
243+
while (i < length && !p(chrs(start + i))) i += 1
244+
i < length
245+
}*/
236246

237247
def encode: SimpleTermName =
238248
if (dontEncode(toTermName)) this else NameTransformer.encode(this)
@@ -254,8 +264,6 @@ object Names {
254264

255265
class TypeName(val toTermName: TermName) extends Name {
256266

257-
def ++ (other: String): ThisName = toTermName.++(other).toTypeName
258-
259267
def isEmpty = toTermName.isEmpty
260268

261269
def encode = toTermName.encode.toTypeName
@@ -274,6 +282,9 @@ object Names {
274282
def asSimpleName = toTermName.asSimpleName
275283
def toSimpleName = toTermName.toSimpleName
276284
def rewrite(f: PartialFunction[Name, Name]): ThisName = toTermName.rewrite(f).toTypeName
285+
def collect[T](f: PartialFunction[Name, T]): Option[T] = toTermName.collect(f)
286+
def mapLast(f: SimpleTermName => SimpleTermName) = toTermName.mapLast(f).toTypeName
287+
def mapParts(f: SimpleTermName => SimpleTermName) = toTermName.mapParts(f).toTypeName
277288

278289
def likeKinded(name: Name): TypeName = name.toTypeName
279290

@@ -298,10 +309,6 @@ object Names {
298309
case qual: NameInfo.Qualified => qual.name
299310
case _ => underlying.lastPart
300311
}
301-
def ++ (other: String): ThisName = info match {
302-
case qual: NameInfo.Qualified => underlying.derived(qual.map(_ ++ other))
303-
case _ => (underlying ++ other).derived(info)
304-
}
305312
override def toString = info.mkString(underlying)
306313
override def debugString = s"${underlying.debugString}[$info]"
307314

@@ -315,6 +322,25 @@ object Names {
315322
case qual: NameInfo.Qualified => this
316323
case _ => underlying.rewrite(f).derived(info)
317324
}
325+
326+
def collect[T](f: PartialFunction[Name, T]): Option[T] =
327+
if (f.isDefinedAt(this)) Some(f(this))
328+
else info match {
329+
case qual: NameInfo.Qualified => None
330+
case _ => underlying.collect(f)
331+
}
332+
333+
def mapLast(f: SimpleTermName => SimpleTermName): ThisName =
334+
info match {
335+
case qual: NameInfo.Qualified => underlying.derived(qual.map(f))
336+
case _ => underlying.mapLast(f).derived(info)
337+
}
338+
339+
def mapParts(f: SimpleTermName => SimpleTermName): ThisName =
340+
info match {
341+
case qual: NameInfo.Qualified => underlying.mapParts(f).derived(qual.map(f))
342+
case _ => underlying.mapParts(f).derived(info)
343+
}
318344
}
319345

320346
// Nametable
@@ -478,23 +504,54 @@ object Names {
478504
}
479505

480506
implicit val NameOrdering: Ordering[Name] = new Ordering[Name] {
507+
private def compareInfos(x: NameInfo, y: NameInfo): Int =
508+
if (x.kind != y.kind) x.kind - y.kind
509+
else x match {
510+
case x: NameInfo.Qualified =>
511+
y match {
512+
case y: NameInfo.Qualified =>
513+
val s = x.separator.compareTo(y.separator)
514+
if (s == 0) compareSimpleNames(x.name, y.name) else s
515+
}
516+
case x: NameInfo.Numbered =>
517+
y match {
518+
case y: NameInfo.Numbered =>
519+
x.num - y.num
520+
}
521+
case _ =>
522+
assert(x == y)
523+
0
524+
}
525+
private def compareSimpleNames(x: SimpleTermName, y: SimpleTermName): Int = {
526+
val until = x.length min y.length
527+
var i = 0
528+
while (i < until && x(i) == y(i)) i = i + 1
529+
if (i < until) {
530+
if (x(i) < y(i)) -1
531+
else /*(x(i) > y(i))*/ 1
532+
} else {
533+
x.length - y.length
534+
}
535+
}
536+
private def compareTermNames(x: TermName, y: TermName): Int = x match {
537+
case x: SimpleTermName =>
538+
y match {
539+
case y: SimpleTermName => compareSimpleNames(x, y)
540+
case _ => -1
541+
}
542+
case DerivedTermName(xPre, xInfo) =>
543+
y match {
544+
case DerivedTermName(yPre, yInfo) =>
545+
val s = compareInfos(xInfo, yInfo)
546+
if (s == 0) compareTermNames(xPre, yPre) else s
547+
case _ => 1
548+
}
549+
}
481550
def compare(x: Name, y: Name): Int = {
482551
if (x.isTermName && y.isTypeName) 1
483552
else if (x.isTypeName && y.isTermName) -1
484553
else if (x eq y) 0
485-
else {
486-
val until = x.length min y.length
487-
var i = 0
488-
489-
while (i < until && x(i) == y(i)) i = i + 1
490-
491-
if (i < until) {
492-
if (x(i) < y(i)) -1
493-
else /*(x(i) > y(i))*/ 1
494-
} else {
495-
x.length - y.length
496-
}
497-
}
554+
else compareTermNames(x.toTermName, y.toTermName)
498555
}
499556
}
500557
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,11 @@ object StdNames {
542542
val synthSwitch: N = "$synthSwitch"
543543
val _scope: N = "$scope"
544544

545+
val nothingClass: N = "Nothing$"
546+
val nullClass: N = "Null$"
547+
548+
val falseModuleClassNames = Set(nothingClass, nullClass, nothingRuntimeClass, nullRuntimeClass)
549+
545550
// unencoded operators
546551
object raw {
547552
final val AMP : N = "&"

compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class NameBuffer extends TastyBuffer(10000) {
3636
case _: NameInfo.Expand => Expanded
3737
}
3838
tcon(nameIndex(prefix, toTasty), nameIndex(qual.name))
39+
case DerivedTermName(prefix, NameInfo.DefaultGetter(num)) =>
40+
DefaultGetter(nameIndex(prefix, toTasty), num)
3941
case name1 =>
4042
if (name1.isShadowedName) Shadowed(nameIndex(name1.revertShadowed, toTasty))
4143
else toTasty(name1.asSimpleName)

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
9090
case Shadowed(original) => toTermName(original).shadowedName
9191
case ModuleClass(original) => toTermName(original).moduleClassName.toTermName
9292
case SuperAccessor(accessed) => toTermName(accessed).superName
93-
case DefaultGetter(meth, num) => ???
93+
case DefaultGetter(meth, num) => toTermName(meth).defaultGetterName(num)
9494
}
9595

9696
private def qualTermName(qual: NameRef, name: NameRef, sep: String) =

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,10 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
431431

432432
val name1 = name0.adjustIfModuleClass(flags)
433433
val name2 = if (name1 == nme.TRAIT_CONSTRUCTOR) nme.CONSTRUCTOR else name1
434-
val name = if (flags is ModuleClass) name2.unmangleClassName else name2
434+
val name =
435+
if (flags is ModuleClass) name2.unmangleClassName
436+
else if (flags is Method) name2.asTermName.unmangleMethodName
437+
else name2
435438

436439
def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass)
437440
def isModuleClassRoot = (name == moduleClassRoot.name) && (owner == moduleClassRoot.owner) && (flags is Module)

0 commit comments

Comments
 (0)