aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2017-03-22 17:59:25 +0100
committerMartin Odersky <odersky@gmail.com>2017-04-11 09:33:10 +0200
commit19bc1ff09fa73e13be7e3464b8440c04b657aa82 (patch)
treebc6934a3c47ab403f4dc3dd2c87531081887dc15
parent2cc16c4d990fa404577dbe1c944958a0cf9896a8 (diff)
downloaddotty-19bc1ff09fa73e13be7e3464b8440c04b657aa82.tar.gz
dotty-19bc1ff09fa73e13be7e3464b8440c04b657aa82.tar.bz2
dotty-19bc1ff09fa73e13be7e3464b8440c04b657aa82.zip
Disentangle Names from Seqs
Structured names are not Seqs anymmore. But the Seq behavior is required in many places that mangle names. As an intermediate step we drop the Seq basetype but add Seq behavior through a decorator. Most Seq operations only work on SimpleTermNames and their TypeName analogue, will throw an exception wehn called on structured names.
-rw-r--r--compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/core/NameInfos.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/core/NameOps.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/Names.scala128
-rw-r--r--compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Scanners.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Tokens.scala2
10 files changed, 71 insertions, 83 deletions
diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
index 77e979e4d..309d97261 100644
--- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
+++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
@@ -544,8 +544,8 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
def toTermName: Name = n.toTermName
def dropModule: Name = n.stripModuleClassSuffix
- def len: Int = n.length
- def offset: Int = n.start
+ def len: Int = n.toSimpleName.length
+ def offset: Int = n.toSimpleName.start
def isTermName: Boolean = n.isTermName
def startsWith(s: String): Boolean = n.startsWith(s)
}
diff --git a/compiler/src/dotty/tools/dotc/core/NameInfos.scala b/compiler/src/dotty/tools/dotc/core/NameInfos.scala
index 51c04b9e4..650a0c0a4 100644
--- a/compiler/src/dotty/tools/dotc/core/NameInfos.scala
+++ b/compiler/src/dotty/tools/dotc/core/NameInfos.scala
@@ -6,9 +6,11 @@ import Names._
/** Additional info associated with a name. At a minimum its kind and
* a way to turn it into a string.
*/
-abstract class NameInfo {
+abstract class NameInfo extends util.DotClass {
def kind: NameInfo.Kind
def mkString(underlying: TermName): String
+ def contains(ch: Char): Boolean = false
+ def ++(other: String): NameInfo = unsupported("++")
}
object NameInfo {
@@ -30,6 +32,8 @@ object NameInfo {
case class Qualified(name: TermName, separator: String) extends NameInfo {
def kind = QualifiedKind
def mkString(underlying: TermName) = s"$underlying$separator$name"
+ override def contains(ch: Char): Boolean = name.contains(ch)
+ override def ++(other: String): NameInfo = Qualified(name ++ other, separator)
override def toString = s"Qualified($name, $separator)"
}
diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala
index 38eb21446..27065a50a 100644
--- a/compiler/src/dotty/tools/dotc/core/NameOps.scala
+++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala
@@ -390,7 +390,7 @@ object NameOps {
// has form <$-separated-trait-name>$_setter_$ `name`_$eq
val start = name.indexOfSlice(TRAIT_SETTER_SEPARATOR) + TRAIT_SETTER_SEPARATOR.length
val end = name.indexOfSlice(SETTER_SUFFIX)
- name.slice(start, end) ++ LOCAL_SUFFIX
+ (name.slice(start, end) ++ LOCAL_SUFFIX).asTermName
} else getterName.fieldName
}
else name ++ LOCAL_SUFFIX
diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala
index 9488aef61..9ec9e73f2 100644
--- a/compiler/src/dotty/tools/dotc/core/Names.scala
+++ b/compiler/src/dotty/tools/dotc/core/Names.scala
@@ -39,20 +39,11 @@ object Names {
* 3. Names are intended to be encoded strings. @see dotc.util.NameTransformer.
* The encoding will be applied when converting a string to a name.
*/
- abstract class Name extends DotClass
- with PreName
- with collection.immutable.Seq[Char]
- with IndexedSeqOptimized[Char, Name] {
+ abstract class Name extends DotClass with PreName {
/** A type for names of the same kind as this name */
type ThisName <: Name
- /** The start index in the character array */
- def start: Int
-
- /** The length of the names */
- override def length: Int
-
/** Is this name a type name? */
def isTypeName: Boolean
@@ -71,6 +62,8 @@ object Names {
/** This name downcasted to a term name */
def asTermName: TermName
+ def toSimpleName: SimpleTermName = this.asInstanceOf[SimpleTermName]
+
/** A name of the same kind as this name and with same characters as given `name` */
def fromName(name: Name): ThisName
@@ -81,17 +74,6 @@ object Names {
def toText(printer: Printer): Text = printer.toText(this)
- /** Write to UTF8 representation of this name to given character array.
- * Start copying to index `to`. Return index of next free byte in array.
- * Array must have enough remaining space for all bytes
- * (i.e. maximally 3*length bytes).
- */
- final def copyUTF8(bs: Array[Byte], offset: Int): Int = {
- val bytes = Codec.toUTF8(chrs, start, length)
- scala.compat.Platform.arraycopy(bytes, 0, bs, offset, bytes.length)
- offset + bytes.length
- }
-
/** Replace \$op_name's by corresponding operator symbols. */
def decode: Name =
if (contains('$')) fromName(termName(NameTransformer.decode(toString)))
@@ -103,41 +85,13 @@ object Names {
/** A more efficient version of concatenation */
def ++ (other: Name): ThisName = ++ (other.toString)
+ def ++ (other: String): ThisName
- def ++ (other: String): ThisName = fromName(termName(toString + other))
-
- def replace(from: Char, to: Char): ThisName = {
- val cs = new Array[Char](length)
- Array.copy(chrs, start, cs, 0, length)
- for (i <- 0 until length) {
- if (cs(i) == from) cs(i) = to
- }
- fromName(termName(cs, 0, length))
- }
-
- def contains(ch: Char): Boolean = {
- var i = 0
- while (i < length && chrs(start + i) != ch) i += 1
- i < length
- }
+ def replace(from: Char, to: Char): ThisName = fromName(toSimpleName.replace(from, to))
- def firstChar = chrs(start)
-
- // ----- Collections integration -------------------------------------
-
- override protected[this] def thisCollection: WrappedString = new WrappedString(repr.toString)
- override protected[this] def toCollection(repr: Name): WrappedString = new WrappedString(repr.toString)
-
- override protected[this] def newBuilder: Builder[Char, Name] = unsupported("newBuilder")
-
- override def apply(index: Int): Char = chrs(start + index)
-
- override def slice(from: Int, until: Int): ThisName =
- fromName(termName(chrs, start + from, until - from))
+ def contains(ch: Char): Boolean
override def equals(that: Any) = this eq that.asInstanceOf[AnyRef]
-
- override def seq = toCollection(this)
}
abstract class TermName extends Name {
@@ -226,12 +180,30 @@ object Names {
ownKind == kind ||
!NameInfo.definesNewName(ownKind) && ownKind > kind && underlying.is(kind)
}
-
- override protected[this] def newBuilder: Builder[Char, Name] = termNameBuilder
}
class SimpleTermName(val start: Int, val length: Int, @sharable private[Names] var next: SimpleTermName) extends TermName {
// `next` is @sharable because it is only modified in the synchronized block of termName.
+
+ def apply(n: Int) = chrs(start + n)
+
+ def ++ (other: String): ThisName = termName(toString + other)
+
+ def contains(ch: Char): Boolean = {
+ var i = 0
+ while (i < length && chrs(start + i) != ch) i += 1
+ i < length
+ }
+
+ override def replace(from: Char, to: Char): ThisName = {
+ val cs = new Array[Char](length)
+ Array.copy(chrs, start, cs, 0, length)
+ for (i <- 0 until length) {
+ if (cs(i) == from) cs(i) = to
+ }
+ fromName(termName(cs, 0, length))
+ }
+
override def hashCode: Int = start
override def toString =
@@ -241,8 +213,12 @@ object Names {
}
class TypeName(val toTermName: TermName) extends Name {
- def start = toTermName.start
- override def length = toTermName.length
+
+ override def toSimpleName: SimpleTermName = toTermName.toSimpleName
+
+ def ++ (other: String): ThisName = toTermName.++(other).toTypeName
+
+ def contains(ch: Char): Boolean = toTermName.contains(ch)
type ThisName = TypeName
def isTypeName = true
@@ -257,9 +233,6 @@ object Names {
def without(kind: NameInfo.Kind): TypeName = toTermName.without(kind).toTypeName
def is(kind: NameInfo.Kind) = toTermName.is(kind)
- override protected[this] def newBuilder: Builder[Char, Name] =
- termNameBuilder.mapResult(_.toTypeName)
-
override def toString = toTermName.toString
override def debugString = toTermName.debugString + "/T"
}
@@ -269,8 +242,8 @@ object Names {
*/
class DerivedTermName(override val underlying: TermName, override val info: NameInfo)
extends TermName {
- def start = underlying.start
- override def length = underlying.length
+ def ++ (other: String): ThisName = derived(info ++ other)
+ def contains(ch: Char): Boolean = underlying.contains(ch) || info.contains(ch)
override def toString = info.mkString(underlying)
override def debugString = s"${underlying.debugString}[$info]"
}
@@ -319,7 +292,7 @@ object Names {
/** Create a term name from the characters in cs[offset..offset+len-1].
* Assume they are already encoded.
*/
- def termName(cs: Array[Char], offset: Int, len: Int): TermName = synchronized {
+ def termName(cs: Array[Char], offset: Int, len: Int): SimpleTermName = synchronized {
util.Stats.record("termName")
val h = hashValue(cs, offset, len) & (table.size - 1)
@@ -385,7 +358,7 @@ object Names {
/** Create a term name from the UTF8 encoded bytes in bs[offset..offset+len-1].
* Assume they are already encoded.
*/
- def termName(bs: Array[Byte], offset: Int, len: Int): TermName = {
+ def termName(bs: Array[Byte], offset: Int, len: Int): SimpleTermName = {
val chars = Codec.fromUTF8(bs, offset, len)
termName(chars, 0, chars.length)
}
@@ -397,7 +370,7 @@ object Names {
termName(bs, offset, len).toTypeName
/** Create a term name from a string, without encoding operators */
- def termName(s: String): TermName = termName(s.toCharArray, 0, s.length)
+ def termName(s: String): SimpleTermName = termName(s.toCharArray, 0, s.length)
/** Create a type name from a string, without encoding operators */
def typeName(s: String): TypeName = typeName(s.toCharArray, 0, s.length)
@@ -411,20 +384,31 @@ object Names {
val EmptyTypeName = EmptyTermName.toTypeName
// can't move CONSTRUCTOR/EMPTY_PACKAGE to `nme` because of bootstrap failures in `encode`.
- val CONSTRUCTOR = termName("<init>")
- val STATIC_CONSTRUCTOR = termName("<clinit>")
- val EMPTY_PACKAGE = termName("<empty>")
+ val CONSTRUCTOR: TermName = termName("<init>")
+ val STATIC_CONSTRUCTOR: TermName = termName("<clinit>")
+ val EMPTY_PACKAGE: TermName = termName("<empty>")
val dontEncode = Set[TermName](CONSTRUCTOR, EMPTY_PACKAGE)
def termNameBuilder: Builder[Char, TermName] =
StringBuilder.newBuilder.mapResult(termName)
- implicit val nameCanBuildFrom: CanBuildFrom[Name, Char, Name] = new CanBuildFrom[Name, Char, Name] {
- def apply(from: Name): Builder[Char, Name] =
- StringBuilder.newBuilder.mapResult(s =>
- from.fromName(termName(s.toCharArray, 0, s.length)))
- def apply(): Builder[Char, Name] = termNameBuilder
+ def typeNameBuilder: Builder[Char, TypeName] =
+ StringBuilder.newBuilder.mapResult(termName(_).toTypeName)
+
+ implicit class nameToSeq(val name: Name) extends IndexedSeqOptimized[Char, Name] {
+ def length = name.toSimpleName.length
+ def apply(n: Int) = name.toSimpleName.apply(n)
+ override protected[this] def newBuilder: Builder[Char, Name] =
+ if (name.isTypeName) typeNameBuilder else termNameBuilder
+
+ def seq: WrappedString = new WrappedString(name.toString)
+ override protected[this] def thisCollection: WrappedString = seq
+ def startsWith(name: Name): Boolean = startsWith(name.toString)
+ def endsWith(name: Name): Boolean = endsWith(name.toString)
+ def indexOfSlice(name: Name): Int = indexOfSlice(name.toString)
+ def lastIndexOfSlice(name: Name): Int = lastIndexOfSlice(name.toString)
+ def containsSlice(name: Name): Boolean = containsSlice(name.toString)
}
implicit val NameOrdering: Ordering[Name] = new Ordering[Name] {
diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
index a0e4cc62b..131c9cf9b 100644
--- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
+++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
@@ -256,7 +256,7 @@ class ClassfileParser(
def subName(isDelimiter: Char => Boolean): TermName = {
val start = index
while (!isDelimiter(sig(index))) { index += 1 }
- sig.slice(start, index)
+ sig.slice(start, index).asTermName
}
// Warning: sigToType contains nested completers which might be forced in a later run!
// So local methods need their own ctx parameters.
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala
index 3ff7298ce..b05e6ef21 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala
@@ -27,7 +27,7 @@ class NameBuffer extends TastyBuffer(10000) {
def nameIndex(name: Name): NameRef = {
val tname =
if (name.isShadowedName) Shadowed(nameIndex(name.revertShadowed))
- else Simple(name.toTermName)
+ else Simple(name.toTermName.toSimpleName)
nameIndex(tname)
}
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala
index 26807115c..da205542e 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala
@@ -3,7 +3,7 @@ package dotc
package core
package tasty
-import core.Names.TermName
+import core.Names.SimpleTermName
import collection.mutable
abstract class TastyName
@@ -12,7 +12,7 @@ object TastyName {
case class NameRef(index: Int) extends AnyVal
- case class Simple(name: TermName) extends TastyName
+ case class Simple(name: SimpleTermName) extends TastyName
case class Qualified(qualified: NameRef, selector: NameRef) extends TastyName
case class Signed(original: NameRef, params: List[NameRef], result: NameRef) extends TastyName
case class Expanded(prefix: NameRef, original: NameRef) extends TastyName
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index 902d01c21..7a6b6b7ea 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
@@ -576,7 +576,7 @@ class TreePickler(pickler: TastyPickler) {
}
def qualifiedName(sym: Symbol)(implicit ctx: Context): TastyName =
- if (sym.isRoot || sym.owner.isRoot) TastyName.Simple(sym.name.toTermName)
+ if (sym.isRoot || sym.owner.isRoot) TastyName.Simple(sym.name.toTermName.toSimpleName)
else TastyName.Qualified(nameIndex(qualifiedName(sym.owner)), nameIndex(sym.name))
def pickleModifiers(sym: Symbol)(implicit ctx: Context): Unit = {
diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala
index ff5019dc9..bcf6eb4a5 100644
--- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala
@@ -101,7 +101,7 @@ object Scanners {
target.name = flushBuf(litBuf).toTermName
target.token = idtoken
if (idtoken == IDENTIFIER) {
- val idx = target.name.start
+ val idx = target.name.toSimpleName.start
target.token = toToken(idx)
}
}
diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala
index d2ea9240c..96ae25c9e 100644
--- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala
@@ -129,7 +129,7 @@ abstract class TokensCommon {
final val lastParen = RBRACE
def buildKeywordArray(keywords: TokenSet) = {
- def start(tok: Token) = tokenString(tok).toTermName.start
+ def start(tok: Token) = tokenString(tok).toTermName.toSimpleName.start
def sourceKeywords = keywords.toList.filter { (kw: Token) =>
val ts = tokenString(kw)
(ts != null) && !ts.contains(' ')