Skip to content

Commit a94400c

Browse files
committed
Names are no longer Seqs
Drop Seq implementation of name. This implementation was always problematic because it entailed potentially very costly conversions to toSimpleName. We now have better control over when we convert a name to a simple name.
1 parent 3f3c8ec commit a94400c

16 files changed

+124
-139
lines changed

compiler/src/dotty/tools/dotc/FromTasty.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Decorators._
1717
import dotty.tools.dotc.transform.Pickler
1818
import tasty.DottyUnpickler
1919
import ast.tpd._
20+
import NameKinds.QualifiedName
2021

2122
/** Compiler for TASTY files.
2223
* Usage:
@@ -74,7 +75,7 @@ object FromTasty extends Driver {
7475
case unit: TASTYCompilationUnit =>
7576
val className = unit.className.toTypeName
7677
val clsd =
77-
if (className.contains('.')) ctx.base.staticRef(className)
78+
if (className.is(QualifiedName)) ctx.base.staticRef(className)
7879
else defn.EmptyPackageClass.info.decl(className)
7980
def cannotUnpickle(reason: String) = {
8081
ctx.error(s"class $className cannot be unpickled because $reason")

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ object desugar {
403403

404404
def anyRef = ref(defn.AnyRefAlias.typeRef)
405405
def productConstr(n: Int) = {
406-
val tycon = scalaDot((tpnme.Product.toString + n).toTypeName)
406+
val tycon = scalaDot((str.Product + n).toTypeName)
407407
val targs = constrVparamss.head map (_.tpt)
408408
if (targs.isEmpty) tycon else AppliedTypeTree(tycon, targs)
409409
}

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
157157
}
158158

159159
/** Is name a left-associative operator? */
160-
def isLeftAssoc(operator: Name) = operator.nonEmpty && (operator.last != ':')
160+
def isLeftAssoc(operator: Name) = !operator.isEmpty && (operator.toSimpleName.last != ':')
161161

