aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2017-03-24 13:20:01 +0100
committerMartin Odersky <odersky@gmail.com>2017-04-11 09:33:10 +0200
commit0ad1cd816bc1537ad332addabb0ff6c293e3e0a0 (patch)
tree68ab44576e17d19fa6cca14a0f750266a638eb7f
parenta2731a8be2f3434218623c0b0ecd4078107f14a5 (diff)
downloaddotty-0ad1cd816bc1537ad332addabb0ff6c293e3e0a0.tar.gz
dotty-0ad1cd816bc1537ad332addabb0ff6c293e3e0a0.tar.bz2
dotty-0ad1cd816bc1537ad332addabb0ff6c293e3e0a0.zip
Add default getter names
Plus various bug fixes and filling in missing functionality
-rw-r--r--compiler/src/dotty/tools/dotc/core/NameInfos.scala17
-rw-r--r--compiler/src/dotty/tools/dotc/core/NameOps.scala69
-rw-r--r--compiler/src/dotty/tools/dotc/core/Names.scala111
-rw-r--r--compiler/src/dotty/tools/dotc/core/StdNames.scala5
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala5
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/transform/TreeChecker.scala4
9 files changed, 169 insertions, 57 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/NameInfos.scala b/compiler/src/dotty/tools/dotc/core/NameInfos.scala
index daaa5c4e1..c5b83b0dc 100644
--- a/compiler/src/dotty/tools/dotc/core/NameInfos.scala
+++ b/compiler/src/dotty/tools/dotc/core/NameInfos.scala
@@ -2,6 +2,7 @@ package dotty.tools.dotc
package core
import Names._
+import NameOps._
import StdNames._
/** Additional info associated with a name. At a minimum its kind and
@@ -20,6 +21,7 @@ object NameInfo {
val TermNameKind = 0
val QualifiedKind = 1
val ModuleClassKind = 2
+ val DefaultGetterKind = 3
val qualifier: Map[String, SimpleTermName => Qualified] =
Map("." -> Select,
@@ -43,7 +45,7 @@ object NameInfo {
def kind = QualifiedKind
override def map(f: SimpleTermName => SimpleTermName): NameInfo = newLikeThis(f(name))
def mkString(underlying: TermName) = s"$underlying$separator$name"
- override def toString = s"$getClass($name)"
+ override def toString = s"${getClass.getSimpleName}($name)"
}
case class Select(val name: SimpleTermName) extends Qualified {
@@ -66,6 +68,19 @@ object NameInfo {
def newLikeThis(name: SimpleTermName) = TraitSetter(name)
}
+ trait Numbered extends NameInfo {
+ def num: Int
+ override def toString = s"${getClass.getSimpleName}($num)"
+ }
+
+ case class DefaultGetter(val num: Int) extends Numbered {
+ def kind = DefaultGetterKind
+ def mkString(underlying: TermName) = {
+ val prefix = if (underlying.isConstructorName) nme.DEFAULT_GETTER_INIT else underlying
+ prefix.toString + nme.DEFAULT_GETTER + (num + 1)
+ }
+ }
+
val ModuleClass = new NameInfo {
def kind = ModuleClassKind
def mkString(underlying: TermName) = underlying + "$"
diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala
index 65669a871..eb284168a 100644
--- a/compiler/src/dotty/tools/dotc/core/NameOps.scala
+++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala
@@ -102,8 +102,10 @@ object NameOps {
def isOpAssignmentName: Boolean = name match {
case raw.NE | raw.LE | raw.GE | EMPTY =>
false
- case _ =>
+ case name: SimpleTermName =>
name.length > 0 && name.last == '=' && name.head != '=' && isOperatorPart(name.head)
+ case _ =>
+ false
}
/** If the name ends with $nn where nn are
@@ -164,7 +166,8 @@ object NameOps {
def expandedName(prefix: Name, separator: Name = nme.EXPAND_SEPARATOR): N =
likeTyped(
if (Config.semanticNames)
- prefix.derived(NameInfo.qualifier(separator.toString)(name.asSimpleName))
+ prefix.derived(NameInfo.qualifier(separator.toString)(name.toSimpleName))
+ // note: expanded name may itself be expanded. For example, look at javap of scala.App.initCode
else prefix ++ separator ++ name)
def expandedName(prefix: Name): N = expandedName(prefix, nme.EXPAND_SEPARATOR)
@@ -247,7 +250,7 @@ object NameOps {
*/
def unmangleClassName: N =
if (Config.semanticNames && name.isSimple && name.isTypeName)
- if (name.endsWith(MODULE_SUFFIX))
+ if (name.endsWith(MODULE_SUFFIX) && !tpnme.falseModuleClassNames.contains(name.asTypeName))
likeTyped(name.dropRight(MODULE_SUFFIX.length).moduleClassName)
else name
else name
@@ -404,44 +407,60 @@ object NameOps {
if (name.isSetterName) {
if (name.isTraitSetterName) {
// 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).asTermName
+ val start = name.lastPart.indexOfSlice(TRAIT_SETTER_SEPARATOR) + TRAIT_SETTER_SEPARATOR.length
+ val end = name.lastPart.indexOfSlice(SETTER_SUFFIX)
+ name.mapLast(n => (n.slice(start, end) ++ LOCAL_SUFFIX).asSimpleName)
} else getterName.fieldName
}
- else name ++ LOCAL_SUFFIX
+ else name.mapLast(n => (n ++ LOCAL_SUFFIX).asSimpleName)
private def setterToGetter: TermName = {
assert(name.endsWith(SETTER_SUFFIX), name + " is referenced as a setter but has wrong name format")
- name.take(name.length - SETTER_SUFFIX.length).asTermName
+ name.mapLast(n => n.take(n.length - SETTER_SUFFIX.length).asSimpleName)
}
def fieldToGetter: TermName = {
assert(name.isFieldName)
- name.take(name.length - LOCAL_SUFFIX.length).asTermName
+ name.mapLast(n => n.take(n.length - LOCAL_SUFFIX.length).asSimpleName)
}
/** Nominally, name$default$N, encoded for <init>
* @param Post the parameters position.
* @note Default getter name suffixes start at 1, so `pos` has to be adjusted by +1
*/
- def defaultGetterName(pos: Int): TermName = {
- val prefix = if (name.isConstructorName) DEFAULT_GETTER_INIT else name
- prefix ++ DEFAULT_GETTER ++ (pos + 1).toString
- }
+ def defaultGetterName(pos: Int): TermName =
+ if (Config.semanticNames) name.derived(NameInfo.DefaultGetter(pos))
+ else {
+ val prefix = if (name.isConstructorName) DEFAULT_GETTER_INIT else name
+ prefix ++ DEFAULT_GETTER ++ (pos + 1).toString
+ }
/** Nominally, name from name$default$N, CONSTRUCTOR for <init> */
- def defaultGetterToMethod: TermName = {
- val p = name.indexOfSlice(DEFAULT_GETTER)
- if (p >= 0) {
- val q = name.take(p).asTermName
- // i.e., if (q.decoded == CONSTRUCTOR.toString) CONSTRUCTOR else q
- if (q == DEFAULT_GETTER_INIT) CONSTRUCTOR else q
- } else name
+ def defaultGetterToMethod: TermName =
+ if (Config.semanticNames)
+ name rewrite {
+ case DerivedTermName(methName, NameInfo.DefaultGetter(_)) => methName
+ }
+ else mangledDefaultGetterToMethod
+
+ def mangledDefaultGetterToMethod: TermName = {
+ val p = name.indexOfSlice(DEFAULT_GETTER)
+ if (p >= 0) {
+ val q = name.take(p).asTermName
+ // i.e., if (q.decoded == CONSTRUCTOR.toString) CONSTRUCTOR else q
+ if (q == DEFAULT_GETTER_INIT) CONSTRUCTOR else q
+ } else name
}
/** If this is a default getter, its index (starting from 0), else -1 */
- def defaultGetterIndex: Int = {
+ def defaultGetterIndex: Int =
+ if (Config.semanticNames)
+ name collect {
+ case DerivedTermName(methName, NameInfo.DefaultGetter(num)) => num
+ } getOrElse -1
+ else mangledDefaultGetterIndex
+
+ def mangledDefaultGetterIndex: Int = {
var i = name.length
while (i > 0 && name(i - 1).isDigit) i -= 1
if (i > 0 && i < name.length && name.take(i).endsWith(DEFAULT_GETTER))
@@ -529,6 +548,14 @@ object NameOps {
}
def inlineAccessorName = nme.INLINE_ACCESSOR_PREFIX ++ name ++ "$"
+
+ def unmangleMethodName: TermName =
+ if (Config.semanticNames && name.isSimple) {
+ val idx = name.mangledDefaultGetterIndex
+ if (idx >= 0) name.mangledDefaultGetterToMethod.defaultGetterName(idx)
+ else name
+ }
+ else name
}
private final val FalseSuper = "$$super".toTermName
diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala
index 84b2fab0c..22d0588f4 100644
--- a/compiler/src/dotty/tools/dotc/core/Names.scala
+++ b/compiler/src/dotty/tools/dotc/core/Names.scala
@@ -66,6 +66,9 @@ object Names {
def asSimpleName: SimpleTermName
def toSimpleName: SimpleTermName
def rewrite(f: PartialFunction[Name, Name]): ThisName
+ def collect[T](f: PartialFunction[Name, T]): Option[T]
+ def mapLast(f: SimpleTermName => SimpleTermName): ThisName
+ def mapParts(f: SimpleTermName => SimpleTermName): ThisName
/** A name of the same kind as this name and with same characters as given `name` */
def likeKinded(name: Name): ThisName
@@ -88,9 +91,8 @@ object Names {
/** A more efficient version of concatenation */
def ++ (other: Name): ThisName = ++ (other.toString)
- def ++ (other: String): ThisName
-
- def replace(from: Char, to: Char): ThisName = likeKinded(asSimpleName.replace(from, to))
+ def ++ (other: String): ThisName = mapLast(n => termName(n.toString + other))
+ def replace(from: Char, to: Char): ThisName = mapParts(_.replace(from, to))
def isEmpty: Boolean
@@ -198,8 +200,6 @@ object Names {
def apply(n: Int) = chrs(start + n)
- def ++ (other: String): SimpleTermName = termName(toString + other)
-
private def contains(ch: Char): Boolean = {
var i = 0
while (i < length && chrs(start + i) != ch) i += 1
@@ -220,19 +220,29 @@ object Names {
i > str.length
}
- override def replace(from: Char, to: Char): ThisName = {
+ override def replace(from: Char, to: Char): SimpleTermName = {
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
}
- likeKinded(termName(cs, 0, length))
+ termName(cs, 0, length)
}
def isSimple = true
def asSimpleName = this
def toSimpleName = this
- def rewrite(f: PartialFunction[Name, Name]): ThisName = likeKinded(f(this))
+ def rewrite(f: PartialFunction[Name, Name]): ThisName =
+ if (f.isDefinedAt(this)) likeKinded(f(this)) else this
+ def collect[T](f: PartialFunction[Name, T]): Option[T] = f.lift(this)
+ def mapLast(f: SimpleTermName => SimpleTermName) = f(this)
+ def mapParts(f: SimpleTermName => SimpleTermName) = f(this)
+
+ /*def exists(p: Char => Boolean): Boolean = {
+ var i = 0
+ while (i < length && !p(chrs(start + i))) i += 1
+ i < length
+ }*/
def encode: SimpleTermName =
if (dontEncode(toTermName)) this else NameTransformer.encode(this)
@@ -254,8 +264,6 @@ object Names {
class TypeName(val toTermName: TermName) extends Name {
- def ++ (other: String): ThisName = toTermName.++(other).toTypeName
-
def isEmpty = toTermName.isEmpty
def encode = toTermName.encode.toTypeName
@@ -274,6 +282,9 @@ object Names {
def asSimpleName = toTermName.asSimpleName
def toSimpleName = toTermName.toSimpleName
def rewrite(f: PartialFunction[Name, Name]): ThisName = toTermName.rewrite(f).toTypeName
+ def collect[T](f: PartialFunction[Name, T]): Option[T] = toTermName.collect(f)
+ def mapLast(f: SimpleTermName => SimpleTermName) = toTermName.mapLast(f).toTypeName
+ def mapParts(f: SimpleTermName => SimpleTermName) = toTermName.mapParts(f).toTypeName
def likeKinded(name: Name): TypeName = name.toTypeName
@@ -298,10 +309,6 @@ object Names {
case qual: NameInfo.Qualified => qual.name
case _ => underlying.lastPart
}
- def ++ (other: String): ThisName = info match {
- case qual: NameInfo.Qualified => underlying.derived(qual.map(_ ++ other))
- case _ => (underlying ++ other).derived(info)
- }
override def toString = info.mkString(underlying)
override def debugString = s"${underlying.debugString}[$info]"
@@ -315,6 +322,25 @@ object Names {
case qual: NameInfo.Qualified => this
case _ => underlying.rewrite(f).derived(info)
}
+
+ def collect[T](f: PartialFunction[Name, T]): Option[T] =
+ if (f.isDefinedAt(this)) Some(f(this))
+ else info match {
+ case qual: NameInfo.Qualified => None
+ case _ => underlying.collect(f)
+ }
+
+ def mapLast(f: SimpleTermName => SimpleTermName): ThisName =
+ info match {
+ case qual: NameInfo.Qualified => underlying.derived(qual.map(f))
+ case _ => underlying.mapLast(f).derived(info)
+ }
+
+ def mapParts(f: SimpleTermName => SimpleTermName): ThisName =
+ info match {
+ case qual: NameInfo.Qualified => underlying.mapParts(f).derived(qual.map(f))
+ case _ => underlying.mapParts(f).derived(info)
+ }
}
// Nametable
@@ -478,23 +504,54 @@ object Names {
}
implicit val NameOrdering: Ordering[Name] = new Ordering[Name] {
+ private def compareInfos(x: NameInfo, y: NameInfo): Int =
+ if (x.kind != y.kind) x.kind - y.kind
+ else x match {
+ case x: NameInfo.Qualified =>
+ y match {
+ case y: NameInfo.Qualified =>
+ val s = x.separator.compareTo(y.separator)
+ if (s == 0) compareSimpleNames(x.name, y.name) else s
+ }
+ case x: NameInfo.Numbered =>
+ y match {
+ case y: NameInfo.Numbered =>
+ x.num - y.num
+ }
+ case _ =>
+ assert(x == y)
+ 0
+ }
+ private def compareSimpleNames(x: SimpleTermName, y: SimpleTermName): Int = {
+ val until = x.length min y.length
+ var i = 0
+ while (i < until && x(i) == y(i)) i = i + 1
+ if (i < until) {
+ if (x(i) < y(i)) -1
+ else /*(x(i) > y(i))*/ 1
+ } else {
+ x.length - y.length
+ }
+ }
+ private def compareTermNames(x: TermName, y: TermName): Int = x match {
+ case x: SimpleTermName =>
+ y match {
+ case y: SimpleTermName => compareSimpleNames(x, y)
+ case _ => -1
+ }
+ case DerivedTermName(xPre, xInfo) =>
+ y match {
+ case DerivedTermName(yPre, yInfo) =>
+ val s = compareInfos(xInfo, yInfo)
+ if (s == 0) compareTermNames(xPre, yPre) else s
+ case _ => 1
+ }
+ }
def compare(x: Name, y: Name): Int = {
if (x.isTermName && y.isTypeName) 1
else if (x.isTypeName && y.isTermName) -1
else if (x eq y) 0
- else {
- val until = x.length min y.length
- var i = 0
-
- while (i < until && x(i) == y(i)) i = i + 1
-
- if (i < until) {
- if (x(i) < y(i)) -1
- else /*(x(i) > y(i))*/ 1
- } else {
- x.length - y.length
- }
- }
+ else compareTermNames(x.toTermName, y.toTermName)
}
}
}
diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala
index 9e05d4bce..1a65556ba 100644
--- a/compiler/src/dotty/tools/dotc/core/StdNames.scala
+++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala
@@ -546,6 +546,11 @@ object StdNames {
val synthSwitch: N = "$synthSwitch"
val _scope: N = "$scope"
+ val nothingClass: N = "Nothing$"
+ val nullClass: N = "Null$"
+
+ val falseModuleClassNames = Set(nothingClass, nullClass, nothingRuntimeClass, nullRuntimeClass)
+
// unencoded operators
object raw {
final val AMP : N = "&"
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala
index 7ac505a20..b45255eb8 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala
@@ -36,6 +36,8 @@ class NameBuffer extends TastyBuffer(10000) {
case _: NameInfo.Expand => Expanded
}
tcon(nameIndex(prefix, toTasty), nameIndex(qual.name))
+ case DerivedTermName(prefix, NameInfo.DefaultGetter(num)) =>
+ DefaultGetter(nameIndex(prefix, toTasty), num)
case name1 =>
if (name1.isShadowedName) Shadowed(nameIndex(name1.revertShadowed, toTasty))
else toTasty(name1.asSimpleName)
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
index 06165c6f4..d4269d6e4 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
@@ -90,7 +90,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
case Shadowed(original) => toTermName(original).shadowedName
case ModuleClass(original) => toTermName(original).moduleClassName.toTermName
case SuperAccessor(accessed) => toTermName(accessed).superName
- case DefaultGetter(meth, num) => ???
+ case DefaultGetter(meth, num) => toTermName(meth).defaultGetterName(num)
}
private def qualTermName(qual: NameRef, name: NameRef, sep: String) =
diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
index a49379327..084b8d098 100644
--- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
+++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
@@ -433,7 +433,10 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
val name1 = name0.adjustIfModuleClass(flags)
val name2 = if (name1 == nme.TRAIT_CONSTRUCTOR) nme.CONSTRUCTOR else name1
- val name = if (flags is ModuleClass) name2.unmangleClassName else name2
+ val name =
+ if (flags is ModuleClass) name2.unmangleClassName
+ else if (flags is Method) name2.asTermName.unmangleMethodName
+ else name2
def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass)
def isModuleClassRoot = (name == moduleClassRoot.name) && (owner == moduleClassRoot.owner) && (flags is Module)
diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala
index 3a301167d..b6c28f570 100644
--- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala
@@ -18,6 +18,7 @@ import util.Positions._
import Names._
import collection.mutable
import ResolveSuper._
+import config.Config
/** This phase adds super accessors and method overrides where
* linearization differs from Java's rule for default methods in interfaces.
@@ -95,10 +96,12 @@ object ResolveSuper {
var bcs = base.info.baseClasses.dropWhile(acc.owner != _).tail
var sym: Symbol = NoSymbol
val unexpandedAccName =
- if (acc.is(ExpandedName)) // Cannot use unexpandedName because of #765. t2183.scala would fail if we did.
- acc.name
- .drop(acc.name.indexOfSlice(nme.EXPAND_SEPARATOR ++ nme.SUPER_PREFIX))
- .drop(nme.EXPAND_SEPARATOR.length)
+ if (acc.is(ExpandedName))
+ if (Config.semanticNames) acc.name.unexpandedName
+ else // Cannot use unexpandedName because of #765. t2183.scala would fail if we did.
+ acc.name
+ .drop(acc.name.indexOfSlice(nme.EXPAND_SEPARATOR ++ nme.SUPER_PREFIX))
+ .drop(nme.EXPAND_SEPARATOR.length)
else acc.name
val SuperAccessorName(memberName) = unexpandedAccName: Name // dotty deviation: ": Name" needed otherwise pattern type is neither a subtype nor a supertype of selector type
ctx.debuglog(i"starting rebindsuper from $base of ${acc.showLocated}: ${acc.info} in $bcs, name = $memberName")
diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
index ebb5b605b..199fac82b 100644
--- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -50,10 +50,10 @@ class TreeChecker extends Phase with SymTransformer {
private val seenModuleVals = collection.mutable.HashMap[String, Symbol]()
def isValidJVMName(name: Name) =
- !name.exists(c => c == '.' || c == ';' || c =='[' || c == '/')
+ !name.toString.exists(c => c == '.' || c == ';' || c =='[' || c == '/')
def isValidJVMMethodName(name: Name) =
- !name.exists(c => c == '.' || c == ';' || c =='[' || c == '/' || c == '<' || c == '>')
+ !name.toString.exists(c => c == '.' || c == ';' || c =='[' || c == '/' || c == '<' || c == '>')
def printError(str: String)(implicit ctx: Context) = {
ctx.echo(Console.RED + "[error] " + Console.WHITE + str)