diff options
author | Martin Odersky <odersky@gmail.com> | 2017-03-23 23:35:17 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2017-04-11 09:33:10 +0200 |
commit | a2731a8be2f3434218623c0b0ecd4078107f14a5 (patch) | |
tree | 3077df892ba46e4142cb6a38555cc7604be36222 | |
parent | e2056bb62e8d4ce5806111f0c54f7331eb690f0a (diff) | |
download | dotty-a2731a8be2f3434218623c0b0ecd4078107f14a5.tar.gz dotty-a2731a8be2f3434218623c0b0ecd4078107f14a5.tar.bz2 dotty-a2731a8be2f3434218623c0b0ecd4078107f14a5.zip |
Handle expansion and flattening
12 files changed, 131 insertions, 49 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 20d7c1458..0ff335e40 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -316,7 +316,7 @@ object Trees { def namePos = if (pos.exists) if (rawMods.is(Synthetic)) Position(pos.point, pos.point) - else Position(pos.point, pos.point + name.stripModuleClassSuffix.length, pos.point) + else Position(pos.point, pos.point + name.stripModuleClassSuffix.lastPart.length, pos.point) else pos } diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index a679cad6f..aa0ea39a2 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -1190,8 +1190,10 @@ object Denotations { recur(path.toTermName, n => wrap(n.toTypeName)) case DerivedTermName(prefix, NameInfo.ModuleClass) => recur(prefix, n => wrap(n.derived(NameInfo.ModuleClass))) - case DerivedTermName(prefix, NameInfo.Qualified(selector, ".")) => + case DerivedTermName(prefix, NameInfo.Select(selector)) => select(recur(prefix), wrap(selector)) + case DerivedTermName(prefix, qual: NameInfo.Qualified) => + recur(prefix, n => wrap(n ++ qual.separator ++ qual.name)) case path: SimpleTermName => def recurSimple(len: Int, wrap: Name => Name): Denotation = { val point = path.lastIndexOf('.', len - 1) diff --git a/compiler/src/dotty/tools/dotc/core/NameInfos.scala b/compiler/src/dotty/tools/dotc/core/NameInfos.scala index e8db88f84..daaa5c4e1 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 StdNames._ /** Additional info associated with a name. At a minimum its kind and * a way to turn it into a string. @@ -20,6 +21,12 @@ object NameInfo { val QualifiedKind = 1 val ModuleClassKind = 2 + val qualifier: Map[String, SimpleTermName => Qualified] = + Map("." -> Select, + "$" -> Flatten, + str.EXPAND_SEPARATOR -> Expand, + str.TRAIT_SETTER_SEPARATOR -> TraitSetter) + def definesNewName(kind: Kind) = kind <= QualifiedKind /** TermNames have the lowest possible kind */ @@ -28,11 +35,35 @@ object NameInfo { def mkString(underlying: TermName) = underlying.toString // will cause an unsupported exception } - case class Qualified(name: SimpleTermName, separator: String) extends NameInfo { + trait Qualified extends NameInfo { + def name: SimpleTermName + def separator: String + def newLikeThis(name: SimpleTermName): Qualified // TODO: should use copy instead after bootstrap + def kind = QualifiedKind + override def map(f: SimpleTermName => SimpleTermName): NameInfo = newLikeThis(f(name)) def mkString(underlying: TermName) = s"$underlying$separator$name" - override def map(f: SimpleTermName => SimpleTermName): NameInfo = Qualified(f(name), separator) - override def toString = s"Qualified($name, $separator)" + override def toString = s"$getClass($name)" + } + + case class Select(val name: SimpleTermName) extends Qualified { + def separator = "." + def newLikeThis(name: SimpleTermName) = Select(name) + } + + case class Flatten(val name: SimpleTermName) extends Qualified { + def separator = "$" + def newLikeThis(name: SimpleTermName) = Flatten(name) + } + + case class Expand(val name: SimpleTermName) extends Qualified { + def separator = str.EXPAND_SEPARATOR + def newLikeThis(name: SimpleTermName) = Expand(name) + } + + case class TraitSetter(val name: SimpleTermName) extends Qualified { + def separator = nme.TRAIT_SETTER_SEPARATOR.toString + def newLikeThis(name: SimpleTermName) = TraitSetter(name) } val ModuleClass = new NameInfo { diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index c4d551981..65669a871 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -162,30 +162,46 @@ object NameOps { /** The expanded name of `name` relative to `basename` with given `separator` */ def expandedName(prefix: Name, separator: Name = nme.EXPAND_SEPARATOR): N = - name.likeKinded(prefix ++ separator ++ name).asInstanceOf[N] + likeTyped( + if (Config.semanticNames) + prefix.derived(NameInfo.qualifier(separator.toString)(name.asSimpleName)) + else prefix ++ separator ++ name) def expandedName(prefix: Name): N = expandedName(prefix, nme.EXPAND_SEPARATOR) - /** Revert the expanded name. Note: This currently gives incorrect results + /** Revert the expanded name. + * Note: This currently gives incorrect results * if the normal name contains `nme.EXPAND_SEPARATOR`, i.e. two consecutive '$' * signs. This can happen for instance if a super accessor is paired with * an encoded name, e.g. super$$plus$eq. See #765. */ - def unexpandedName: N = { - var idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) + def unexpandedName: N = likeTyped { + if (Config.semanticNames) + name.rewrite { + case DerivedTermName(_, NameInfo.Expand(unexp)) => unexp + } + else { + var idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) - // Hack to make super accessors from traits work. They would otherwise fail because of #765 - // TODO: drop this once we have more robust name handling - if (idx > FalseSuperLength && name.slice(idx - FalseSuperLength, idx) == FalseSuper) - idx -= FalseSuper.length + // Hack to make super accessors from traits work. They would otherwise fail because of #765 + // TODO: drop this once we have more robust name handling + if (idx > FalseSuperLength && name.slice(idx - FalseSuperLength, idx) == FalseSuper) + idx -= FalseSuper.length - if (idx < 0) name else (name drop (idx + nme.EXPAND_SEPARATOR.length)).asInstanceOf[N] + if (idx < 0) name else (name drop (idx + nme.EXPAND_SEPARATOR.length)) + } } - def expandedPrefix: N = { - val idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) - assert(idx >= 0) - name.take(idx).asInstanceOf[N] + def expandedPrefix: N = likeTyped { + if (Config.semanticNames) + name.rewrite { + case DerivedTermName(prefix, NameInfo.Expand(_)) => prefix + } + else { + val idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) + assert(idx >= 0) + name.take(idx) + } } def shadowedName: N = likeTyped(nme.SHADOWED ++ name) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index ffbb097b8..84b2fab0c 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -65,13 +65,12 @@ object Names { def isSimple: Boolean def asSimpleName: SimpleTermName def toSimpleName: SimpleTermName - def mapSimpleCore(f: SimpleTermName => Name): ThisName + def rewrite(f: PartialFunction[Name, Name]): ThisName /** A name of the same kind as this name and with same characters as given `name` */ def likeKinded(name: Name): ThisName def derived(info: NameInfo): ThisName - def select(name: SimpleTermName, sep: String) = derived(NameInfo.Qualified(name, sep)) def exclude(kind: NameInfo.Kind): ThisName def is(kind: NameInfo.Kind): Boolean def debugString: String @@ -99,6 +98,8 @@ object Names { def startsWith(name: Name): Boolean = startsWith(name.toString) def endsWith(str: String): Boolean = lastPart.endsWith(str) def endsWith(name: Name): Boolean = endsWith(name.toString) + def lastIndexOfSlice(str: String): Int = lastPart.toString.lastIndexOfSlice(str) + def lastIndexOfSlice(name: Name): Int = lastIndexOfSlice(name.toString) override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] } @@ -231,7 +232,7 @@ object Names { def isSimple = true def asSimpleName = this def toSimpleName = this - def mapSimpleCore(f: SimpleTermName => Name): TermName = likeKinded(f(this)) + def rewrite(f: PartialFunction[Name, Name]): ThisName = likeKinded(f(this)) def encode: SimpleTermName = if (dontEncode(toTermName)) this else NameTransformer.encode(this) @@ -272,7 +273,7 @@ object Names { def isSimple = toTermName.isSimple def asSimpleName = toTermName.asSimpleName def toSimpleName = toTermName.toSimpleName - def mapSimpleCore(f: SimpleTermName => Name): TypeName = toTermName.mapSimpleCore(f).toTypeName + def rewrite(f: PartialFunction[Name, Name]): ThisName = toTermName.rewrite(f).toTypeName def likeKinded(name: Name): TypeName = name.toTypeName @@ -292,16 +293,13 @@ object Names { def isEmpty = false def encode: Name = underlying.encode.derived(info.map(_.encode)) def decode: Name = underlying.decode.derived(info.map(_.decode)) - def firstPart = info match { - case NameInfo.Qualified(name, _) => name - case _ => underlying.firstPart - } + def firstPart = underlying.firstPart def lastPart = info match { - case NameInfo.Qualified(name, _) => name + case qual: NameInfo.Qualified => qual.name case _ => underlying.lastPart } def ++ (other: String): ThisName = info match { - case NameInfo.Qualified(name, sep) => underlying.select(name ++ other, sep) + case qual: NameInfo.Qualified => underlying.derived(qual.map(_ ++ other)) case _ => (underlying ++ other).derived(info) } override def toString = info.mkString(underlying) @@ -310,7 +308,13 @@ object Names { def isSimple = false def asSimpleName = throw new UnsupportedOperationException(s"$debugString is not a simple name") def toSimpleName = termName(toString) - def mapSimpleCore(f: SimpleTermName => Name) = underlying.mapSimpleCore(f).derived(info) + + def rewrite(f: PartialFunction[Name, Name]): ThisName = + if (f.isDefinedAt(this)) likeKinded(f(this)) + else info match { + case qual: NameInfo.Qualified => this + case _ => underlying.rewrite(f).derived(info) + } } // Nametable @@ -470,7 +474,6 @@ object Names { def seq: WrappedString = new WrappedString(name.toString) override protected[this] def thisCollection: WrappedString = seq def indexOfSlice(name: Name): Int = indexOfSlice(name.toString) - def lastIndexOfSlice(name: Name): Int = lastIndexOfSlice(name.toString) def containsSlice(name: Name): Boolean = containsSlice(name.toString) } diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 56f8ca189..9e05d4bce 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -15,6 +15,11 @@ object StdNames { /** Base strings from which synthetic names are derived. */ + object str { + val EXPAND_SEPARATOR = "$$" + val TRAIT_SETTER_SEPARATOR = "$_setter_$" + } + abstract class DefinedNames[N <: Name] { protected implicit def fromString(s: String): N protected def fromName(name: Name): N = fromString(name.toString) @@ -99,7 +104,7 @@ object StdNames { val EVIDENCE_PARAM_PREFIX: N = "evidence$" val DEP_PARAM_PREFIX = "<param>" val EXCEPTION_RESULT_PREFIX: N = "exceptionResult" - val EXPAND_SEPARATOR: N = "$$" + val EXPAND_SEPARATOR: N = str.EXPAND_SEPARATOR val IMPL_CLASS_SUFFIX: N = "$class" val IMPORT: N = "<import>" val INLINE_ACCESSOR_PREFIX = "$inlineAccessor$" @@ -129,7 +134,7 @@ object StdNames { val INITIALIZER_PREFIX: N = "initial$" val COMPANION_MODULE_METHOD: N = "companion$module" val COMPANION_CLASS_METHOD: N = "companion$class" - val TRAIT_SETTER_SEPARATOR: N = "$_setter_$" + val TRAIT_SETTER_SEPARATOR: N = str.TRAIT_SETTER_SEPARATOR val DIRECT_SUFFIX: N = "$direct" val LAZY_IMPLICIT_PREFIX: N = "$lazy_implicit$" val DOLLAR_VALUES: N = "$values" diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index f671ab557..74505d811 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -411,11 +411,13 @@ object SymDenotations { } var prefix = encl.fullNameSeparated(separator) val fn = - if (Config.semanticNames) { + if (Config.semanticNames && NameInfo.qualifier.contains(sep)) { if (sep == "$") // duplicate scalac's behavior: don't write a double '$$' for module class members. prefix = prefix.exclude(NameInfo.ModuleClassKind) - name.mapSimpleCore(prefix.select(_, sep)) + name rewrite { + case n: SimpleTermName => prefix.derived(NameInfo.qualifier(sep)(n)) + } } else { if (owner.is(ModuleClass, butNot = Package) && sep == "$") diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index f1f03dd3c..7ac505a20 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala @@ -29,8 +29,13 @@ class NameBuffer extends TastyBuffer(10000) { val tname = name.toTermName match { case DerivedTermName(name1, NameInfo.ModuleClass) => ModuleClass(nameIndex(name1, toTasty)) - case DerivedTermName(prefix, NameInfo.Qualified(selector, ".")) => - Qualified(nameIndex(prefix, toTasty), nameIndex(selector)) + case DerivedTermName(prefix, qual: NameInfo.Qualified) => + val tcon: (NameRef, NameRef) => TastyName = qual match { + case _: NameInfo.Select => Qualified + case _: NameInfo.Flatten => Flattened + case _: NameInfo.Expand => Expanded + } + tcon(nameIndex(prefix, toTasty), nameIndex(qual.name)) case name1 => if (name1.isShadowedName) Shadowed(nameIndex(name1.revertShadowed, toTasty)) else toTasty(name1.asSimpleName) @@ -72,14 +77,17 @@ class NameBuffer extends TastyBuffer(10000) { case Qualified(qualified, selector) => writeByte(QUALIFIED) withLength { writeNameRef(qualified); writeNameRef(selector) } + case Flattened(qualified, selector) => + writeByte(FLATTENED) + withLength { writeNameRef(qualified); writeNameRef(selector) } + case Expanded(prefix, original) => + writeByte(EXPANDED) + withLength { writeNameRef(prefix); writeNameRef(original) } case Signed(original, params, result) => writeByte(SIGNED) withLength( { writeNameRef(original); writeNameRef(result); params.foreach(writeNameRef) }, if ((params.length + 2) * maxIndexWidth <= maxNumInByte) 1 else 2) - case Expanded(prefix, original) => - writeByte(EXPANDED) - withLength { writeNameRef(prefix); writeNameRef(original) } case ModuleClass(module) => writeByte(OBJECTCLASS) withLength { writeNameRef(module) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 8b2255e94..848b7995f 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -222,12 +222,13 @@ object TastyFormat { final val UTF8 = 1 final val QUALIFIED = 2 - final val SIGNED = 3 + final val FLATTENED = 3 final val EXPANDED = 4 - final val OBJECTCLASS = 5 - final val SUPERACCESSOR = 6 - final val DEFAULTGETTER = 7 - final val SHADOWED = 8 + final val SIGNED = 5 + final val OBJECTCLASS = 6 + final val SUPERACCESSOR = 7 + final val DEFAULTGETTER = 8 + final val SHADOWED = 9 // AST tags diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala index da205542e..67b08a1c1 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala @@ -14,8 +14,9 @@ object 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 + case class Flattened(prefix: NameRef, original: NameRef) extends TastyName + case class Signed(original: NameRef, params: List[NameRef], result: NameRef) extends TastyName case class ModuleClass(module: NameRef) extends TastyName case class SuperAccessor(accessed: NameRef) extends TastyName case class DefaultGetter(method: NameRef, num: Int) extends TastyName diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala index 8a1f58acd..c8c1878bc 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala @@ -45,13 +45,15 @@ class TastyUnpickler(reader: TastyReader) { Simple(termName(bytes, start.index, length)) case QUALIFIED => Qualified(readNameRef(), readNameRef()) + case FLATTENED => + Flattened(readNameRef(), readNameRef()) + case EXPANDED => + Expanded(readNameRef(), readNameRef()) case SIGNED => val original = readNameRef() val result = readNameRef() val params = until(end)(readNameRef()) Signed(original, params, result) - case EXPANDED => - Expanded(readNameRef(), readNameRef()) case OBJECTCLASS => ModuleClass(readNameRef()) case SUPERACCESSOR => diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index a186d1ce4..06165c6f4 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -15,6 +15,7 @@ import scala.collection.mutable.ListBuffer import scala.collection.{ mutable, immutable } import config.Printers.pickling import typer.Checking +import config.Config /** Unpickler for typed trees * @param reader the reader from which to unpickle @@ -76,15 +77,25 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle def toTermName(tname: TastyName): TermName = tname match { case Simple(name) => name - case Qualified(qual, name) => toTermName(qual) ++ "." ++ toTermName(name) + case Qualified(qual, name) => + if (Config.semanticNames) qualTermName(qual, name, ".") + else toTermName(qual) ++ "." ++ toTermName(name) + case Flattened(qual, name) => + if (Config.semanticNames) qualTermName(qual, name, "$") + else toTermName(qual) ++ "$" ++ toTermName(name) + case Expanded(prefix, original) => + if (Config.semanticNames) qualTermName(prefix, original, str.EXPAND_SEPARATOR) + else toTermName(original).expandedName(toTermName(prefix)) case Signed(original, params, result) => toTermName(original) case Shadowed(original) => toTermName(original).shadowedName - case Expanded(prefix, original) => toTermName(original).expandedName(toTermName(prefix)) case ModuleClass(original) => toTermName(original).moduleClassName.toTermName case SuperAccessor(accessed) => toTermName(accessed).superName case DefaultGetter(meth, num) => ??? } + private def qualTermName(qual: NameRef, name: NameRef, sep: String) = + toTermName(qual).derived(NameInfo.qualifier(sep)(toTermName(name).asSimpleName)) + def toTermName(ref: NameRef): TermName = toTermName(tastyName(ref)) def toTypeName(ref: NameRef): TypeName = toTermName(ref).toTypeName |