Skip to content

Commit 6304195

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 29b51e8 commit 6304195

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
@@ -381,7 +381,7 @@ object desugar {
381381

382382
def anyRef = ref(defn.AnyRefAlias.typeRef)
383383
def productConstr(n: Int) = {
384-
val tycon = scalaDot((tpnme.Product.toString + n).toTypeName)
384+
val tycon = scalaDot((str.Product + n).toTypeName)
385385
val targs = constrVparamss.head map (_.tpt)
386386
if (targs.isEmpty) tycon else AppliedTypeTree(tycon, targs)
387387
}

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))
@@ -719,12 +719,11 @@ class Definitions {
719719
/** If type `ref` refers to a class in the scala package, its name, otherwise EmptyTypeName */
720720
def scalaClassName(ref: Type)(implicit ctx: Context): TypeName = scalaClassName(ref.classSymbol)
721721

722-
private def isVarArityClass(cls: Symbol, prefix: Name) = {
723-
val name = scalaClassName(cls)
724-
name.startsWith(prefix) &&
725-
name.length > prefix.length &&
726-
name.drop(prefix.length).forall(_.isDigit)
727-
}
722+
private def isVarArityClass(cls: Symbol, prefix: String) =
723+
scalaClassName(cls).testSimple(name =>
724+
name.startsWith(prefix) &&
725+
name.length > prefix.length &&
726+
name.drop(prefix.length).forall(_.isDigit))
728727

729728
def isBottomClass(cls: Symbol) =
730729
cls == NothingClass || cls == NullClass
@@ -754,9 +753,9 @@ class Definitions {
754753
*/
755754
def isSyntheticFunctionClass(cls: Symbol) = scalaClassName(cls).isSyntheticFunction
756755

757-
def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.AbstractFunction)
758-
def isTupleClass(cls: Symbol) = isVarArityClass(cls, tpnme.Tuple)
759-
def isProductClass(cls: Symbol) = isVarArityClass(cls, tpnme.Product)
756+
def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, str.AbstractFunction)
757+
def isTupleClass(cls: Symbol) = isVarArityClass(cls, str.Tuple)
758+
def isProductClass(cls: Symbol) = isVarArityClass(cls, str.Product)
760759

761760
/** Returns the erased class of the function class `cls`
762761
* - 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 */
@@ -126,56 +133,13 @@ object NameOps {
126133
}
127134
}
128135

129-
def unmangleClassName: N =
130-
if (name.isSimple && name.isTypeName)
131-
if (name.endsWith(MODULE_SUFFIX) && !tpnme.falseModuleClassNames.contains(name.asTypeName))
132-
likeTyped(name.dropRight(MODULE_SUFFIX.length).moduleClassName)
133-
else name
134-
else name
135-
136-
/** Translate a name into a list of simple TypeNames and TermNames.
137-
* In all segments before the last, type/term is determined by whether
138-
* the following separator char is '.' or '#'. The last segment
139-
* is of the same type as the original name.
140-
*
141-
* Examples:
142-
*
143-
* package foo {
144-
* object Lorax { object Wog ; class Wog }
145-
* class Lorax { object Zax ; class Zax }
146-
* }
147-
*
148-
* f("foo.Lorax".toTermName) == List("foo": Term, "Lorax": Term) // object Lorax
149-
* f("foo.Lorax".toTypeName) == List("foo": Term, "Lorax": Type) // class Lorax
150-
* f("Lorax.Wog".toTermName) == List("Lorax": Term, "Wog": Term) // object Wog
151-
* f("Lorax.Wog".toTypeName) == List("Lorax": Term, "Wog": Type) // class Wog
152-
* f("Lorax#Zax".toTermName) == List("Lorax": Type, "Zax": Term) // object Zax
153-
* f("Lorax#Zax".toTypeName) == List("Lorax": Type, "Zax": Type) // class Zax
154-
*
155-
* Note that in actual scala syntax you cannot refer to object Zax without an
156-
* instance of Lorax, so Lorax#Zax could only mean the type. One might think
157-
* that Lorax#Zax.type would work, but this is not accepted by the parser.
158-
* For the purposes of referencing that object, the syntax is allowed.
159-
*/
160-
def segments: List[Name] = {
161-
def mkName(name: Name, follow: Char): Name =
162-
if (follow == '.') name.toTermName else name.toTypeName
163-
164-
name.indexWhere(ch => ch == '.' || ch == '#') match {
165-
case -1 =>
166-
if (name.isEmpty) scala.Nil else name :: scala.Nil
167-
case idx =>
168-
mkName(name take idx, name(idx)) :: (name drop (idx + 1)).segments
169-
}
170-
}
171-
172136
/** Is a synthetic function name
173137
* - N for FunctionN
174138
* - N for ImplicitFunctionN
175139
* - (-1) otherwise
176140
*/
177141
def functionArity: Int =
178-
functionArityFor(tpnme.Function) max functionArityFor(tpnme.ImplicitFunction)
142+
functionArityFor(str.Function) max functionArityFor(str.ImplicitFunction)
179143