162162
/** can this type be a type pattern? */
163163
def mayBeTypePat(tree: untpd.Tree): Boolean = unsplice(tree) match {

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

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class Definitions {
119119
enterTypeParam(cls, name ++ "$T" ++ i.toString, Contravariant, decls)
120120
val resParam = enterTypeParam(cls, name ++ "$R", Covariant, decls)
121121
val (methodType, parentTraits) =
122-
if (name.startsWith(tpnme.ImplicitFunction)) {
122+
if (name.startsWith(str.ImplicitFunction)) {
123123
val superTrait =
124124
FunctionType(arity).appliedTo(argParams.map(_.typeRef) ::: resParam.typeRef :: Nil)
125125
(ImplicitMethodType, ctx.normalizeToClassRefs(superTrait :: Nil, cls, decls))
@@ -723,12 +723,11 @@ class Definitions {
723723
/** If type `ref` refers to a class in the scala package, its name, otherwise EmptyTypeName */
724724
def scalaClassName(ref: Type)(implicit ctx: Context): TypeName = scalaClassName(ref.classSymbol)
725725

726-
private def isVarArityClass(cls: Symbol, prefix: Name) = {
727-
val name = scalaClassName(cls)
728-
name.startsWith(prefix) &&
729-
name.length > prefix.length &&
730-
name.drop(prefix.length).forall(_.isDigit)
731-
}
726+
private def isVarArityClass(cls: Symbol, prefix: String) =
727+
scalaClassName(cls).testSimple(name =>
728+
name.startsWith(prefix) &&
729+
name.length > prefix.length &&
730+
name.drop(prefix.length).forall(_.isDigit))
732731

733732
def isBottomClass(cls: Symbol) =
734733
cls == NothingClass || cls == NullClass
@@ -758,9 +757,9 @@ class Definitions {
758757
*/
759758
def isSyntheticFunctionClass(cls: Symbol) = scalaClassName(cls).isSyntheticFunction
760759

761-
def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.AbstractFunction)
762-
def isTupleClass(cls: Symbol) = isVarArityClass(cls, tpnme.Tuple)
763-
def isProductClass(cls: Symbol) = isVarArityClass(cls, tpnme.Product)
760+
def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, str.AbstractFunction)
761+
def isTupleClass(cls: Symbol) = isVarArityClass(cls, str.Tuple)
762+
def isProductClass(cls: Symbol) = isVarArityClass(cls, str.Product)
764763

765764
/** Returns the erased class of the function class `cls`
766765
* - FunctionN for N > 22 becomes FunctionXXL

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ object NameKinds {
164164
val ExpandPrefixName = new QualifiedNameKind(EXPANDPREFIX, "$")
165165

166166
val ExpandedName = new QualifiedNameKind(EXPANDED, str.EXPAND_SEPARATOR) {
167-
private val FalseSuper = "$$super".toTermName
167+
private val FalseSuper = termName("$$super")
168168
private val FalseSuperLength = FalseSuper.length
169169

170170
override def unmangle(name: SimpleTermName): TermName = {
@@ -216,10 +216,10 @@ object NameKinds {
216216
object DefaultGetterName extends NumberedNameKind(DEFAULTGETTER, "DefaultGetter") {
217217
def mkString(underlying: TermName, info: ThisInfo) = {
218218
val prefix = if (underlying.isConstructorName) nme.DEFAULT_GETTER_INIT else underlying
219-
prefix.toString + nme.DEFAULT_GETTER + (info.num + 1)
219+
prefix.toString + str.DEFAULT_GETTER + (info.num + 1)
220220
}
221221

222-
private val dgLen = nme.DEFAULT_GETTER.length
222+
private val dgLen = str.DEFAULT_GETTER.length
223223

224224
override def unmangle(name: SimpleTermName): TermName = {
225225
var i = name.length

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

Lines changed: 36 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -52,24 +52,32 @@ object NameOps {
5252
implicit class NameDecorator[N <: Name](val name: N) extends AnyVal {
5353
import nme._
5454

55+
def testSimple(f: SimpleTermName => Boolean): Boolean = name match {
56+
case name: SimpleTermName => f(name)
57+
case name: TypeName => name.toTermName.testSimple(f)
58+
case _ => false
59+
}
60+
5561
def likeTyped(n: PreName): N =
5662
(if (name.isTermName) n.toTermName else n.toTypeName).asInstanceOf[N]
5763

5864
def isConstructorName = name == CONSTRUCTOR || name == TRAIT_CONSTRUCTOR
5965
def isStaticConstructorName = name == STATIC_CONSTRUCTOR
6066
def isLocalDummyName = name startsWith LOCALDUMMY_PREFIX
61-
def isReplWrapperName = name.toSimpleName containsSlice INTERPRETER_IMPORT_WRAPPER
67+
def isReplWrapperName = name.toString contains str.INTERPRETER_IMPORT_WRAPPER
6268
def isSetterName = name endsWith SETTER_SUFFIX
63-
def isScala2LocalSuffix = name.endsWith(" ")
64-
def isSelectorName = name.startsWith("_") && name.tail.forall(_.isDigit)
69+
def isScala2LocalSuffix = testSimple(_.endsWith(" "))
70+
def isSelectorName = testSimple(n => n.startsWith("_") && n.drop(1).forall(_.isDigit))
6571

6672
/** Is name a variable name? */
67-
def isVariableName: Boolean = name.length > 0 && {
68-
val first = name.head
69-
(((first.isLower && first.isLetter) || first == '_')
70-
&& (name != false_)
71-
&& (name != true_)
72-
&& (name != null_))
73+
def isVariableName: Boolean = testSimple { n =>
74+
n.length > 0 && {
75+
val first = n.head
76+
(((first.isLower && first.isLetter) || first == '_')
77+
&& (n != false_)
78+
&& (n != true_)
79+
&& (n != null_))
80+
}
7381
}
7482

7583
def isOpAssignmentName: Boolean = name match {
@@ -91,11 +99,10 @@ object NameOps {
9199
* method needs to work on mangled as well as unmangled names because
92100
* it is also called from the backend.
93101
*/
94-
def stripModuleClassSuffix: Name = name.toTermName match {
95-
case n: SimpleTermName if n.endsWith("$") =>
96-
name.unmangleClassName.exclude(ModuleClassName)
97-
case _ =>
98-
name.exclude(ModuleClassName)
102+
def stripModuleClassSuffix: N = likeTyped {
103+
val name1 =
104+
if (name.isSimple && name.endsWith("$")) name.unmangleClassName else name
105+
name.exclude(ModuleClassName)
99106
}
100107

101108
/** If flags is a ModuleClass but not a Package, add module class suffix */
@@ -159,56 +166,13 @@ object NameOps {
159166
}
160167
}
161168

162-
def unmangleClassName: N =
163-
if (name.isSimple && name.isTypeName)
164-
if (name.endsWith(MODULE_SUFFIX) && !tpnme.falseModuleClassNames.contains(name.asTypeName))
165-
likeTyped(name.dropRight(MODULE_SUFFIX.length).moduleClassName)
166-
else name
167-
else name
168-
169-
/** Translate a name into a list of simple TypeNames and TermNames.
170-
* In all segments before the last, type/term is determined by whether
171-
* the following separator char is '.' or '#'. The last segment
172-
* is of the same type as the original name.
173-
*
174-
* Examples:
175-
*
176-
* package foo {
177-
* object Lorax { object Wog ; class Wog }
178-
* class Lorax { object Zax ; class Zax }
179-
* }
180-
*
181-
* f("foo.Lorax".toTermName) == List("foo": Term, "Lorax": Term) // object Lorax
182-
* f("foo.Lorax".toTypeName) == List("foo": Term, "Lorax": Type) // class Lorax
183-
* f("Lorax.Wog".toTermName) == List("Lorax": Term, "Wog": Term) // object Wog
184-
* f("Lorax.Wog".toTypeName) == List("Lorax": Term, "Wog": Type) // class Wog
185-
* f("Lorax#Zax".toTermName) == List("Lorax": Type, "Zax": Term) // object Zax
186-
* f("Lorax#Zax".toTypeName) == List("Lorax": Type, "Zax": Type) // class Zax
187-
*
188-
* Note that in actual scala syntax you cannot refer to object Zax without an
189-
* instance of Lorax, so Lorax#Zax could only mean the type. One might think
190-
* that Lorax#Zax.type would work, but this is not accepted by the parser.
191-
* For the purposes of referencing that object, the syntax is allowed.
192-
*/
193-
def segments: List[Name] = {
194-
def mkName(name: Name, follow: Char): Name =
195-
if (follow == '.') name.toTermName else name.toTypeName
196-
197-
name.indexWhere(ch => ch == '.' || ch == '#') match {
198-
case -1 =>
199-
if (name.isEmpty) scala.Nil else name :: scala.Nil
200-
case idx =>
201-
mkName(name take idx, name(idx)) :: (name drop (idx + 1)).segments
202-
}
203-
}
204-
205169
/** Is a synthetic function name
206170
* - N for FunctionN
207171
* - N for ImplicitFunctionN
208172
* - (-1) otherwise
209173
*/
210174
def functionArity: Int =
211-
functionArityFor(tpnme.Function) max functionArityFor(tpnme.ImplicitFunction)
175+
functionArityFor(str.Function) max functionArityFor(str.ImplicitFunction)
212176

213177
/** Is a function name
214178
* - FunctionN for N >= 0
@@ -221,20 +185,20 @@ object NameOps {
221185
* - ImplicitFunctionN for N >= 0
222186
* - false otherwise
223187
*/
224-
def isImplicitFunction: Boolean = functionArityFor(tpnme.ImplicitFunction) >= 0
188+
def isImplicitFunction: Boolean = functionArityFor(str.ImplicitFunction) >= 0
225189

226190
/** Is a synthetic function name
227191
* - FunctionN for N > 22
228192
* - ImplicitFunctionN for N >= 0
229193
* - false otherwise
230194
*/
231195
def isSyntheticFunction: Boolean = {
232-
functionArityFor(tpnme.Function) > MaxImplementedFunctionArity ||
233-
functionArityFor(tpnme.ImplicitFunction) >= 0
196+
functionArityFor(str.Function) > MaxImplementedFunctionArity ||
197+
functionArityFor(str.ImplicitFunction) >= 0
234198
}
235199

236200
/** Parsed function arity for function with some specific prefix */
237-
private def functionArityFor(prefix: Name): Int = {
201+
private def functionArityFor(prefix: String): Int = {
238202
if (name.startsWith(prefix))
239203
try name.toString.substring(prefix.length).toInt
240204
catch { case _: NumberFormatException => -1 }
@@ -285,6 +249,13 @@ object NameOps {
285249
/** If name length exceeds allowable limit, replace part of it by hash */
286250
def compactified(implicit ctx: Context): TermName = termName(compactify(name.toString))
287251

252+
def unmangleClassName: N = name.toTermName match {
253+
case name: SimpleTermName
254+
if name.endsWith(str.MODULE_SUFFIX) && !nme.falseModuleClassNames.contains(name) =>
255+
likeTyped(name.dropRight(str.MODULE_SUFFIX.length).moduleClassName)
256+
case _ => name
257+
}
258+
288259
def unmangle(kind: NameKind): N = likeTyped {
289260
name rewrite {
290261
case unmangled: SimpleTermName =>
@@ -306,11 +277,11 @@ object NameOps {
306277
implicit class TermNameDecorator(val name: TermName) extends AnyVal {
307278
import nme._
308279

309-
def setterName: TermName = name.exclude(FieldName) ++ SETTER_SUFFIX
280+
def setterName: TermName = name.exclude(FieldName) ++ str.SETTER_SUFFIX
310281

311282
def getterName: TermName =
312283
name.exclude(FieldName).mapLast(n =>
313-
if (n.endsWith(SETTER_SUFFIX)) n.take(n.length - SETTER_SUFFIX.length).asSimpleName
284+
if (n.endsWith(SETTER_SUFFIX)) n.take(n.length - str.SETTER_SUFFIX.length).asSimpleName
314285
else n)
315286

316287
def fieldName: TermName =
@@ -324,7 +295,7 @@ object NameOps {
324295
else FieldName(name)
325296

326297
def stripScala2LocalSuffix: TermName =
327-
if (name.isScala2LocalSuffix) name.init.asTermName else name
298+
if (name.isScala2LocalSuffix) name.asSimpleName.dropRight(1) else name
328299

329300
/** The name unary_x for a prefix operator x */
330301
def toUnaryName: TermName = name match {

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

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ object Names {
8888
/** Replace operator symbols by corresponding \$op_name's. */
8989
def encode: Name
9090

91-
def firstPart: TermName
92-
def lastPart: TermName
91+
def firstPart: SimpleTermName
92+
def lastPart: SimpleTermName
9393

9494
/** A more efficient version of concatenation */
9595
def ++ (other: Name): ThisName = ++ (other.toString)
@@ -204,7 +204,15 @@ object Names {
204204

205205
def apply(n: Int) = chrs(start + n)
206206

207-
private def contains(ch: Char): Boolean = {
207+
def exists(p: Char => Boolean): Boolean = {
208+
var i = 0
209+
while (i < length && !p(chrs(start + i))) i += 1
210+
i < length
211+
}
212+
213+
def forall(p: Char => Boolean) = !exists(!p(_))
214+
215+
def contains(ch: Char): Boolean = {
208216
var i = 0
209217
while (i < length && chrs(start + i) != ch) i += 1
210218
i < length
@@ -224,6 +232,12 @@ object Names {
224232
i > str.length
225233
}
226234

235+
def lastIndexOf(ch: Char, start: Int = length - 1): Int = {
236+
var i = start
237+
while (i >= 0 && apply(i) != ch) i -= 1
238+
i
239+
}
240+
227241
override def replace(from: Char, to: Char): SimpleTermName = {
228242
val cs = new Array[Char](length)
229243
Array.copy(chrs, start, cs, 0, length)
@@ -233,6 +247,19 @@ object Names {
233247
termName(cs, 0, length)
234248
}
235249

250+
def slice(from: Int, until: Int): SimpleTermName = {
251+
assert(0 <= from && from <= until && until <= length)
252+
termName(chrs, start + from, until - from)
253+
}
254+
255+
def drop(n: Int) = slice(n, length)
256+
def take(n: Int) = slice(0, n)
257+
def dropRight(n: Int) = slice(0, length - n)
258+
def takeRight(n: Int) = slice(length - n, length)
259+
260+
def head = apply(0)
261+
def last = apply(length - 1)
262+
236263
def isSimple = true
237264
def asSimpleName = this
238265
def toSimpleName = this
@@ -242,12 +269,6 @@ object Names {
242269
def mapLast(f: SimpleTermName => SimpleTermName) = f(this)
243270
def mapParts(f: SimpleTermName => SimpleTermName) = f(this)
244271

245-
/*def exists(p: Char => Boolean): Boolean = {
246-
var i = 0
247-
while (i < length && !p(chrs(start + i))) i += 1
248-
i < length
249-
}*/
250-
251272
def encode: SimpleTermName =
252273
if (dontEncode(toTermName)) this else NameTransformer.encode(this)
253274

@@ -490,24 +511,6 @@ object Names {
490511

491512
val dontEncode = Set(CONSTRUCTOR, EMPTY_PACKAGE, REFINEMENT)
492513

493-
def termNameBuilder: Builder[Char, TermName] =
494-
StringBuilder.newBuilder.mapResult(termName)
495-
496-
def typeNameBuilder: Builder[Char, TypeName] =
497-
StringBuilder.newBuilder.mapResult(termName(_).toTypeName)
498-
499-
implicit class nameToSeq(val name: Name) extends IndexedSeqOptimized[Char, Name] {
500-
def length = name.asSimpleName.length
501-
def apply(n: Int) = name.asSimpleName.apply(n)
502-
override protected[this] def newBuilder: Builder[Char, Name] =
503-
if (name.isTypeName) typeNameBuilder else termNameBuilder
504-
505-
def seq: WrappedString = new WrappedString(name.toString)
506-
override protected[this] def thisCollection: WrappedString = seq
507-
def indexOfSlice(name: Name): Int = indexOfSlice(name.toString)
508-
def containsSlice(name: Name): Boolean = containsSlice(name.toString)
509-
}
510-
511514
implicit val NameOrdering: Ordering[Name] = new Ordering[Name] {
512515
private def compareInfos(x: NameInfo, y: NameInfo): Int =
513516
if (x.kind.tag != y.kind.tag) x.kind.tag - y.kind.tag

0 commit comments

Comments
 (0)