From c27cbd16e6fd3cc00e603aebef95f477684b3390 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 23 Mar 2017 17:14:39 +0100 Subject: Bug fixes nameddefaults.scala now compiles without crashing --- .../dotty/tools/dotc/config/ScalaSettings.scala | 2 +- .../src/dotty/tools/dotc/core/Denotations.scala | 43 +++++++++------ compiler/src/dotty/tools/dotc/core/NameInfos.scala | 4 +- compiler/src/dotty/tools/dotc/core/NameOps.scala | 12 ++--- compiler/src/dotty/tools/dotc/core/Names.scala | 61 +++++++++++++++++----- .../src/dotty/tools/dotc/core/SymDenotations.scala | 17 ++---- .../dotty/tools/dotc/core/tasty/NameBuffer.scala | 30 +++++++---- .../dotty/tools/dotc/core/tasty/TreePickler.scala | 2 +- .../src/dotty/tools/dotc/parsing/Scanners.scala | 2 +- compiler/src/dotty/tools/dotc/parsing/Tokens.scala | 2 +- .../dotty/tools/dotc/printing/RefinedPrinter.scala | 3 +- compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 +- 12 files changed, 115 insertions(+), 65 deletions(-) (limited to 'compiler/src/dotty/tools') diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 49b64d869..63c3d5f74 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -65,9 +65,9 @@ class ScalaSettings extends Settings.SettingGroup { val YcheckMods = BooleanSetting("-Ycheck-mods", "Check that symbols and their defining trees have modifiers in sync") val debug = BooleanSetting("-Ydebug", "Increase the quantity of debugging output.") val debugAlias = BooleanSetting("-Ydebug-alias", "Never follow alias when printing types") - val debugNames = BooleanSetting("-YdebugNames", "Show name-space indicators when printing names") val debugTrace = BooleanSetting("-Ydebug-trace", "Trace core operations") val debugFlags = BooleanSetting("-Ydebug-flags", "Print all flags of definitions") + val debugNames = BooleanSetting("-Ydebug-names", "Show internal representation of names") val debugOwners = BooleanSetting("-Ydebug-owners", "Print all owners of definitions (requires -Yprint-syms)") val termConflict = ChoiceSetting("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error") val log = PhasesSetting("-Ylog", "Log operations during") diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 7341b96af..a679cad6f 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -4,8 +4,8 @@ package core import SymDenotations.{ SymDenotation, ClassDenotation, NoDenotation } import Contexts.{Context, ContextBase} -import Names.{Name, PreName} -import Names.TypeName +import Names._ +import NameOps._ import StdNames._ import Symbols.NoSymbol import Symbols._ @@ -1171,27 +1171,40 @@ object Denotations { * if generateStubs is set, generates stubs for missing top-level symbols */ def staticRef(path: Name, generateStubs: Boolean = true)(implicit ctx: Context): Denotation = { - def recur(path: Name, len: Int): Denotation = { - val point = path.lastIndexOf('.', len - 1) - val owner = - if (point > 0) recur(path.toTermName, point).disambiguate(_.info.isParameterless) - else if (path.isTermName) defn.RootClass.denot - else defn.EmptyPackageClass.denot + def select(prefix: Denotation, selector: Name): Denotation = { + val owner = prefix.disambiguate(_.info.isParameterless) if (owner.exists) { - val name = path slice (point + 1, len) - val result = owner.info.member(name) - if (result ne NoDenotation) result + val result = owner.info.member(selector) + if (result.exists) result else { val alt = - if (generateStubs) missingHook(owner.symbol.moduleClass, name) + if (generateStubs) missingHook(owner.symbol.moduleClass, selector) else NoSymbol - if (alt.exists) alt.denot - else MissingRef(owner, name) + if (alt.exists) alt.denot else MissingRef(owner, selector) } } else owner } - recur(path, path.length) + def recur(path: Name, wrap: Name => Name = identity): Denotation = path match { + case path: TypeName => + 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, ".")) => + select(recur(prefix), wrap(selector)) + case path: SimpleTermName => + def recurSimple(len: Int, wrap: Name => Name): Denotation = { + val point = path.lastIndexOf('.', len - 1) + val selector = wrap(path.slice(point + 1, len)) + val prefix = + if (point > 0) recurSimple(point, identity) + else if (selector.isTermName) defn.RootClass.denot + else defn.EmptyPackageClass.denot + select(prefix, selector) + } + recurSimple(path.length, wrap) + } + recur(path.unmangleClassName) } /** If we are looking for a non-existing term name in a package, diff --git a/compiler/src/dotty/tools/dotc/core/NameInfos.scala b/compiler/src/dotty/tools/dotc/core/NameInfos.scala index 031ca8f6e..b49a0979e 100644 --- a/compiler/src/dotty/tools/dotc/core/NameInfos.scala +++ b/compiler/src/dotty/tools/dotc/core/NameInfos.scala @@ -10,7 +10,7 @@ abstract class NameInfo extends util.DotClass { def kind: NameInfo.Kind def mkString(underlying: TermName): String def map(f: SimpleTermName => SimpleTermName): NameInfo = this - def contains(ch: Char): Boolean = false + def satisfies(p: SimpleTermName => Boolean): Boolean = false def ++(other: String): NameInfo = unsupported("++") } @@ -34,7 +34,7 @@ object NameInfo { def kind = QualifiedKind def mkString(underlying: TermName) = s"$underlying$separator$name" override def map(f: SimpleTermName => SimpleTermName): NameInfo = Qualified(f(name), separator) - override def contains(ch: Char): Boolean = name.contains(ch) + override def satisfies(p: SimpleTermName => Boolean): Boolean = p(name) 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 27065a50a..f49c82ee4 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -70,8 +70,8 @@ object NameOps { def isLocalDummyName = name startsWith LOCALDUMMY_PREFIX def isLoopHeaderLabel = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX) def isProtectedAccessorName = name startsWith PROTECTED_PREFIX - def isReplWrapperName = name containsSlice INTERPRETER_IMPORT_WRAPPER - def isTraitSetterName = name containsSlice TRAIT_SETTER_SEPARATOR + def isReplWrapperName = name.toSimpleName containsSlice INTERPRETER_IMPORT_WRAPPER + def isTraitSetterName = name.toSimpleName containsSlice TRAIT_SETTER_SEPARATOR def isSetterName = name endsWith SETTER_SUFFIX def isSingletonName = name endsWith SINGLETON_SUFFIX def isModuleClassName = @@ -80,7 +80,7 @@ object NameOps { def isAvoidClashName = name endsWith AVOID_CLASH_SUFFIX def isImportName = name startsWith IMPORT def isFieldName = name endsWith LOCAL_SUFFIX - def isShadowedName = name.length > 0 && name.head == '(' && name.startsWith(nme.SHADOWED) + def isShadowedName = name.startsWith(nme.SHADOWED) def isDefaultGetterName = name.isTermName && name.asTermName.defaultGetterIndex >= 0 def isScala2LocalSuffix = name.endsWith(" ") def isModuleVarName(name: Name): Boolean = @@ -162,7 +162,7 @@ object NameOps { /** The expanded name of `name` relative to `basename` with given `separator` */ def expandedName(prefix: Name, separator: Name = nme.EXPAND_SEPARATOR): N = - name.fromName(prefix ++ separator ++ name).asInstanceOf[N] + name.likeKinded(prefix ++ separator ++ name).asInstanceOf[N] def expandedName(prefix: Name): N = expandedName(prefix, nme.EXPAND_SEPARATOR) @@ -230,7 +230,7 @@ object NameOps { */ def unmangleClassName: N = - if (Config.semanticNames) + if (Config.semanticNames && name.isSimple && name.isTypeName) if (name.endsWith(MODULE_SUFFIX)) likeTyped(name.dropRight(MODULE_SUFFIX.length).moduleClassName) else name @@ -353,7 +353,7 @@ object NameOps { val methodTags: Seq[Name] = (methodTargs zip methodTarsNames).sortBy(_._2).map(x => typeToTag(x._1)) val classTags: Seq[Name] = (classTargs zip classTargsNames).sortBy(_._2).map(x => typeToTag(x._1)) - name.fromName(name ++ nme.specializedTypeNames.prefix ++ + name.likeKinded(name ++ nme.specializedTypeNames.prefix ++ methodTags.fold(nme.EMPTY)(_ ++ _) ++ nme.specializedTypeNames.separator ++ classTags.fold(nme.EMPTY)(_ ++ _) ++ nme.specializedTypeNames.suffix) } diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index e9dbd7f7c..9730adb59 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -62,10 +62,13 @@ object Names { /** This name downcasted to a term name */ def asTermName: TermName - def toSimpleName: SimpleTermName = this.asInstanceOf[SimpleTermName] + def isSimple: Boolean + def asSimpleName: SimpleTermName + def toSimpleName: SimpleTermName + def mapSimpleCore(f: SimpleTermName => Name): ThisName /** A name of the same kind as this name and with same characters as given `name` */ - def fromName(name: Name): ThisName + def likeKinded(name: Name): ThisName def derived(info: NameInfo): ThisName def without(kind: NameInfo.Kind): ThisName @@ -84,10 +87,14 @@ object Names { def ++ (other: Name): ThisName = ++ (other.toString) def ++ (other: String): ThisName - def replace(from: Char, to: Char): ThisName = fromName(toSimpleName.replace(from, to)) + def replace(from: Char, to: Char): ThisName = likeKinded(asSimpleName.replace(from, to)) + def isEmpty: Boolean def startsWith(str: String): Boolean def startsWith(name: Name): Boolean = startsWith(name.toString) + def endsWith(str: String): Boolean + def endsWith(name: Name): Boolean = endsWith(name.toString) + override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] } @@ -112,7 +119,7 @@ object Names { _typeName } - def fromName(name: Name): TermName = name.toTermName + def likeKinded(name: Name): TermName = name.toTermName def info = NameInfo.TermName def underlying: TermName = unsupported("underlying") @@ -178,6 +185,9 @@ object Names { ownKind == kind || !NameInfo.definesNewName(ownKind) && ownKind > kind && underlying.is(kind) } + + override def hashCode = System.identityHashCode(this) + override def equals(other: Any) = this eq other.asInstanceOf[AnyRef] } class SimpleTermName(val start: Int, val length: Int, @sharable private[Names] var next: SimpleTermName) extends TermName { @@ -193,21 +203,34 @@ object Names { i < length } + def isEmpty = length == 0 + def startsWith(str: String): Boolean = { var i = 0 while (i < str.length && i < length && apply(i) == str(i)) i += 1 i == str.length } + def endsWith(str: String): Boolean = { + var i = 1 + while (i <= str.length && i <= length && apply(length - i) == str(str.length - i)) i += 1 + i > str.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)) + likeKinded(termName(cs, 0, length)) } + def isSimple = true + def asSimpleName = this + def toSimpleName = this + def mapSimpleCore(f: SimpleTermName => Name): TermName = likeKinded(f(this)) + def encode: SimpleTermName = if (dontEncode(toTermName)) this else NameTransformer.encode(this) @@ -225,14 +248,14 @@ object Names { class TypeName(val toTermName: TermName) extends Name { - override def toSimpleName: SimpleTermName = toTermName.toSimpleName - def ++ (other: String): ThisName = toTermName.++(other).toTypeName + def isEmpty = toTermName.isEmpty def startsWith(str: String): Boolean = toTermName.startsWith(str) + def endsWith(str: String): Boolean = toTermName.endsWith(str) - def encode: Name = toTermName.encode - def decode: Name = toTermName.decode + def encode: Name = toTermName.encode.toTypeName + def decode: Name = toTermName.decode.toTypeName type ThisName = TypeName def isTypeName = true @@ -241,7 +264,12 @@ object Names { def asTypeName = this def asTermName = throw new ClassCastException(this + " is not a term name") - def fromName(name: Name): TypeName = name.toTypeName + def isSimple = toTermName.isSimple + def asSimpleName = toTermName.asSimpleName + def toSimpleName = toTermName.toSimpleName + def mapSimpleCore(f: SimpleTermName => Name): TypeName = toTermName.mapSimpleCore(f).toTypeName + + def likeKinded(name: Name): TypeName = name.toTypeName def derived(info: NameInfo): TypeName = toTermName.derived(info).toTypeName def without(kind: NameInfo.Kind): TypeName = toTermName.without(kind).toTypeName @@ -254,14 +282,21 @@ object Names { /** A term name that's derived from an `underlying` name and that * adds `info` to it. */ - class DerivedTermName(override val underlying: TermName, override val info: NameInfo) + case class DerivedTermName(override val underlying: TermName, override val info: NameInfo) extends TermName { def ++ (other: String): ThisName = derived(info ++ other) + def isEmpty = false def startsWith(str: String): Boolean = underlying.startsWith(str) + def endsWith(str: String): Boolean = info.satisfies(_.endsWith(str)) def encode: Name = underlying.encode.derived(info.map(_.encode)) def decode: Name = underlying.decode.derived(info.map(_.decode)) override def toString = info.mkString(underlying) override def debugString = s"${underlying.debugString}[$info]" + + 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) } // Nametable @@ -413,8 +448,8 @@ object Names { 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) + def length = name.asSimpleName.length + def apply(n: Int) = name.asSimpleName.apply(n) override protected[this] def newBuilder: Builder[Char, Name] = if (name.isTypeName) typeNameBuilder else termNameBuilder diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 070fdf345..3f8eda625 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -392,7 +392,7 @@ object SymDenotations { * A separator "" means "flat name"; the real separator in this case is "$" and * enclosing packages do not form part of the name. */ - def fullNameSeparated(separator: String, semantic: Boolean)(implicit ctx: Context): Name = { + def fullNameSeparated(separator: String)(implicit ctx: Context): Name = { var sep = separator var stopAtPackage = false if (sep.isEmpty) { @@ -409,13 +409,13 @@ object SymDenotations { encl = encl.owner sep += "~" } - var prefix = encl.fullNameSeparated(separator, semantic) + var prefix = encl.fullNameSeparated(separator) val fn = - if (semantic) { + if (Config.semanticNames) { if (sep == "$") // duplicate scalac's behavior: don't write a double '$$' for module class members. prefix = prefix.without(NameInfo.ModuleClassKind) - prefix.derived(NameInfo.Qualified(name.toSimpleName, sep)) + name.mapSimpleCore(sn => prefix.derived(NameInfo.Qualified(sn, sep))) } else { if (owner.is(ModuleClass, butNot = Package) && sep == "$") @@ -427,15 +427,6 @@ object SymDenotations { } } - def fullNameSeparated(separator: String)(implicit ctx: Context): Name = - if (Config.semanticNames) { - val fn1 = fullNameSeparated(separator, false) - val fn2 = fullNameSeparated(separator, true) - assert(fn1.toString == fn2.toString, s"mismatch, was: $fn1, sem: $fn2") - fn2 - } - else fullNameSeparated(separator, false) - /** The encoded flat name of this denotation, where joined names are separated by `separator` characters. */ def flatName(implicit ctx: Context): Name = fullNameSeparated("") diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index b05e6ef21..f1f03dd3c 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala @@ -4,7 +4,7 @@ package core package tasty import collection.mutable -import Names.{Name, chrs} +import Names.{Name, chrs, DerivedTermName, SimpleTermName} import Decorators._, NameOps._ import TastyBuffer._ import scala.io.Codec @@ -24,21 +24,31 @@ class NameBuffer extends TastyBuffer(10000) { nameRefs(name) = ref ref } - def nameIndex(name: Name): NameRef = { - val tname = - if (name.isShadowedName) Shadowed(nameIndex(name.revertShadowed)) - else Simple(name.toTermName.toSimpleName) + + def nameIndex(name: Name, toTasty: SimpleTermName => TastyName): NameRef = { + 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 name1 => + if (name1.isShadowedName) Shadowed(nameIndex(name1.revertShadowed, toTasty)) + else toTasty(name1.asSimpleName) + } nameIndex(tname) } + def nameIndex(name: Name): NameRef = nameIndex(name, Simple) + def nameIndex(str: String): NameRef = nameIndex(str.toTermName) def fullNameIndex(name: Name): NameRef = { - val pos = name.lastIndexOf('.') - if (pos > 0) - nameIndex(Qualified(fullNameIndex(name.take(pos)), nameIndex(name.drop(pos + 1)))) - else - nameIndex(name) + def split(name: SimpleTermName): TastyName = { + val pos = name.lastIndexOf('.') + if (pos <= 0) Simple(name) + else Qualified(fullNameIndex(name.take(pos)), nameIndex(name.drop(pos + 1))) + } + nameIndex(name, split) } private def withLength(op: => Unit, lengthWidth: Int = 1): Unit = { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 7a6b6b7ea..78d59c99f 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.toSimpleName) + if (sym.isRoot || sym.owner.isRoot) TastyName.Simple(sym.name.toTermName.asSimpleName) 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 bcf6eb4a5..3084c30a8 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.toSimpleName.start + val idx = target.name.asSimpleName.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 96ae25c9e..770b826fd 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.toSimpleName.start + def start(tok: Token) = tokenString(tok).toTermName.asSimpleName.start def sourceKeywords = keywords.toList.filter { (kw: Token) => val ts = tokenString(kw) (ts != null) && !ts.contains(' ') diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 0b683d90c..798a1c854 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -58,7 +58,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { protected val PrintableFlags = (SourceModifierFlags | Label | Module | Local).toCommonFlags - override def nameString(name: Name): String = name.decode.toString + override def nameString(name: Name): String = + if (ctx.settings.debugNames.value) name.debugString else name.decode.toString override protected def simpleNameString(sym: Symbol): String = { val name = if (ctx.property(XprintMode).isEmpty) sym.originalName else sym.name diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index b436b36b0..78a1cd9c3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -281,7 +281,7 @@ class Namer { typer: Typer => tree match { case tree: TypeDef if tree.isClassDef => - val name = checkNoConflict(tree.name.encode).asTypeName + val name = checkNoConflict(tree.name.encode).toTypeName val flags = checkFlags(tree.mods.flags &~ Implicit) val cls = recordSym(ctx.newClassSymbol( ctx.owner, name, flags | inSuperCall, -- cgit v1.2.3