180144
/** Is a function name
181145
* - FunctionN for N >= 0
@@ -188,20 +152,20 @@ object NameOps {
188152
* - ImplicitFunctionN for N >= 0
189153
* - false otherwise
190154
*/
191-
def isImplicitFunction: Boolean = functionArityFor(tpnme.ImplicitFunction) >= 0
155+
def isImplicitFunction: Boolean = functionArityFor(str.ImplicitFunction) >= 0
192156

193157
/** Is a synthetic function name
194158
* - FunctionN for N > 22
195159
* - ImplicitFunctionN for N >= 0
196160
* - false otherwise
197161
*/
198162
def isSyntheticFunction: Boolean = {
199-
functionArityFor(tpnme.Function) > MaxImplementedFunctionArity ||
200-
functionArityFor(tpnme.ImplicitFunction) >= 0
163+
functionArityFor(str.Function) > MaxImplementedFunctionArity ||
164+
functionArityFor(str.ImplicitFunction) >= 0
201165
}
202166

203167
/** Parsed function arity for function with some specific prefix */
204-
private def functionArityFor(prefix: Name): Int = {
168+
private def functionArityFor(prefix: String): Int = {
205169
if (name.startsWith(prefix))
206170
try name.toString.substring(prefix.length).toInt
207171
catch { case _: NumberFormatException => -1 }
@@ -252,6 +216,13 @@ object NameOps {
252216
/** If name length exceeds allowable limit, replace part of it by hash */
253217
def compactified(implicit ctx: Context): TermName = termName(compactify(name.toString))
254218

219+
def unmangleClassName: N = name.toTermName match {
220+
case name: SimpleTermName
221+
if name.endsWith(str.MODULE_SUFFIX) && !nme.falseModuleClassNames.contains(name) =>
222+
likeTyped(name.dropRight(str.MODULE_SUFFIX.length).moduleClassName)
223+
case _ => name
224+
}
225+
255226
def unmangle(kind: NameKind): N = likeTyped {
256227
name rewrite {
257228
case unmangled: SimpleTermName =>
@@ -273,11 +244,11 @@ object NameOps {
273244
implicit class TermNameDecorator(val name: TermName) extends AnyVal {
274245
import nme._
275246

276-
def setterName: TermName = name.exclude(FieldName) ++ SETTER_SUFFIX
247+
def setterName: TermName = name.exclude(FieldName) ++ str.SETTER_SUFFIX
277248

278249
def getterName: TermName =
279250
name.exclude(FieldName).mapLast(n =>
280-
if (n.endsWith(SETTER_SUFFIX)) n.take(n.length - SETTER_SUFFIX.length).asSimpleName
251+
if (n.endsWith(SETTER_SUFFIX)) n.take(n.length - str.SETTER_SUFFIX.length).asSimpleName
281252
else n)
282253

283254
def fieldName: TermName =
@@ -291,7 +262,7 @@ object NameOps {
291262
else FieldName(name)
292263

293264
def stripScala2LocalSuffix: TermName =
294-
if (name.isScala2LocalSuffix) name.init.asTermName else name
265+
if (name.isScala2LocalSuffix) name.asSimpleName.dropRight(1) else name
295266

296267
/** The name unary_x for a prefix operator x */
297268
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)