From efb5fa4fb946db7a2543ac60b613117828a92990 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 21 Mar 2017 11:51:21 +0100 Subject: [PATCH 01/68] Cleanup of simple names Reduce # of creation methods and make TypeNames simple derived names from TermNames. --- .../src/dotty/tools/dotc/core/Names.scala | 84 +++++++++---------- 1 file changed, 39 insertions(+), 45 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 11f0b55a8dbe..6f970aae14eb 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -46,10 +46,10 @@ object Names { type ThisName <: Name /** The start index in the character array */ - val start: Int + def start: Int /** The length of the names */ - override val length: Int + override def length: Int /** Is this name a type name? */ def isTypeName: Boolean @@ -69,23 +69,8 @@ object Names { /** This name downcasted to a term name */ def asTermName: TermName - /** Create a new name of same kind as this one, in the given - * basis, with `len` characters taken from `cs` starting at `offset`. - */ - def fromChars(cs: Array[Char], offset: Int, len: Int): ThisName - - /** Create new name of same kind as this name and with same - * characters as given `name`. - */ - def fromName(name: Name): ThisName = fromChars(chrs, name.start, name.length) - - /** Create new name of same kind as this name with characters from - * the given string - */ - def fromString(str: String): ThisName = { - val cs = str.toCharArray - fromChars(cs, 0, cs.length) - } + /** A name of the same kind as this name and with same characters as given `name` */ + def fromName(name: Name): ThisName override def toString = if (length == 0) "" else new String(chrs, start, length) @@ -105,7 +90,7 @@ object Names { /** Replace \$op_name's by corresponding operator symbols. */ def decode: Name = - if (contains('$')) fromString(NameTransformer.decode(toString)) + if (contains('$')) fromName(termName(NameTransformer.decode(toString))) else this /** Replace operator symbols by corresponding \$op_name's. */ @@ -115,10 +100,7 @@ object Names { /** A more efficient version of concatenation */ def ++ (other: Name): ThisName = ++ (other.toString) - def ++ (other: String): ThisName = { - val s = toString + other - fromChars(s.toCharArray, 0, s.length) - } + def ++ (other: String): ThisName = fromName(termName(toString + other)) def replace(from: Char, to: Char): ThisName = { val cs = new Array[Char](length) @@ -126,7 +108,7 @@ object Names { for (i <- 0 until length) { if (cs(i) == from) cs(i) = to } - fromChars(cs, 0, length) + fromName(termName(cs, 0, length)) } def contains(ch: Char): Boolean = { @@ -147,18 +129,20 @@ object Names { override def apply(index: Int): Char = chrs(start + index) override def slice(from: Int, until: Int): ThisName = - fromChars(chrs, start + from, until - from) + fromName(termName(chrs, start + from, until - from)) override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] override def seq = toCollection(this) } - class TermName(val start: Int, val length: Int, @sharable private[Names] var next: TermName) extends Name { - // `next` is @sharable because it is only modified in the synchronized block of termName. + abstract class TermName extends Name { type ThisName = TermName def isTypeName = false def isTermName = true + def toTermName = this + def asTypeName = throw new ClassCastException(this + " is not a type name") + def asTermName = this @sharable // because it is only modified in the synchronized block of toTypeName. @volatile private[this] var _typeName: TypeName = null @@ -167,22 +151,31 @@ object Names { if (_typeName == null) synchronized { if (_typeName == null) - _typeName = new TypeName(start, length, this) + _typeName = new TypeName(this) } _typeName } - def toTermName = this - def asTypeName = throw new ClassCastException(this + " is not a type name") - def asTermName = this + + def fromName(name: Name): TermName = name.toTermName override def hashCode: Int = start 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 fromChars(cs: Array[Char], offset: Int, len: Int): TermName = termName(cs, offset, len) + abstract class DerivedName extends Name { + def underlying: Name + def start = underlying.start + override def length = underlying.length } - class TypeName(val start: Int, val length: Int, val toTermName: TermName) extends Name { + class TypeName(val toTermName: TermName) extends DerivedName { + def underlying = toTermName + type ThisName = TypeName def isTypeName = true def isTermName = false @@ -190,12 +183,12 @@ object Names { def asTypeName = this def asTermName = throw new ClassCastException(this + " is not a term name") + def fromName(name: Name): TypeName = name.toTypeName + override def hashCode: Int = -start override protected[this] def newBuilder: Builder[Char, Name] = termNameBuilder.mapResult(_.toTypeName) - - def fromChars(cs: Array[Char], offset: Int, len: Int): TypeName = typeName(cs, offset, len) } // Nametable @@ -214,7 +207,7 @@ object Names { /** Hashtable for finding term names quickly. */ @sharable // because it's only mutated in synchronized block of termName - private var table = new Array[TermName](InitialHashSize) + private var table = new Array[SimpleTermName](InitialHashSize) /** The number of defined names. */ @sharable // because it's only mutated in synchronized block of termName @@ -266,7 +259,7 @@ object Names { } /** Rehash chain of names */ - def rehash(name: TermName): Unit = + def rehash(name: SimpleTermName): Unit = if (name != null) { val oldNext = name.next val h = hashValue(chrs, name.start, name.length) & (table.size - 1) @@ -280,7 +273,7 @@ object Names { size += 1 if (size.toDouble / table.size > fillFactor) { val oldTable = table - table = new Array[TermName](table.size * 2) + table = new Array[SimpleTermName](table.size * 2) for (i <- 0 until oldTable.size) rehash(oldTable(i)) } } @@ -292,7 +285,7 @@ object Names { return name name = name.next } - name = new TermName(nc, len, next) + name = new SimpleTermName(nc, len, next) enterChars() table(h) = name incTableSize() @@ -325,10 +318,10 @@ object Names { /** Create a type name from a string, without encoding operators */ def typeName(s: String): TypeName = typeName(s.toCharArray, 0, s.length) - /** The term name represented by the empty string */ - val EmptyTermName = new TermName(-1, 0, null) + table(0) = new SimpleTermName(-1, 0, null) - table(0) = EmptyTermName + /** The term name represented by the empty string */ + val EmptyTermName: TermName = table(0) /** The type name represented by the empty string */ val EmptyTypeName = EmptyTermName.toTypeName @@ -338,14 +331,15 @@ object Names { val STATIC_CONSTRUCTOR = termName("") val EMPTY_PACKAGE = termName("") - val dontEncode = Set(CONSTRUCTOR, EMPTY_PACKAGE) + 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.fromChars(s.toCharArray, 0, s.length)) + StringBuilder.newBuilder.mapResult(s => + from.fromName(termName(s.toCharArray, 0, s.length))) def apply(): Builder[Char, Name] = termNameBuilder } From f827882850754ba7862a1ff1615d78b350cf56cb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 21 Mar 2017 14:47:59 +0100 Subject: [PATCH 02/68] Add derived name machinery Add machinery to define and hash cons derived names. --- .../src/dotty/tools/dotc/core/NameInfos.scala | 39 +++++++++ .../src/dotty/tools/dotc/core/NameOps.scala | 1 - .../src/dotty/tools/dotc/core/Names.scala | 85 ++++++++++++++++--- 3 files changed, 114 insertions(+), 11 deletions(-) create mode 100644 compiler/src/dotty/tools/dotc/core/NameInfos.scala diff --git a/compiler/src/dotty/tools/dotc/core/NameInfos.scala b/compiler/src/dotty/tools/dotc/core/NameInfos.scala new file mode 100644 index 000000000000..4bbc5bbcfc42 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/core/NameInfos.scala @@ -0,0 +1,39 @@ +package dotty.tools.dotc +package core + +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 { + def kind: NameInfo.Kind + def oneOfAKind = true + def mkString(underlying: TermName): String +} + +object NameInfo { + + type Kind = Int + + val TermNameKind = 0 + val QualifiedKind = 1 + + /** TermNames have the lowest possible kind */ + val TermName = new NameInfo { + def kind = 0 + def mkString(underlying: TermName) = underlying.toString // will cause an unsupptored exception + } + + case class Qualified(name: TermName) extends NameInfo { + def kind = 1 + override def oneOfAKind = false + def mkString(underlying: TermName) = s"$underlying.$name" + } + + val ModuleClass = new NameInfo { + def kind = 10 + def mkString(underlying: TermName) = underlying + "$" + } + +} \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 240ad359bba1..a6e5fefc7d4e 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -65,7 +65,6 @@ object NameOps { def isConstructorName = name == CONSTRUCTOR || name == TRAIT_CONSTRUCTOR def isStaticConstructorName = name == STATIC_CONSTRUCTOR - def isExceptionResultName = name startsWith EXCEPTION_RESULT_PREFIX def isImplClassName = name endsWith IMPL_CLASS_SUFFIX def isLocalDummyName = name startsWith LOCALDUMMY_PREFIX def isLoopHeaderLabel = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 6f970aae14eb..74e1fd2d2d02 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -10,10 +10,12 @@ import Decorators._ import Contexts.Context import collection.IndexedSeqOptimized import collection.generic.CanBuildFrom -import collection.mutable.{ Builder, StringBuilder } +import collection.mutable.{ Builder, StringBuilder, AnyRefMap } import collection.immutable.WrappedString import collection.generic.CanBuildFrom -import util.DotClass +import util.{DotClass, SimpleMap} +import java.util.HashMap + //import annotation.volatile object Names { @@ -158,6 +160,64 @@ object Names { def fromName(name: Name): TermName = name.toTermName + def info = NameInfo.TermName + def underlying: TermName = unsupported("underlying") + + private var derivedNames: AnyRef /* SimpleMap | j.u.HashMap */ = + SimpleMap.Empty[NameInfo] + + private def getDerived(info: NameInfo): DerivedTermName /* | Null */= derivedNames match { + case derivedNames: SimpleMap[NameInfo, DerivedTermName] @unchecked => + derivedNames(info) + case derivedNames: HashMap[NameInfo, DerivedTermName] @unchecked => + derivedNames.get(info) + } + + private def putDerived(info: NameInfo, name: DerivedTermName): name.type = { + derivedNames match { + case derivedNames: SimpleMap[NameInfo, DerivedTermName] @unchecked => + if (derivedNames.size < 4) + this.derivedNames = derivedNames.updated(info, name) + else { + val newMap = new HashMap[NameInfo, DerivedTermName] + derivedNames.foreachBinding(newMap.put(_, _)) + newMap.put(info, name) + this.derivedNames = newMap + } + case derivedNames: HashMap[NameInfo, DerivedTermName] @unchecked => + derivedNames.put(info, name) + } + name + } + + /** Return derived name with given `info` and the current + * name as underlying name. + */ + def derived(info: NameInfo): TermName = { + def addIt() = synchronized { + getDerived(info) match { + case null => putDerived(info, new DerivedTermName(this, info)) + case derivedName => derivedName + } + } + + val ownKind = this.info.kind + if (ownKind > info.kind) + underlying.derived(info).derived(this.info) + else if (ownKind == info.kind) + if (info.oneOfAKind) { + assert(info == this.info) + this + } + else addIt() + else addIt() + } + + def is(kind: NameInfo.Kind): Boolean = { + val ownKind = info.kind + ownKind == kind || ownKind > kind && underlying.is(kind) + } + override def hashCode: Int = start override protected[this] def newBuilder: Builder[Char, Name] = termNameBuilder @@ -167,14 +227,9 @@ object Names { // `next` is @sharable because it is only modified in the synchronized block of termName. } - abstract class DerivedName extends Name { - def underlying: Name - def start = underlying.start - override def length = underlying.length - } - - class TypeName(val toTermName: TermName) extends DerivedName { - def underlying = toTermName + class TypeName(val toTermName: TermName) extends Name { + def start = toTermName.start + override def length = toTermName.length type ThisName = TypeName def isTypeName = true @@ -191,6 +246,16 @@ object Names { termNameBuilder.mapResult(_.toTypeName) } + /** 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) + extends TermName { + def start = underlying.start + override def length = underlying.length + override def toString = info.mkString(underlying) + } + // Nametable private final val InitialHashSize = 0x8000 From 8144ac29420f18fc4a60690ac33d6247cb87a40c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 21 Mar 2017 15:17:53 +0100 Subject: [PATCH 03/68] Fix @sharable problem --- compiler/src/dotty/tools/dotc/core/Names.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 74e1fd2d2d02..3c867c7548d1 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -163,7 +163,7 @@ object Names { def info = NameInfo.TermName def underlying: TermName = unsupported("underlying") - private var derivedNames: AnyRef /* SimpleMap | j.u.HashMap */ = + @sharable private var derivedNames: AnyRef /* SimpleMap | j.u.HashMap */ = SimpleMap.Empty[NameInfo] private def getDerived(info: NameInfo): DerivedTermName /* | Null */= derivedNames match { From 01d9659e21a149801fd8ced6652cc0e94f4827e2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Mar 2017 11:17:33 +0100 Subject: [PATCH 04/68] Fix handling of qualified names These always construct a new name, other derivations should not commute with Qualified. --- .../src/dotty/tools/dotc/core/NameInfos.scala | 20 +++++---- .../src/dotty/tools/dotc/core/Names.scala | 41 ++++++++++++++----- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameInfos.scala b/compiler/src/dotty/tools/dotc/core/NameInfos.scala index 4bbc5bbcfc42..51c04b9e46cb 100644 --- a/compiler/src/dotty/tools/dotc/core/NameInfos.scala +++ b/compiler/src/dotty/tools/dotc/core/NameInfos.scala @@ -8,7 +8,6 @@ import Names._ */ abstract class NameInfo { def kind: NameInfo.Kind - def oneOfAKind = true def mkString(underlying: TermName): String } @@ -18,22 +17,25 @@ object NameInfo { val TermNameKind = 0 val QualifiedKind = 1 + val ModuleClassKind = 2 + + def definesNewName(kind: Kind) = kind <= QualifiedKind /** TermNames have the lowest possible kind */ val TermName = new NameInfo { - def kind = 0 - def mkString(underlying: TermName) = underlying.toString // will cause an unsupptored exception + def kind = TermNameKind + def mkString(underlying: TermName) = underlying.toString // will cause an unsupported exception } - case class Qualified(name: TermName) extends NameInfo { - def kind = 1 - override def oneOfAKind = false - def mkString(underlying: TermName) = s"$underlying.$name" + case class Qualified(name: TermName, separator: String) extends NameInfo { + def kind = QualifiedKind + def mkString(underlying: TermName) = s"$underlying$separator$name" + override def toString = s"Qualified($name, $separator)" } val ModuleClass = new NameInfo { - def kind = 10 + def kind = ModuleClassKind def mkString(underlying: TermName) = underlying + "$" + override def toString = "ModuleClass" } - } \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 3c867c7548d1..dbaa338a2f84 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -74,8 +74,10 @@ object Names { /** A name of the same kind as this name and with same characters as given `name` */ def fromName(name: Name): ThisName - override def toString = - if (length == 0) "" else new String(chrs, start, length) + def derived(info: NameInfo): ThisName + def without(kind: NameInfo.Kind): ThisName + def is(kind: NameInfo.Kind): Boolean + def debugString: String def toText(printer: Printer): Text = printer.toText(this) @@ -202,20 +204,27 @@ object Names { } val ownKind = this.info.kind - if (ownKind > info.kind) + if (NameInfo.definesNewName(info.kind)) addIt() + else if (ownKind > info.kind) underlying.derived(info).derived(this.info) - else if (ownKind == info.kind) - if (info.oneOfAKind) { - assert(info == this.info) - this - } - else addIt() + else if (ownKind == info.kind) { + assert(info == this.info) + this + } else addIt() } + def without(kind: NameInfo.Kind): TermName = { + val ownKind = info.kind + if (ownKind < kind || NameInfo.definesNewName(ownKind)) this + else if (ownKind == kind) underlying.without(kind) + else underlying.without(kind).derived(this.info) + } + def is(kind: NameInfo.Kind): Boolean = { val ownKind = info.kind - ownKind == kind || ownKind > kind && underlying.is(kind) + ownKind == kind || + !NameInfo.definesNewName(ownKind) && ownKind > kind && underlying.is(kind) } override def hashCode: Int = start @@ -225,6 +234,10 @@ object Names { 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. + override def toString = + if (length == 0) "" else new String(chrs, start, length) + + def debugString: String = toString } class TypeName(val toTermName: TermName) extends Name { @@ -240,10 +253,17 @@ object Names { def fromName(name: Name): TypeName = name.toTypeName + def derived(info: NameInfo): TypeName = toTermName.derived(info).toTypeName + def without(kind: NameInfo.Kind): TypeName = toTermName.without(kind).toTypeName + def is(kind: NameInfo.Kind) = toTermName.is(kind) + override def hashCode: Int = -start override protected[this] def newBuilder: Builder[Char, Name] = termNameBuilder.mapResult(_.toTypeName) + + override def toString = toTermName.toString + override def debugString = toTermName.debugString + "/T" } /** A term name that's derived from an `underlying` name and that @@ -254,6 +274,7 @@ object Names { def start = underlying.start override def length = underlying.length override def toString = info.mkString(underlying) + override def debugString = s"${underlying.debugString}[$info]" } // Nametable From 67105e3f36378d652aa919e23aa3b2678004bdc6 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Mar 2017 11:18:36 +0100 Subject: [PATCH 05/68] Start to use structured ModuleNames Subject to flags Config.semanticNames. --- .../src/dotty/tools/dotc/config/Config.scala | 2 ++ .../src/dotty/tools/dotc/core/NameOps.scala | 24 +++++++++++++++---- .../dotty/tools/dotc/core/SymbolLoaders.scala | 10 +++++--- .../core/unpickleScala2/Scala2Unpickler.scala | 3 ++- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index 46b1896f1add..a225b3019180 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -10,6 +10,8 @@ object Config { final val checkCacheMembersNamed = false + final val semanticNames = true + /** When updating a constraint bound, check that the constrained parameter * does not appear at the top-level of either of its bounds. */ diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index a6e5fefc7d4e..38eb21446a8f 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -9,6 +9,7 @@ import Decorators.PreNamedString import util.{Chars, NameTransformer} import Chars.isOperatorPart import Definitions._ +import config.Config object NameOps { @@ -73,7 +74,9 @@ object NameOps { def isTraitSetterName = name containsSlice TRAIT_SETTER_SEPARATOR def isSetterName = name endsWith SETTER_SUFFIX def isSingletonName = name endsWith SINGLETON_SUFFIX - def isModuleClassName = name endsWith MODULE_SUFFIX + def isModuleClassName = + if (Config.semanticNames) name.is(NameInfo.ModuleClass.kind) + else name endsWith MODULE_SUFFIX def isAvoidClashName = name endsWith AVOID_CLASH_SUFFIX def isImportName = name startsWith IMPORT def isFieldName = name endsWith LOCAL_SUFFIX @@ -119,14 +122,19 @@ object NameOps { } /** Convert this module name to corresponding module class name */ - def moduleClassName: TypeName = (name ++ tpnme.MODULE_SUFFIX).toTypeName + def moduleClassName: TypeName = + if (Config.semanticNames) name.derived(NameInfo.ModuleClass).toTypeName + else (name ++ tpnme.MODULE_SUFFIX).toTypeName /** Convert this module class name to corresponding source module name */ def sourceModuleName: TermName = stripModuleClassSuffix.toTermName /** If name ends in module class suffix, drop it */ def stripModuleClassSuffix: Name = - if (isModuleClassName) name dropRight MODULE_SUFFIX.length else name + if (isModuleClassName) + if (Config.semanticNames) name.without(NameInfo.ModuleClass.kind) + else name dropRight MODULE_SUFFIX.length + else name /** Append a suffix so that this name does not clash with another name in the same scope */ def avoidClashName: TermName = (name ++ AVOID_CLASH_SUFFIX).toTermName @@ -194,7 +202,7 @@ object NameOps { likeTyped( if (name.isModuleClassName) name.stripModuleClassSuffix.freshened.moduleClassName else likeTyped(ctx.freshName(name ++ NameTransformer.NAME_JOIN_STRING))) - +/* /** Name with variance prefix: `+` for covariant, `-` for contravariant */ def withVariance(v: Int): N = if (hasVariance) dropVariance.withVariance(v) @@ -220,6 +228,14 @@ object NameOps { case _ => 0 } +*/ + def unmangleClassName: N = + if (Config.semanticNames) + if (name.endsWith(MODULE_SUFFIX)) + likeTyped(name.dropRight(MODULE_SUFFIX.length).moduleClassName) + else name + else name + /** Translate a name into a list of simple TypeNames and TermNames. * In all segments before the last, type/term is determined by whether * the following separator char is '.' or '#'. The last segment diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 79f8a6a45d05..40e561d3ff73 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -39,7 +39,7 @@ class SymbolLoaders { def enterClass( owner: Symbol, name: PreName, completer: SymbolLoader, flags: FlagSet = EmptyFlags, scope: Scope = EmptyScope)(implicit ctx: Context): Symbol = { - val cls = ctx.newClassSymbol(owner, name.toTypeName, flags, completer, assocFile = completer.sourceFileOrNull) + val cls = ctx.newClassSymbol(owner, name.toTypeName.unmangleClassName, flags, completer, assocFile = completer.sourceFileOrNull) enterNew(owner, cls, completer, scope) } @@ -152,7 +152,7 @@ class SymbolLoaders { def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = { assert(root is PackageClass, root) - def maybeModuleClass(classRep: ClassPath#ClassRep) = classRep.name.last == '$' + def maybeModuleClass(classRep: ClassPath#ClassRep) = classRep.name.last == '$' val pre = root.owner.thisType root.info = ClassInfo(pre, root.symbol.asClass, Nil, currentDecls, pre select sourceModule) if (!sourceModule.isCompleted) @@ -162,7 +162,8 @@ class SymbolLoaders { if (!maybeModuleClass(classRep)) initializeFromClassPath(root.symbol, classRep) for (classRep <- classpath.classes) - if (maybeModuleClass(classRep) && !root.unforcedDecls.lookup(classRep.name.toTypeName).exists) + if (maybeModuleClass(classRep) && + !root.unforcedDecls.lookup(classRep.name.toTypeName.unmangleClassName).exists) initializeFromClassPath(root.symbol, classRep) } if (!root.isEmptyPackage) @@ -247,8 +248,11 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader { (module, _) => new NoCompleter() withDecls newScope withSourceModule (_ => module)) .moduleClass.denot.asClass } + val res = if (rootDenot is ModuleClass) (linkedDenot, rootDenot) else (rootDenot, linkedDenot) + println(s"root denots of ${rootDenot.name.debugString} = ${res._1.name.debugString}, ${res._2.name.debugString} / ${rootDenot is ModuleClass}") + res } override def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index cf99bb02228a..a49379327d38 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -432,7 +432,8 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas } val name1 = name0.adjustIfModuleClass(flags) - val name = if (name1 == nme.TRAIT_CONSTRUCTOR) nme.CONSTRUCTOR else name1 + val name2 = if (name1 == nme.TRAIT_CONSTRUCTOR) nme.CONSTRUCTOR else name1 + val name = if (flags is ModuleClass) name2.unmangleClassName else name2 def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass) def isModuleClassRoot = (name == moduleClassRoot.name) && (owner == moduleClassRoot.owner) && (flags is Module) From ccba1b7762cc54c01ad8e5f949b8c6b1674122e0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Mar 2017 11:22:50 +0100 Subject: [PATCH 06/68] Self-checked structured qualified names This is a temporary step. If semanticNames is true we construct structured qualified names, but check they have the same string representation as the unstructured names. --- .../tools/dotc/core/SymDenotations.scala | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 6d1a006ed19b..150bb1584f49 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)(implicit ctx: Context): Name = { + def fullNameSeparated(separator: String, semantic: Boolean)(implicit ctx: Context): Name = { var sep = separator var stopAtPackage = false if (sep.isEmpty) { @@ -409,12 +409,34 @@ object SymDenotations { encl = encl.owner sep += "~" } - if (owner.is(ModuleClass, butNot = Package) && sep == "$") sep = "" // duplicate scalac's behavior: don't write a double '$$' for module class members. - val fn = encl.fullNameSeparated(separator) ++ sep ++ name + var prefix = encl.fullNameSeparated(separator, semantic) + val fn = + if (semantic) { + 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.toTermName, sep)) + } + else { + if (owner.is(ModuleClass, butNot = Package) && sep == "$") + // duplicate scalac's behavior: don't write a double '$$' for module class members. + sep = "" + prefix ++ sep ++ name + } if (isType) fn.toTypeName else fn.toTermName } } + 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("") @@ -1220,7 +1242,8 @@ object SymDenotations { // ----- denotation fields and accessors ------------------------------ - if (initFlags is (Module, butNot = Package)) assert(name.isModuleClassName, s"module naming inconsistency: $name") + if (initFlags is (Module, butNot = Package)) + assert(name.isModuleClassName, s"module naming inconsistency: ${name.debugString}") /** The symbol asserted to have type ClassSymbol */ def classSymbol: ClassSymbol = symbol.asInstanceOf[ClassSymbol] From 88171be0c4aeb7e9ea0f858929a26160badf688c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Mar 2017 11:24:03 +0100 Subject: [PATCH 07/68] Unmangle class names in ClassfileParser --- .../src/dotty/tools/dotc/core/classfile/ClassfileParser.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index da875c90622b..1e419a72b486 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -931,7 +931,7 @@ class ClassfileParser( errorBadIndex(index) if (internalized(index) == null) - internalized(index) = getName(index).replace('/', '.') + internalized(index) = getName(index).replace('/', '.').unmangleClassName internalized(index) } From d44eb20b8361fdce92496e3f62a8b9d94d93baab Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Mar 2017 11:24:19 +0100 Subject: [PATCH 08/68] Deug info in classfile parser --- .../tools/dotc/core/classfile/ClassfileParser.scala | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 1e419a72b486..a0e4cc62bafc 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -25,6 +25,8 @@ class ClassfileParser( classRoot: ClassDenotation, moduleRoot: ClassDenotation)(ictx: Context) { + //println(s"parsing ${classRoot.name.debugString} ${moduleRoot.name.debugString}") + import ClassfileConstants._ import ClassfileParser._ @@ -91,7 +93,12 @@ class ClassfileParser( if (currentIsTopLevel) { val c = pool.getClassSymbol(nameIdx) - if (c != classRoot.symbol) mismatchError(c) + if (c != classRoot.symbol) { + println(currentClassName.debugString) // TODO: remove + println(c.name.debugString) + println(classRoot.symbol.name.debugString) + mismatchError(c) + } } addEnclosingTParams() From e1181d9f5b3fc56baafbe859d3d3441dfdb113a1 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Mar 2017 11:30:26 +0100 Subject: [PATCH 09/68] Fix typos and redundant statements in previous commits --- compiler/src/dotty/tools/dotc/config/Config.scala | 2 +- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 3 +-- compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala | 3 --- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index a225b3019180..65e9d3856482 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -10,7 +10,7 @@ object Config { final val checkCacheMembersNamed = false - final val semanticNames = true + final val semanticNames = false /** When updating a constraint bound, check that the constrained parameter * does not appear at the top-level of either of its bounds. diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 150bb1584f49..0483e0ca14dd 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -433,9 +433,8 @@ object SymDenotations { 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/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 40e561d3ff73..0ea643e0d9a5 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -248,11 +248,8 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader { (module, _) => new NoCompleter() withDecls newScope withSourceModule (_ => module)) .moduleClass.denot.asClass } - val res = if (rootDenot is ModuleClass) (linkedDenot, rootDenot) else (rootDenot, linkedDenot) - println(s"root denots of ${rootDenot.name.debugString} = ${res._1.name.debugString}, ${res._2.name.debugString} / ${rootDenot is ModuleClass}") - res } override def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = From 2cc16c4d990fa404577dbe1c944958a0cf9896a8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Mar 2017 15:08:28 +0100 Subject: [PATCH 10/68] Use system hashcode for all names except SimpleTermNames Keep start as a hash for SimpleTermNames because it distributed better. --- compiler/src/dotty/tools/dotc/core/Names.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index dbaa338a2f84..9488aef618bd 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -227,13 +227,13 @@ object Names { !NameInfo.definesNewName(ownKind) && ownKind > kind && underlying.is(kind) } - override def hashCode: Int = start - 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. + override def hashCode: Int = start + override def toString = if (length == 0) "" else new String(chrs, start, length) @@ -257,8 +257,6 @@ object Names { def without(kind: NameInfo.Kind): TypeName = toTermName.without(kind).toTypeName def is(kind: NameInfo.Kind) = toTermName.is(kind) - override def hashCode: Int = -start - override protected[this] def newBuilder: Builder[Char, Name] = termNameBuilder.mapResult(_.toTypeName) From 19bc1ff09fa73e13be7e3464b8440c04b657aa82 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Mar 2017 17:59:25 +0100 Subject: [PATCH 11/68] 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. --- .../backend/jvm/DottyBackendInterface.scala | 4 +- .../src/dotty/tools/dotc/core/NameInfos.scala | 6 +- .../src/dotty/tools/dotc/core/NameOps.scala | 2 +- .../src/dotty/tools/dotc/core/Names.scala | 128 ++++++++---------- .../dotc/core/classfile/ClassfileParser.scala | 2 +- .../tools/dotc/core/tasty/NameBuffer.scala | 2 +- .../tools/dotc/core/tasty/TastyName.scala | 4 +- .../tools/dotc/core/tasty/TreePickler.scala | 2 +- .../dotty/tools/dotc/parsing/Scanners.scala | 2 +- .../src/dotty/tools/dotc/parsing/Tokens.scala | 2 +- 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 77e979e4d88a..309d97261b2f 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 51c04b9e46cb..650a0c0a4174 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 38eb21446a8f..27065a50a304 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 9488aef618bd..9ec9e73f2c60 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("") - val STATIC_CONSTRUCTOR = termName("") - val EMPTY_PACKAGE = termName("") + val CONSTRUCTOR: TermName = termName("") + val STATIC_CONSTRUCTOR: TermName = termName("") + val EMPTY_PACKAGE: TermName = termName("") 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 a0e4cc62bafc..131c9cf9ba9b 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 3ff7298cec0c..b05e6ef21885 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 26807115cfe3..da205542ef08 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 902d01c21653..7a6b6b7ea97f 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 ff5019dc9871..bcf6eb4a5fd5 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 d2ea9240c504..96ae25c9eeb9 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(' ') From bbc84eabcd244179299ad435b6e9d7473e5ff892 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Mar 2017 19:18:20 +0100 Subject: [PATCH 12/68] Implement startsWith/encode/decode for derived names. --- .../src/dotty/tools/dotc/core/NameInfos.scala | 4 +- .../src/dotty/tools/dotc/core/Names.scala | 39 +++++++++++++------ .../src/dotty/tools/dotc/core/StdNames.scala | 2 +- .../tools/dotc/core/SymDenotations.scala | 2 +- .../tools/dotc/util/NameTransformer.scala | 5 +-- 5 files changed, 34 insertions(+), 18 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameInfos.scala b/compiler/src/dotty/tools/dotc/core/NameInfos.scala index 650a0c0a4174..031ca8f6e152 100644 --- a/compiler/src/dotty/tools/dotc/core/NameInfos.scala +++ b/compiler/src/dotty/tools/dotc/core/NameInfos.scala @@ -9,6 +9,7 @@ import Names._ 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 ++(other: String): NameInfo = unsupported("++") } @@ -29,9 +30,10 @@ object NameInfo { def mkString(underlying: TermName) = underlying.toString // will cause an unsupported exception } - case class Qualified(name: TermName, separator: String) extends NameInfo { + case class Qualified(name: SimpleTermName, separator: String) extends 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 ++(other: String): NameInfo = Qualified(name ++ other, separator) override def toString = s"Qualified($name, $separator)" diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 9ec9e73f2c60..e9dbd7f7c4b7 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -75,13 +75,10 @@ object Names { def toText(printer: Printer): Text = printer.toText(this) /** Replace \$op_name's by corresponding operator symbols. */ - def decode: Name = - if (contains('$')) fromName(termName(NameTransformer.decode(toString))) - else this + def decode: Name /** Replace operator symbols by corresponding \$op_name's. */ - def encode: Name = - if (dontEncode(toTermName)) this else NameTransformer.encode(this) + def encode: Name /** A more efficient version of concatenation */ def ++ (other: Name): ThisName = ++ (other.toString) @@ -89,7 +86,8 @@ object Names { def replace(from: Char, to: Char): ThisName = fromName(toSimpleName.replace(from, to)) - def contains(ch: Char): Boolean + def startsWith(str: String): Boolean + def startsWith(name: Name): Boolean = startsWith(name.toString) override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] } @@ -187,14 +185,20 @@ object Names { def apply(n: Int) = chrs(start + n) - def ++ (other: String): ThisName = termName(toString + other) + def ++ (other: String): SimpleTermName = termName(toString + other) - def contains(ch: Char): Boolean = { + private def contains(ch: Char): Boolean = { var i = 0 while (i < length && chrs(start + i) != ch) i += 1 i < length } + def startsWith(str: String): Boolean = { + var i = 0 + while (i < str.length && i < length && apply(i) == str(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) @@ -204,6 +208,13 @@ object Names { fromName(termName(cs, 0, length)) } + def encode: SimpleTermName = + if (dontEncode(toTermName)) this else NameTransformer.encode(this) + + /** Replace \$op_name's by corresponding operator symbols. */ + def decode: SimpleTermName = + if (contains('$')) termName(NameTransformer.decode(toString)) else this + override def hashCode: Int = start override def toString = @@ -218,7 +229,10 @@ object Names { def ++ (other: String): ThisName = toTermName.++(other).toTypeName - def contains(ch: Char): Boolean = toTermName.contains(ch) + def startsWith(str: String): Boolean = toTermName.startsWith(str) + + def encode: Name = toTermName.encode + def decode: Name = toTermName.decode type ThisName = TypeName def isTypeName = true @@ -243,7 +257,9 @@ object Names { class DerivedTermName(override val underlying: TermName, override val info: NameInfo) extends TermName { def ++ (other: String): ThisName = derived(info ++ other) - def contains(ch: Char): Boolean = underlying.contains(ch) || info.contains(ch) + def startsWith(str: String): Boolean = underlying.startsWith(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]" } @@ -388,7 +404,7 @@ object Names { val STATIC_CONSTRUCTOR: TermName = termName("") val EMPTY_PACKAGE: TermName = termName("") - val dontEncode = Set[TermName](CONSTRUCTOR, EMPTY_PACKAGE) + val dontEncode = Set(CONSTRUCTOR, EMPTY_PACKAGE) def termNameBuilder: Builder[Char, TermName] = StringBuilder.newBuilder.mapResult(termName) @@ -404,7 +420,6 @@ object Names { 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) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index e7928fd09476..56f8ca1894b9 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -92,7 +92,7 @@ object StdNames { val BITMAP_CHECKINIT: N = BITMAP_PREFIX + "init$" // initialization bitmap for checkinit values val BITMAP_CHECKINIT_TRANSIENT: N = BITMAP_PREFIX + "inittrans$" // initialization bitmap for transient checkinit values val DEFAULT_GETTER: N = "$default$" - val DEFAULT_GETTER_INIT: N = NameTransformer.encode("") + val DEFAULT_GETTER_INIT: N = "$lessinit$greater" val DO_WHILE_PREFIX: N = "doWhile$" val EMPTY: N = "" val EMPTY_PACKAGE: N = Names.EMPTY_PACKAGE.toString diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 0483e0ca14dd..070fdf345c09 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -415,7 +415,7 @@ object SymDenotations { 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.toTermName, sep)) + prefix.derived(NameInfo.Qualified(name.toSimpleName, sep)) } else { if (owner.is(ModuleClass, butNot = Package) && sep == "$") diff --git a/compiler/src/dotty/tools/dotc/util/NameTransformer.scala b/compiler/src/dotty/tools/dotc/util/NameTransformer.scala index 330d513fec39..52f8e6ec0bb4 100644 --- a/compiler/src/dotty/tools/dotc/util/NameTransformer.scala +++ b/compiler/src/dotty/tools/dotc/util/NameTransformer.scala @@ -60,7 +60,7 @@ object NameTransformer { * @param name the string to encode * @return the string with all recognized opchars replaced with their encoding */ - def encode[N <: Name](name: N): N = { + def encode(name: SimpleTermName): SimpleTermName = { var buf: StringBuilder = null val len = name.length var i = 0 @@ -87,8 +87,7 @@ object NameTransformer { i += 1 } if (buf eq null) name - else if (name.isTermName) buf.toString.toTermName.asInstanceOf[N] - else buf.toString.toTypeName.asInstanceOf[N] + else termName(buf.toString) } /** Replace `\$opname` by corresponding operator symbol. From c27cbd16e6fd3cc00e603aebef95f477684b3390 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 23 Mar 2017 17:14:39 +0100 Subject: [PATCH 13/68] Bug fixes nameddefaults.scala now compiles without crashing --- .../tools/dotc/config/ScalaSettings.scala | 2 +- .../dotty/tools/dotc/core/Denotations.scala | 43 ++++++++----- .../src/dotty/tools/dotc/core/NameInfos.scala | 4 +- .../src/dotty/tools/dotc/core/NameOps.scala | 12 ++-- .../src/dotty/tools/dotc/core/Names.scala | 61 +++++++++++++++---- .../tools/dotc/core/SymDenotations.scala | 17 ++---- .../tools/dotc/core/tasty/NameBuffer.scala | 30 ++++++--- .../tools/dotc/core/tasty/TreePickler.scala | 2 +- .../dotty/tools/dotc/parsing/Scanners.scala | 2 +- .../src/dotty/tools/dotc/parsing/Tokens.scala | 2 +- .../tools/dotc/printing/RefinedPrinter.scala | 3 +- .../src/dotty/tools/dotc/typer/Namer.scala | 2 +- 12 files changed, 115 insertions(+), 65 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 49b64d86949a..63c3d5f74ed7 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 7341b96af2e0..a679cad6f2cb 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 031ca8f6e152..b49a0979eb1a 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 27065a50a304..f49c82ee48a1 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 e9dbd7f7c4b7..9730adb59a1d 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 070fdf345c09..3f8eda625d35 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 b05e6ef21885..f1f03dd3c3c2 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 7a6b6b7ea97f..78d59c99f94b 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 bcf6eb4a5fd5..3084c30a8957 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 96ae25c9eeb9..770b826fd9f2 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 0b683d90c66a..798a1c854b75 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 b436b36b073c..78a1cd9c30e0 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, From e2056bb62e8d4ce5806111f0c54f7331eb690f0a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 23 Mar 2017 18:50:39 +0100 Subject: [PATCH 14/68] Polishings --- .../src/dotty/tools/dotc/core/NameInfos.scala | 4 - .../src/dotty/tools/dotc/core/NameOps.scala | 2 +- .../src/dotty/tools/dotc/core/Names.scala | 75 +++++++++++-------- .../tools/dotc/core/SymDenotations.scala | 4 +- 4 files changed, 47 insertions(+), 38 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameInfos.scala b/compiler/src/dotty/tools/dotc/core/NameInfos.scala index b49a0979eb1a..e8db88f84226 100644 --- a/compiler/src/dotty/tools/dotc/core/NameInfos.scala +++ b/compiler/src/dotty/tools/dotc/core/NameInfos.scala @@ -10,8 +10,6 @@ abstract class NameInfo extends util.DotClass { def kind: NameInfo.Kind def mkString(underlying: TermName): String def map(f: SimpleTermName => SimpleTermName): NameInfo = this - def satisfies(p: SimpleTermName => Boolean): Boolean = false - def ++(other: String): NameInfo = unsupported("++") } object NameInfo { @@ -34,8 +32,6 @@ 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 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 f49c82ee48a1..c4d5519818a3 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -132,7 +132,7 @@ object NameOps { /** If name ends in module class suffix, drop it */ def stripModuleClassSuffix: Name = if (isModuleClassName) - if (Config.semanticNames) name.without(NameInfo.ModuleClass.kind) + if (Config.semanticNames) name.exclude(NameInfo.ModuleClass.kind) else name dropRight MODULE_SUFFIX.length else name diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 9730adb59a1d..ffbb097b82ca 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -71,7 +71,8 @@ object Names { def likeKinded(name: Name): ThisName def derived(info: NameInfo): ThisName - def without(kind: NameInfo.Kind): 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 @@ -83,6 +84,9 @@ object Names { /** Replace operator symbols by corresponding \$op_name's. */ def encode: Name + def firstPart: TermName + def lastPart: TermName + /** A more efficient version of concatenation */ def ++ (other: Name): ThisName = ++ (other.toString) def ++ (other: String): ThisName @@ -90,12 +94,12 @@ object Names { def replace(from: Char, to: Char): ThisName = likeKinded(asSimpleName.replace(from, to)) def isEmpty: Boolean - def startsWith(str: String): Boolean + + def startsWith(str: String): Boolean = firstPart.startsWith(str) def startsWith(name: Name): Boolean = startsWith(name.toString) - def endsWith(str: String): Boolean + def endsWith(str: String): Boolean = lastPart.endsWith(str) def endsWith(name: Name): Boolean = endsWith(name.toString) - override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] } @@ -151,33 +155,31 @@ object Names { name } + private def add(info: NameInfo): TermName = synchronized { + getDerived(info) match { + case null => putDerived(info, new DerivedTermName(this, info)) + case derivedName => derivedName + } + } + /** Return derived name with given `info` and the current * name as underlying name. */ def derived(info: NameInfo): TermName = { - def addIt() = synchronized { - getDerived(info) match { - case null => putDerived(info, new DerivedTermName(this, info)) - case derivedName => derivedName - } - } - val ownKind = this.info.kind - if (NameInfo.definesNewName(info.kind)) addIt() - else if (ownKind > info.kind) - underlying.derived(info).derived(this.info) - else if (ownKind == info.kind) { + if (ownKind < info.kind || NameInfo.definesNewName(info.kind)) add(info) + else if (ownKind > info.kind) underlying.derived(info).add(this.info) + else { assert(info == this.info) this } - else addIt() } - def without(kind: NameInfo.Kind): TermName = { - val ownKind = info.kind + def exclude(kind: NameInfo.Kind): TermName = { + val ownKind = this.info.kind if (ownKind < kind || NameInfo.definesNewName(ownKind)) this - else if (ownKind == kind) underlying.without(kind) - else underlying.without(kind).derived(this.info) + else if (ownKind > kind) underlying.exclude(kind).add(this.info) + else underlying } def is(kind: NameInfo.Kind): Boolean = { @@ -205,13 +207,13 @@ object Names { def isEmpty = length == 0 - def startsWith(str: String): Boolean = { + override 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 = { + override 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 @@ -238,6 +240,9 @@ object Names { def decode: SimpleTermName = if (contains('$')) termName(NameTransformer.decode(toString)) else this + def firstPart = this + def lastPart = this + override def hashCode: Int = start override def toString = @@ -251,11 +256,11 @@ object Names { 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.toTypeName - def decode: Name = toTermName.decode.toTypeName + def encode = toTermName.encode.toTypeName + def decode = toTermName.decode.toTypeName + def firstPart = toTermName.firstPart + def lastPart = toTermName.lastPart type ThisName = TypeName def isTypeName = true @@ -272,7 +277,7 @@ object Names { 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 + def exclude(kind: NameInfo.Kind): TypeName = toTermName.exclude(kind).toTypeName def is(kind: NameInfo.Kind) = toTermName.is(kind) override def toString = toTermName.toString @@ -284,12 +289,21 @@ object Names { */ 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)) + def firstPart = info match { + case NameInfo.Qualified(name, _) => name + case _ => underlying.firstPart + } + def lastPart = info match { + case NameInfo.Qualified(name, _) => name + case _ => underlying.lastPart + } + def ++ (other: String): ThisName = info match { + case NameInfo.Qualified(name, sep) => underlying.select(name ++ other, sep) + case _ => (underlying ++ other).derived(info) + } override def toString = info.mkString(underlying) override def debugString = s"${underlying.debugString}[$info]" @@ -455,7 +469,6 @@ object Names { def seq: WrappedString = new WrappedString(name.toString) override protected[this] def thisCollection: WrappedString = seq - 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) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 3f8eda625d35..f671ab5574f8 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -414,8 +414,8 @@ object SymDenotations { if (Config.semanticNames) { if (sep == "$") // duplicate scalac's behavior: don't write a double '$$' for module class members. - prefix = prefix.without(NameInfo.ModuleClassKind) - name.mapSimpleCore(sn => prefix.derived(NameInfo.Qualified(sn, sep))) + prefix = prefix.exclude(NameInfo.ModuleClassKind) + name.mapSimpleCore(prefix.select(_, sep)) } else { if (owner.is(ModuleClass, butNot = Package) && sep == "$") From a2731a8be2f3434218623c0b0ecd4078107f14a5 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 23 Mar 2017 23:35:17 +0100 Subject: [PATCH 15/68] Handle expansion and flattening --- compiler/src/dotty/tools/dotc/ast/Trees.scala | 2 +- .../dotty/tools/dotc/core/Denotations.scala | 4 +- .../src/dotty/tools/dotc/core/NameInfos.scala | 37 ++++++++++++++-- .../src/dotty/tools/dotc/core/NameOps.scala | 42 +++++++++++++------ .../src/dotty/tools/dotc/core/Names.scala | 27 ++++++------ .../src/dotty/tools/dotc/core/StdNames.scala | 9 +++- .../tools/dotc/core/SymDenotations.scala | 6 ++- .../tools/dotc/core/tasty/NameBuffer.scala | 18 +++++--- .../tools/dotc/core/tasty/TastyFormat.scala | 11 ++--- .../tools/dotc/core/tasty/TastyName.scala | 3 +- .../dotc/core/tasty/TastyUnpickler.scala | 6 ++- .../tools/dotc/core/tasty/TreeUnpickler.scala | 15 ++++++- 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 20d7c1458b94..0ff335e4099e 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 a679cad6f2cb..aa0ea39a2963 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 e8db88f84226..daaa5c4e1b4f 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 c4d5519818a3..65669a871347 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 ffbb097b82ca..84b2fab0cd76 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 56f8ca1894b9..9e05d4bced8d 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 = "" 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 = "" 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 f671ab5574f8..74505d81127d 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 f1f03dd3c3c2..7ac505a2006c 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 8b2255e940b4..848b7995f8c4 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 da205542ef08..67b08a1c1cc7 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 8a1f58acd77c..c8c1878bc3c5 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 a186d1ce4289..06165c6f41c0 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 From 0ad1cd816bc1537ad332addabb0ff6c293e3e0a0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Mar 2017 13:20:01 +0100 Subject: [PATCH 16/68] Add default getter names Plus various bug fixes and filling in missing functionality --- .../src/dotty/tools/dotc/core/NameInfos.scala | 17 ++- .../src/dotty/tools/dotc/core/NameOps.scala | 69 +++++++---- .../src/dotty/tools/dotc/core/Names.scala | 111 +++++++++++++----- .../src/dotty/tools/dotc/core/StdNames.scala | 5 + .../tools/dotc/core/tasty/NameBuffer.scala | 2 + .../tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- .../core/unpickleScala2/Scala2Unpickler.scala | 5 +- .../tools/dotc/transform/ResolveSuper.scala | 11 +- .../tools/dotc/transform/TreeChecker.scala | 4 +- 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 daaa5c4e1b4f..c5b83b0dc7b0 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 65669a871347..eb284168adc0 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 * @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 */ - 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 84b2fab0cd76..22d0588f422d 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 9e05d4bced8d..1a65556bab41 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 7ac505a2006c..b45255eb8786 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 06165c6f41c0..d4269d6e4ab8 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 a49379327d38..084b8d09890a 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 3a301167dee9..b6c28f570e92 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 ebb5b605b43e..199fac82b08b 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) From 0755ec28d22798c51aedf45e4dcdf1ed299c2aa5 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Mar 2017 19:15:51 +0100 Subject: [PATCH 17/68] Add Variant NameInfo Plus further bug fixes. --- .../src/dotty/tools/dotc/core/NameInfos.scala | 12 +++++++++- .../src/dotty/tools/dotc/core/Names.scala | 3 ++- .../src/dotty/tools/dotc/core/StdNames.scala | 2 +- .../tools/dotc/core/SymDenotations.scala | 24 +++++++++---------- .../tools/dotc/core/tasty/NameBuffer.scala | 5 ++++ .../tools/dotc/core/tasty/TastyFormat.scala | 6 ++++- .../tools/dotc/core/tasty/TastyName.scala | 1 + .../dotc/core/tasty/TastyUnpickler.scala | 2 ++ .../tools/dotc/core/tasty/TreePickler.scala | 1 + .../tools/dotc/core/tasty/TreeUnpickler.scala | 1 + .../tools/dotc/printing/PlainPrinter.scala | 6 +---- 11 files changed, 42 insertions(+), 21 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameInfos.scala b/compiler/src/dotty/tools/dotc/core/NameInfos.scala index c5b83b0dc7b0..f6d9e84c00d1 100644 --- a/compiler/src/dotty/tools/dotc/core/NameInfos.scala +++ b/compiler/src/dotty/tools/dotc/core/NameInfos.scala @@ -20,8 +20,9 @@ object NameInfo { val TermNameKind = 0 val QualifiedKind = 1 - val ModuleClassKind = 2 val DefaultGetterKind = 3 + val VariantKind = 4 + val ModuleClassKind = 10 val qualifier: Map[String, SimpleTermName => Qualified] = Map("." -> Select, @@ -81,9 +82,18 @@ object NameInfo { } } + case class Variant(val num: Int) extends Numbered { + def kind = VariantKind + def mkString(underlying: TermName) = varianceToPrefix(num).toString + underlying + } + val ModuleClass = new NameInfo { def kind = ModuleClassKind def mkString(underlying: TermName) = underlying + "$" override def toString = "ModuleClass" } + + /** Map between variances and name prefixes */ + val varianceToPrefix = Map(-1 -> '-', 0 -> '=', 1 -> '+') + val prefixToVariance = Map('-' -> -1, '=' -> 0, '+' -> 1) } \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 22d0588f422d..407dc149a79a 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -482,8 +482,9 @@ object Names { val CONSTRUCTOR: TermName = termName("") val STATIC_CONSTRUCTOR: TermName = termName("") val EMPTY_PACKAGE: TermName = termName("") + val REFINEMENT: TermName = termName("") - val dontEncode = Set(CONSTRUCTOR, EMPTY_PACKAGE) + val dontEncode = Set(CONSTRUCTOR, EMPTY_PACKAGE, REFINEMENT) def termNameBuilder: Builder[Char, TermName] = StringBuilder.newBuilder.mapResult(termName) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 1a65556bab41..e5e2165ce2ba 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -548,7 +548,7 @@ object StdNames { val nothingClass: N = "Nothing$" val nullClass: N = "Null$" - + val falseModuleClassNames = Set(nothingClass, nullClass, nothingRuntimeClass, nullRuntimeClass) // unencoded operators diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 74505d81127d..e50d6a133c75 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -393,21 +393,18 @@ object SymDenotations { * enclosing packages do not form part of the name. */ def fullNameSeparated(separator: String)(implicit ctx: Context): Name = { - var sep = separator - var stopAtPackage = false - if (sep.isEmpty) { - sep = "$" - stopAtPackage = true - } + val stopAtPackage = separator.isEmpty + val sep = if (stopAtPackage) "$" else separator if (symbol == NoSymbol || owner == NoSymbol || owner.isEffectiveRoot || stopAtPackage && owner.is(PackageClass)) name else { + var filler = "" var encl = owner while (!encl.isClass && !encl.isPackageObject) { encl = encl.owner - sep += "~" + filler += "~" } var prefix = encl.fullNameSeparated(separator) val fn = @@ -416,14 +413,17 @@ object SymDenotations { // duplicate scalac's behavior: don't write a double '$$' for module class members. prefix = prefix.exclude(NameInfo.ModuleClassKind) name rewrite { - case n: SimpleTermName => prefix.derived(NameInfo.qualifier(sep)(n)) + case n: SimpleTermName => + val n1 = if (filler.isEmpty) n else termName(filler ++ n) + prefix.derived(NameInfo.qualifier(sep)(n1)) } } else { - if (owner.is(ModuleClass, butNot = Package) && sep == "$") - // duplicate scalac's behavior: don't write a double '$$' for module class members. - sep = "" - prefix ++ sep ++ name + val sep1 = + if (owner.is(ModuleClass, butNot = Package) && sep == "$") "" + else sep + // duplicate scalac's behavior: don't write a double '$$' for module class members. + prefix ++ sep1 ++ name } if (isType) fn.toTypeName else fn.toTermName } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index b45255eb8786..19eb731c71a2 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala @@ -38,6 +38,8 @@ class NameBuffer extends TastyBuffer(10000) { tcon(nameIndex(prefix, toTasty), nameIndex(qual.name)) case DerivedTermName(prefix, NameInfo.DefaultGetter(num)) => DefaultGetter(nameIndex(prefix, toTasty), num) + case DerivedTermName(prefix, NameInfo.Variant(sign)) => + Variant(nameIndex(prefix, toTasty), sign) case name1 => if (name1.isShadowedName) Shadowed(nameIndex(name1.revertShadowed, toTasty)) else toTasty(name1.asSimpleName) @@ -102,6 +104,9 @@ class NameBuffer extends TastyBuffer(10000) { case Shadowed(original) => writeByte(SHADOWED) withLength { writeNameRef(original) } + case Variant(original, sign) => + writeByte(VARIANT) + withLength { writeNameRef(original); writeNat(sign + 1) } } override def assemble(): Unit = { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 848b7995f8c4..d4f6782fb1c2 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -229,6 +229,7 @@ object TastyFormat { final val SUPERACCESSOR = 7 final val DEFAULTGETTER = 8 final val SHADOWED = 9 + final val VARIANT = 10 // AST tags @@ -412,11 +413,14 @@ object TastyFormat { def nameTagToString(tag: Int): String = tag match { case UTF8 => "UTF8" case QUALIFIED => "QUALIFIED" - case SIGNED => "SIGNED" + case FLATTENED => "FLATTENED" case EXPANDED => "EXPANDED" + case SIGNED => "SIGNED" case OBJECTCLASS => "OBJECTCLASS" case SUPERACCESSOR => "SUPERACCESSOR" case DEFAULTGETTER => "DEFAULTGETTER" + case SHADOWED => "SHADOWED" + case VARIANT => "VARIANT" } def astTagToString(tag: Int): String = tag match { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala index 67b08a1c1cc7..769ecfbfceba 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala @@ -21,6 +21,7 @@ object TastyName { case class SuperAccessor(accessed: NameRef) extends TastyName case class DefaultGetter(method: NameRef, num: Int) extends TastyName case class Shadowed(original: NameRef) extends TastyName + case class Variant(original: NameRef, sign: Int) extends TastyName class Table extends (NameRef => TastyName) { private val names = new mutable.ArrayBuffer[TastyName] diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala index c8c1878bc3c5..e6b43e6b4334 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala @@ -62,6 +62,8 @@ class TastyUnpickler(reader: TastyReader) { DefaultGetter(readNameRef(), readNat()) case SHADOWED => Shadowed(readNameRef()) + case VARIANT => + Variant(readNameRef(), readNat() - 1) } assert(currentAddr == end, s"bad name $result $start $currentAddr $end") result diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 78d59c99f94b..d81bd3ea8a09 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -13,6 +13,7 @@ import NameOps._ import StdNames.nme import TastyBuffer._ import TypeApplications._ +import config.Config class TreePickler(pickler: TastyPickler) { val buf = new TreeBuffer diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index d4269d6e4ab8..14c3d7cd1249 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -91,6 +91,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle case ModuleClass(original) => toTermName(original).moduleClassName.toTermName case SuperAccessor(accessed) => toTermName(accessed).superName case DefaultGetter(meth, num) => toTermName(meth).defaultGetterName(num) + case Variant(original, sign) => toTermName(original).derived(NameInfo.Variant(sign)) } private def qualTermName(qual: NameRef, name: NameRef, sep: String) = diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index c762bbeafbdd..20e657ce705c 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -97,11 +97,7 @@ class PlainPrinter(_ctx: Context) extends Printer { || (sym.name == nme.PACKAGE) // package ) - def nameString(name: Name): String = name.toString + { - if (ctx.settings.debugNames.value) - if (name.isTypeName) "/T" else "/V" - else "" - } + def nameString(name: Name): String = name.toString def toText(name: Name): Text = Str(nameString(name)) From f9a9ddb879e9de4730a463f28c8b6602e0e60bbc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 25 Mar 2017 11:00:13 +0100 Subject: [PATCH 18/68] Turn on semantic names --- compiler/src/dotty/tools/dotc/config/Config.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index 65e9d3856482..a225b3019180 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -10,7 +10,7 @@ object Config { final val checkCacheMembersNamed = false - final val semanticNames = false + final val semanticNames = true /** When updating a constraint bound, check that the constrained parameter * does not appear at the top-level of either of its bounds. From 624b4eb59862644646dec685833c67c64756a8bd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 25 Mar 2017 16:14:50 +0100 Subject: [PATCH 19/68] Semantic SuperAccessor and Initializer names --- .../src/dotty/tools/dotc/core/NameInfos.scala | 16 +++ .../src/dotty/tools/dotc/core/NameOps.scala | 109 ++++++++++++------ .../tools/dotc/core/SymDenotations.scala | 6 +- .../tools/dotc/core/tasty/NameBuffer.scala | 2 + .../tools/dotc/core/tasty/TreePickler.scala | 29 +++-- .../core/unpickleScala2/Scala2Unpickler.scala | 18 +-- 6 files changed, 122 insertions(+), 58 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameInfos.scala b/compiler/src/dotty/tools/dotc/core/NameInfos.scala index f6d9e84c00d1..23a161756b91 100644 --- a/compiler/src/dotty/tools/dotc/core/NameInfos.scala +++ b/compiler/src/dotty/tools/dotc/core/NameInfos.scala @@ -22,6 +22,8 @@ object NameInfo { val QualifiedKind = 1 val DefaultGetterKind = 3 val VariantKind = 4 + val SuperAccessorKind = 5 + val InitializerKind = 6 val ModuleClassKind = 10 val qualifier: Map[String, SimpleTermName => Qualified] = @@ -87,6 +89,20 @@ object NameInfo { def mkString(underlying: TermName) = varianceToPrefix(num).toString + underlying } + val SuperAccessor = new NameInfo { + def kind = SuperAccessorKind + def mkString(underlying: TermName) = + underlying.mapLast(n => (nme.SUPER_PREFIX ++ n).asSimpleName).toString + override def toString = "SuperAccessor" + } + + val Initializer = new NameInfo { + def kind = InitializerKind + def mkString(underlying: TermName) = + underlying.mapLast(n => (nme.INITIALIZER_PREFIX ++ n).asSimpleName).toString + override def toString = "Initializer" + } + 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 eb284168adc0..9d5d3bd6adf7 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -49,14 +49,25 @@ object NameOps { } } - class PrefixNameExtractor(pre: TermName) { - def apply(name: TermName): TermName = pre ++ name + class PrefixNameExtractor(pre: TermName, info: NameInfo) { + def apply(name: TermName): TermName = + if (Config.semanticNames) name.derived(info) else pre ++ name + def unapply(name: TermName): Option[TermName] = - if (name startsWith pre) Some(name.drop(pre.length).asTermName) else None + if (Config.semanticNames) + name match { + case DerivedTermName(original, `info`) => Some(original) + case _ => None + } + else tryUnmangle(name) + + def tryUnmangle(name: TermName): Option[TermName] = + if (name startsWith pre) Some(name.drop(pre.length).asTermName) + else None } - object SuperAccessorName extends PrefixNameExtractor(nme.SUPER_PREFIX) - object InitializerName extends PrefixNameExtractor(nme.INITIALIZER_PREFIX) + object SuperAccessorName extends PrefixNameExtractor(nme.SUPER_PREFIX, NameInfo.SuperAccessor) + object InitializerName extends PrefixNameExtractor(nme.INITIALIZER_PREFIX, NameInfo.Initializer) implicit class NameDecorator[N <: Name](val name: N) extends AnyVal { import nme._ @@ -152,7 +163,9 @@ object NameOps { }.asInstanceOf[N] /** The superaccessor for method with given name */ - def superName: TermName = (nme.SUPER_PREFIX ++ name).toTermName + def superName: TermName = + if (Config.semanticNames) name.derived(NameInfo.SuperAccessor).toTermName + else (nme.SUPER_PREFIX ++ name).toTermName /** The expanded name of `name` relative to given class `base`. */ @@ -165,9 +178,17 @@ object NameOps { */ def expandedName(prefix: Name, separator: Name = nme.EXPAND_SEPARATOR): N = likeTyped( - if (Config.semanticNames) - prefix.derived(NameInfo.qualifier(separator.toString)(name.toSimpleName)) - // note: expanded name may itself be expanded. For example, look at javap of scala.App.initCode + if (Config.semanticNames) { + def qualify(name: SimpleTermName) = + prefix.derived(NameInfo.qualifier(separator.toString)(name)) + name rewrite { + case name: SimpleTermName => + qualify(name) + case DerivedTermName(_, _: NameInfo.Qualified) => + // Note: an expanded name may itself be expanded. For example, look at javap of scala.App.initCode + qualify(name.toSimpleName) + } + } else prefix ++ separator ++ name) def expandedName(prefix: Name): N = expandedName(prefix, nme.EXPAND_SEPARATOR) @@ -178,35 +199,45 @@ object NameOps { * 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 = likeTyped { + def unexpandedName: N = if (Config.semanticNames) - name.rewrite { - case DerivedTermName(_, NameInfo.Expand(unexp)) => unexp + likeTyped { + name.rewrite { case DerivedTermName(_, NameInfo.Expand(unexp)) => unexp } } - else { - var idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) + else unexpandedNameOfMangled - // 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 + def unexpandedNameOfMangled: N = likeTyped { + var idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) - if (idx < 0) name else (name drop (idx + nme.EXPAND_SEPARATOR.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)) } - def expandedPrefix: N = likeTyped { + def expandedPrefix: N = if (Config.semanticNames) - name.rewrite { - case DerivedTermName(prefix, NameInfo.Expand(_)) => prefix + likeTyped { + name.rewrite { case DerivedTermName(prefix, NameInfo.Expand(_)) => prefix } } - else { - val idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) - assert(idx >= 0) - name.take(idx) - } + else expandedPrefixOfMangled + + def expandedPrefixOfMangled: N = { + val idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) + assert(idx >= 0) + likeTyped(name.take(idx)) } + def unmangleExpandedName: N = + if (Config.semanticNames && name.isSimple) { + val unmangled = unexpandedNameOfMangled + if (name eq unmangled) name + else likeTyped(expandedPrefixOfMangled.derived(NameInfo.Expand(unmangled.asSimpleName))) + } + else name + def shadowedName: N = likeTyped(nme.SHADOWED ++ name) def revertShadowed: N = likeTyped(name.drop(nme.SHADOWED.length)) @@ -441,9 +472,9 @@ object NameOps { name rewrite { case DerivedTermName(methName, NameInfo.DefaultGetter(_)) => methName } - else mangledDefaultGetterToMethod + else defaultGetterToMethodOfMangled - def mangledDefaultGetterToMethod: TermName = { + def defaultGetterToMethodOfMangled: TermName = { val p = name.indexOfSlice(DEFAULT_GETTER) if (p >= 0) { val q = name.take(p).asTermName @@ -458,9 +489,9 @@ object NameOps { name collect { case DerivedTermName(methName, NameInfo.DefaultGetter(num)) => num } getOrElse -1 - else mangledDefaultGetterIndex + else defaultGetterIndexOfMangled - def mangledDefaultGetterIndex: Int = { + def defaultGetterIndexOfMangled: 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)) @@ -551,11 +582,21 @@ object NameOps { def unmangleMethodName: TermName = if (Config.semanticNames && name.isSimple) { - val idx = name.mangledDefaultGetterIndex - if (idx >= 0) name.mangledDefaultGetterToMethod.defaultGetterName(idx) + val idx = name.defaultGetterIndexOfMangled + if (idx >= 0) name.defaultGetterToMethodOfMangled.defaultGetterName(idx) else name } else name + + def unmangleSuperName: TermName = + if (Config.semanticNames && name.isSimple) + SuperAccessorName.tryUnmangle(name.lastPart) match { + case scala.Some(original) => + name.mapLast(_ => original.asSimpleName).derived(NameInfo.SuperAccessor) + case None => + name + } + else name } private final val FalseSuper = "$$super".toTermName diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index e50d6a133c75..845da95f2e7f 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -377,10 +377,8 @@ object SymDenotations { // might have been moved from different origins into the same class /** The name with which the denoting symbol was created */ - final def originalName(implicit ctx: Context) = { - val d = initial - if (d is ExpandedName) d.name.unexpandedName else d.name // !!!DEBUG, was: effectiveName - } + final def originalName(implicit ctx: Context) = + initial.effectiveName /** The encoded full path name of this denotation, where outer names and inner names * are separated by `separator` strings. diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index 19eb731c71a2..61a2c7fc5f51 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala @@ -29,6 +29,8 @@ class NameBuffer extends TastyBuffer(10000) { val tname = name.toTermName match { case DerivedTermName(name1, NameInfo.ModuleClass) => ModuleClass(nameIndex(name1, toTasty)) + case DerivedTermName(name1, NameInfo.SuperAccessor) => + SuperAccessor(nameIndex(name1, toTasty)) case DerivedTermName(prefix, qual: NameInfo.Qualified) => val tcon: (NameRef, NameRef) => TastyName = qual match { case _: NameInfo.Select => Qualified diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index d81bd3ea8a09..34ce40cb09ba 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -60,19 +60,24 @@ class TreePickler(pickler: TastyPickler) { } private def pickleName(sym: Symbol)(implicit ctx: Context): Unit = { - def encodeSuper(name: Name): TastyName.NameRef = - if (sym is Flags.SuperAccessor) { - val SuperAccessorName(n) = name - nameIndex(TastyName.SuperAccessor(nameIndex(n))) - } - else nameIndex(name) val nameRef = - if (sym is Flags.ExpandedName) - nameIndex( - TastyName.Expanded( - nameIndex(sym.name.expandedPrefix), - encodeSuper(sym.name.unexpandedName))) - else encodeSuper(sym.name) + if (Config.semanticNames) { + if (sym is Flags.ExpandedName) assert(sym.name.is(NameInfo.QualifiedKind)) + nameIndex(sym.name) + } + else { + def encodeSuper(name: Name): TastyName.NameRef = + if (sym is Flags.SuperAccessor) { + val SuperAccessorName(n) = name + nameIndex(TastyName.SuperAccessor(nameIndex(n))) + } else nameIndex(name) + if (sym is Flags.ExpandedName) + nameIndex( + TastyName.Expanded( + nameIndex(sym.name.expandedPrefix), + encodeSuper(sym.name.unexpandedName))) + else encodeSuper(sym.name) + } writeNat(nameRef.index) } diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 084b8d09890a..c37d60b4177c 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -420,10 +420,10 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas // symbols that were pickled with Pickler.writeSymInfo val nameref = readNat() - val name0 = at(nameref, readName) + var name = at(nameref, readName) val owner = readSymbolRef() - var flags = unpickleScalaFlags(readLongNat(), name0.isTypeName) + var flags = unpickleScalaFlags(readLongNat(), name.isTypeName) if (flags is DefaultParameter) { // DefaultParameterized flag now on method, not parameter //assert(flags is Param, s"$name0 in $owner") @@ -431,12 +431,14 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas owner.setFlag(DefaultParameterized) } - 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 if (flags is Method) name2.asTermName.unmangleMethodName - else name2 + name = name.adjustIfModuleClass(flags) + if (flags is Method) { + name = + if (name == nme.TRAIT_CONSTRUCTOR) nme.CONSTRUCTOR + else name.asTermName.unmangleMethodName + } + if (flags is ExpandedName) name = name.unmangleExpandedName + if (flags is SuperAccessor) name = name.asTermName.unmangleSuperName def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass) def isModuleClassRoot = (name == moduleClassRoot.name) && (owner == moduleClassRoot.owner) && (flags is Module) From 2ab37596efc9cd19081ee009fc97d46cf6c35896 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 25 Mar 2017 16:29:52 +0100 Subject: [PATCH 20/68] Fix test --- compiler/test/dotty/tools/ShowClassTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/test/dotty/tools/ShowClassTests.scala b/compiler/test/dotty/tools/ShowClassTests.scala index 4aa9e8845e2a..66ae8016965f 100644 --- a/compiler/test/dotty/tools/ShowClassTests.scala +++ b/compiler/test/dotty/tools/ShowClassTests.scala @@ -65,7 +65,7 @@ class ShowClassTests extends DottyTest { debug_println(s"blacklisted package: $path") else { for ( - sym <- pkg.info.decls if sym.owner == pkg.moduleClass && !(sym.name contains '$') + sym <- pkg.info.decls if sym.owner == pkg.moduleClass && !(sym.name.toString contains '$') ) { debug_println(s"showing $sym in ${pkg.fullName}") if (sym is PackageVal) showPackage(sym.asTerm) From 47158c9ae592bab53b9618b90b2514166a8a6004 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 26 Mar 2017 12:57:28 +0200 Subject: [PATCH 21/68] Properly integrate TraitSetter names --- .../src/dotty/tools/dotc/core/NameInfos.scala | 21 ++++++++++++------- .../src/dotty/tools/dotc/core/NameOps.scala | 18 +++++++++++----- .../tools/dotc/core/tasty/TreePickler.scala | 2 +- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameInfos.scala b/compiler/src/dotty/tools/dotc/core/NameInfos.scala index 23a161756b91..4f2628a9e465 100644 --- a/compiler/src/dotty/tools/dotc/core/NameInfos.scala +++ b/compiler/src/dotty/tools/dotc/core/NameInfos.scala @@ -19,11 +19,14 @@ object NameInfo { type Kind = Int val TermNameKind = 0 - val QualifiedKind = 1 - val DefaultGetterKind = 3 - val VariantKind = 4 - val SuperAccessorKind = 5 - val InitializerKind = 6 + val SelectKind = 1 + val FlattenKind = 2 + val ExpandKind = 3 + val TraitSetterKind = 4 + val DefaultGetterKind = 5 + val VariantKind = 6 + val SuperAccessorKind = 7 + val InitializerKind = 8 val ModuleClassKind = 10 val qualifier: Map[String, SimpleTermName => Qualified] = @@ -32,7 +35,7 @@ object NameInfo { str.EXPAND_SEPARATOR -> Expand, str.TRAIT_SETTER_SEPARATOR -> TraitSetter) - def definesNewName(kind: Kind) = kind <= QualifiedKind + def definesNewName(kind: Kind) = kind <= TraitSetterKind /** TermNames have the lowest possible kind */ val TermName = new NameInfo { @@ -41,32 +44,36 @@ object NameInfo { } trait Qualified extends NameInfo { + def kind: Kind 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 toString = s"${getClass.getSimpleName}($name)" } case class Select(val name: SimpleTermName) extends Qualified { + def kind = SelectKind def separator = "." def newLikeThis(name: SimpleTermName) = Select(name) } case class Flatten(val name: SimpleTermName) extends Qualified { + def kind = FlattenKind def separator = "$" def newLikeThis(name: SimpleTermName) = Flatten(name) } case class Expand(val name: SimpleTermName) extends Qualified { + def kind = ExpandKind def separator = str.EXPAND_SEPARATOR def newLikeThis(name: SimpleTermName) = Expand(name) } case class TraitSetter(val name: SimpleTermName) extends Qualified { + def kind = TraitSetterKind def separator = nme.TRAIT_SETTER_SEPARATOR.toString def newLikeThis(name: SimpleTermName) = TraitSetter(name) } diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 9d5d3bd6adf7..6d58a82bc21d 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -82,7 +82,9 @@ object NameOps { def isLoopHeaderLabel = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX) def isProtectedAccessorName = name startsWith PROTECTED_PREFIX def isReplWrapperName = name.toSimpleName containsSlice INTERPRETER_IMPORT_WRAPPER - def isTraitSetterName = name.toSimpleName containsSlice TRAIT_SETTER_SEPARATOR + def isTraitSetterName = + if (Config.semanticNames) name.is(NameInfo.TraitSetterKind) + else name containsSlice TRAIT_SETTER_SEPARATOR def isSetterName = name endsWith SETTER_SUFFIX def isSingletonName = name endsWith SINGLETON_SUFFIX def isModuleClassName = @@ -437,10 +439,16 @@ object NameOps { def fieldName: TermName = if (name.isSetterName) { if (name.isTraitSetterName) { - // has form <$-separated-trait-name>$_setter_$ `name`_$eq - 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) + if (Config.semanticNames) { + val DerivedTermName(_, NameInfo.TraitSetter(original)) = name + original ++ LOCAL_SUFFIX + } + else { + // 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 + } } else getterName.fieldName } else name.mapLast(n => (n ++ LOCAL_SUFFIX).asSimpleName) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 34ce40cb09ba..e73d6ed0d46c 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -62,7 +62,7 @@ class TreePickler(pickler: TastyPickler) { private def pickleName(sym: Symbol)(implicit ctx: Context): Unit = { val nameRef = if (Config.semanticNames) { - if (sym is Flags.ExpandedName) assert(sym.name.is(NameInfo.QualifiedKind)) + if (sym is Flags.ExpandedName) assert(sym.name.is(NameInfo.ExpandKind)) nameIndex(sym.name) } else { From baa2d513ad12cee410b824e0775bc570ed07b3dd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 26 Mar 2017 13:28:31 +0200 Subject: [PATCH 22/68] Fix to fieldName for trait setters --- compiler/src/dotty/tools/dotc/core/NameOps.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 6d58a82bc21d..ed6a41ac5068 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -441,7 +441,7 @@ object NameOps { if (name.isTraitSetterName) { if (Config.semanticNames) { val DerivedTermName(_, NameInfo.TraitSetter(original)) = name - original ++ LOCAL_SUFFIX + original.fieldName } else { // has form <$-separated-trait-name>$_setter_$ `name`_$eq From 606294c5729a7b106964415af6304d60cc102810 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 26 Mar 2017 14:44:11 +0200 Subject: [PATCH 23/68] Don't forget ExpandedName when unpickling SuperAccessors --- compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 14c3d7cd1249..e83a6f195dc7 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -465,7 +465,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle val (givenFlags, annots, privateWithin) = readModifiers(end) def nameFlags(tname: TastyName): FlagSet = tname match { case TastyName.Expanded(_, original) => ExpandedName | nameFlags(tastyName(original)) - case TastyName.SuperAccessor(_) => Flags.SuperAccessor + case TastyName.SuperAccessor(original) => Flags.SuperAccessor | nameFlags(tastyName(original)) case _ => EmptyFlags } pickling.println(i"creating symbol $name at $start with flags $givenFlags") From 0698383d595fec40c70905eb0e06b430f93ba0b8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Mar 2017 10:08:59 +0200 Subject: [PATCH 24/68] Add NameExtractors Use a new scheme for creating and accessing semantic names which is based on semantic name extractors with nested info classes. --- .../dotty/tools/dotc/core/Denotations.scala | 19 +-- .../src/dotty/tools/dotc/core/NameInfos.scala | 122 ------------------ .../src/dotty/tools/dotc/core/NameOps.scala | 43 +++--- .../src/dotty/tools/dotc/core/Names.scala | 60 +++++---- .../src/dotty/tools/dotc/core/StdNames.scala | 2 + .../tools/dotc/core/SymDenotations.scala | 8 +- .../tools/dotc/core/tasty/NameBuffer.scala | 27 ++-- .../tools/dotc/core/tasty/TreePickler.scala | 6 +- .../tools/dotc/core/tasty/TreeUnpickler.scala | 5 +- 9 files changed, 90 insertions(+), 202 deletions(-) delete mode 100644 compiler/src/dotty/tools/dotc/core/NameInfos.scala diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index aa0ea39a2963..60a506291341 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -6,6 +6,7 @@ import SymDenotations.{ SymDenotation, ClassDenotation, NoDenotation } import Contexts.{Context, ContextBase} import Names._ import NameOps._ +import NameExtractors._ import StdNames._ import Symbols.NoSymbol import Symbols._ @@ -1185,19 +1186,19 @@ object Denotations { } else owner } - def recur(path: Name, wrap: Name => Name = identity): Denotation = path match { + def recur(path: Name, wrap: TermName => 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.Select(selector)) => + recur(path.toTermName, n => n.toTypeName) + case ModuleClassName(underlying) => + recur(underlying, n => wrap(ModuleClassName(n))) + case QualifiedName(prefix, selector) => select(recur(prefix), wrap(selector)) - case DerivedTermName(prefix, qual: NameInfo.Qualified) => - recur(prefix, n => wrap(n ++ qual.separator ++ qual.name)) + case AnyQualifiedName(prefix, info) => + recur(prefix, n => wrap(info.mkString(n).toTermName)) case path: SimpleTermName => - def recurSimple(len: Int, wrap: Name => Name): Denotation = { + def recurSimple(len: Int, wrap: TermName => Name): Denotation = { val point = path.lastIndexOf('.', len - 1) - val selector = wrap(path.slice(point + 1, len)) + val selector = wrap(path.slice(point + 1, len).asTermName) val prefix = if (point > 0) recurSimple(point, identity) else if (selector.isTermName) defn.RootClass.denot diff --git a/compiler/src/dotty/tools/dotc/core/NameInfos.scala b/compiler/src/dotty/tools/dotc/core/NameInfos.scala deleted file mode 100644 index 4f2628a9e465..000000000000 --- a/compiler/src/dotty/tools/dotc/core/NameInfos.scala +++ /dev/null @@ -1,122 +0,0 @@ -package dotty.tools.dotc -package core - -import Names._ -import NameOps._ -import StdNames._ - -/** Additional info associated with a name. At a minimum its kind and - * a way to turn it into a string. - */ -abstract class NameInfo extends util.DotClass { - def kind: NameInfo.Kind - def mkString(underlying: TermName): String - def map(f: SimpleTermName => SimpleTermName): NameInfo = this -} - -object NameInfo { - - type Kind = Int - - val TermNameKind = 0 - val SelectKind = 1 - val FlattenKind = 2 - val ExpandKind = 3 - val TraitSetterKind = 4 - val DefaultGetterKind = 5 - val VariantKind = 6 - val SuperAccessorKind = 7 - val InitializerKind = 8 - val ModuleClassKind = 10 - - val qualifier: Map[String, SimpleTermName => Qualified] = - Map("." -> Select, - "$" -> Flatten, - str.EXPAND_SEPARATOR -> Expand, - str.TRAIT_SETTER_SEPARATOR -> TraitSetter) - - def definesNewName(kind: Kind) = kind <= TraitSetterKind - - /** TermNames have the lowest possible kind */ - val TermName = new NameInfo { - def kind = TermNameKind - def mkString(underlying: TermName) = underlying.toString // will cause an unsupported exception - } - - trait Qualified extends NameInfo { - def kind: Kind - def name: SimpleTermName - def separator: String - def newLikeThis(name: SimpleTermName): Qualified // TODO: should use copy instead after bootstrap - - override def map(f: SimpleTermName => SimpleTermName): NameInfo = newLikeThis(f(name)) - def mkString(underlying: TermName) = s"$underlying$separator$name" - override def toString = s"${getClass.getSimpleName}($name)" - } - - case class Select(val name: SimpleTermName) extends Qualified { - def kind = SelectKind - def separator = "." - def newLikeThis(name: SimpleTermName) = Select(name) - } - - case class Flatten(val name: SimpleTermName) extends Qualified { - def kind = FlattenKind - def separator = "$" - def newLikeThis(name: SimpleTermName) = Flatten(name) - } - - case class Expand(val name: SimpleTermName) extends Qualified { - def kind = ExpandKind - def separator = str.EXPAND_SEPARATOR - def newLikeThis(name: SimpleTermName) = Expand(name) - } - - case class TraitSetter(val name: SimpleTermName) extends Qualified { - def kind = TraitSetterKind - def separator = nme.TRAIT_SETTER_SEPARATOR.toString - 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) - } - } - - case class Variant(val num: Int) extends Numbered { - def kind = VariantKind - def mkString(underlying: TermName) = varianceToPrefix(num).toString + underlying - } - - val SuperAccessor = new NameInfo { - def kind = SuperAccessorKind - def mkString(underlying: TermName) = - underlying.mapLast(n => (nme.SUPER_PREFIX ++ n).asSimpleName).toString - override def toString = "SuperAccessor" - } - - val Initializer = new NameInfo { - def kind = InitializerKind - def mkString(underlying: TermName) = - underlying.mapLast(n => (nme.INITIALIZER_PREFIX ++ n).asSimpleName).toString - override def toString = "Initializer" - } - - val ModuleClass = new NameInfo { - def kind = ModuleClassKind - def mkString(underlying: TermName) = underlying + "$" - override def toString = "ModuleClass" - } - - /** Map between variances and name prefixes */ - val varianceToPrefix = Map(-1 -> '-', 0 -> '=', 1 -> '+') - val prefixToVariance = Map('-' -> -1, '=' -> 0, '+' -> 1) -} \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index ed6a41ac5068..b51955d9d1cf 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -4,7 +4,7 @@ package core import java.security.MessageDigest import scala.annotation.switch import scala.io.Codec -import Names._, StdNames._, Contexts._, Symbols._, Flags._ +import Names._, StdNames._, Contexts._, Symbols._, Flags._, NameExtractors._ import Decorators.PreNamedString import util.{Chars, NameTransformer} import Chars.isOperatorPart @@ -49,14 +49,14 @@ object NameOps { } } - class PrefixNameExtractor(pre: TermName, info: NameInfo) { + class PrefixNameExtractor(pre: TermName, bldr: NameExtractors.PrefixNameExtractor) { def apply(name: TermName): TermName = - if (Config.semanticNames) name.derived(info) else pre ++ name + if (Config.semanticNames) bldr(name) else pre ++ name def unapply(name: TermName): Option[TermName] = if (Config.semanticNames) name match { - case DerivedTermName(original, `info`) => Some(original) + case bldr(original) => Some(original) case _ => None } else tryUnmangle(name) @@ -66,8 +66,8 @@ object NameOps { else None } - object SuperAccessorName extends PrefixNameExtractor(nme.SUPER_PREFIX, NameInfo.SuperAccessor) - object InitializerName extends PrefixNameExtractor(nme.INITIALIZER_PREFIX, NameInfo.Initializer) + object SuperAccessorName extends PrefixNameExtractor(nme.SUPER_PREFIX, NameExtractors.SuperAccessorName) + object InitializerName extends PrefixNameExtractor(nme.INITIALIZER_PREFIX, NameExtractors.InitializerName) implicit class NameDecorator[N <: Name](val name: N) extends AnyVal { import nme._ @@ -83,12 +83,12 @@ object NameOps { def isProtectedAccessorName = name startsWith PROTECTED_PREFIX def isReplWrapperName = name.toSimpleName containsSlice INTERPRETER_IMPORT_WRAPPER def isTraitSetterName = - if (Config.semanticNames) name.is(NameInfo.TraitSetterKind) + if (Config.semanticNames) name.is(TraitSetterName) else name containsSlice TRAIT_SETTER_SEPARATOR def isSetterName = name endsWith SETTER_SUFFIX def isSingletonName = name endsWith SINGLETON_SUFFIX def isModuleClassName = - if (Config.semanticNames) name.is(NameInfo.ModuleClass.kind) + if (Config.semanticNames) name.is(ModuleClassName) else name endsWith MODULE_SUFFIX def isAvoidClashName = name endsWith AVOID_CLASH_SUFFIX def isImportName = name startsWith IMPORT @@ -138,7 +138,7 @@ object NameOps { /** Convert this module name to corresponding module class name */ def moduleClassName: TypeName = - if (Config.semanticNames) name.derived(NameInfo.ModuleClass).toTypeName + if (Config.semanticNames) name.derived(ModuleClassName).toTypeName else (name ++ tpnme.MODULE_SUFFIX).toTypeName /** Convert this module class name to corresponding source module name */ @@ -147,7 +147,7 @@ object NameOps { /** If name ends in module class suffix, drop it */ def stripModuleClassSuffix: Name = if (isModuleClassName) - if (Config.semanticNames) name.exclude(NameInfo.ModuleClass.kind) + if (Config.semanticNames) name.exclude(ModuleClassName) else name dropRight MODULE_SUFFIX.length else name @@ -166,7 +166,7 @@ object NameOps { /** The superaccessor for method with given name */ def superName: TermName = - if (Config.semanticNames) name.derived(NameInfo.SuperAccessor).toTermName + if (Config.semanticNames) SuperAccessorName(name.toTermName) else (nme.SUPER_PREFIX ++ name).toTermName /** The expanded name of `name` relative to given class `base`. @@ -182,11 +182,11 @@ object NameOps { likeTyped( if (Config.semanticNames) { def qualify(name: SimpleTermName) = - prefix.derived(NameInfo.qualifier(separator.toString)(name)) + separatorToQualified(separator.toString)(prefix.toTermName, name) name rewrite { case name: SimpleTermName => qualify(name) - case DerivedTermName(_, _: NameInfo.Qualified) => + case AnyQualifiedName(_, _) => // Note: an expanded name may itself be expanded. For example, look at javap of scala.App.initCode qualify(name.toSimpleName) } @@ -204,7 +204,7 @@ object NameOps { def unexpandedName: N = if (Config.semanticNames) likeTyped { - name.rewrite { case DerivedTermName(_, NameInfo.Expand(unexp)) => unexp } + name.rewrite { case XpandedName(_, unexp) => unexp } } else unexpandedNameOfMangled @@ -222,7 +222,7 @@ object NameOps { def expandedPrefix: N = if (Config.semanticNames) likeTyped { - name.rewrite { case DerivedTermName(prefix, NameInfo.Expand(_)) => prefix } + name.rewrite { case XpandedName(prefix, _) => prefix } } else expandedPrefixOfMangled @@ -236,7 +236,8 @@ object NameOps { if (Config.semanticNames && name.isSimple) { val unmangled = unexpandedNameOfMangled if (name eq unmangled) name - else likeTyped(expandedPrefixOfMangled.derived(NameInfo.Expand(unmangled.asSimpleName))) + else likeTyped( + XpandedName(expandedPrefixOfMangled.toTermName, unmangled.asSimpleName)) } else name @@ -440,7 +441,7 @@ object NameOps { if (name.isSetterName) { if (name.isTraitSetterName) { if (Config.semanticNames) { - val DerivedTermName(_, NameInfo.TraitSetter(original)) = name + val TraitSetterName(_, original) = name original.fieldName } else { @@ -468,7 +469,7 @@ object NameOps { * @note Default getter name suffixes start at 1, so `pos` has to be adjusted by +1 */ def defaultGetterName(pos: Int): TermName = - if (Config.semanticNames) name.derived(NameInfo.DefaultGetter(pos)) + if (Config.semanticNames) DefaultGetterName(name, pos) else { val prefix = if (name.isConstructorName) DEFAULT_GETTER_INIT else name prefix ++ DEFAULT_GETTER ++ (pos + 1).toString @@ -478,7 +479,7 @@ object NameOps { def defaultGetterToMethod: TermName = if (Config.semanticNames) name rewrite { - case DerivedTermName(methName, NameInfo.DefaultGetter(_)) => methName + case DefaultGetterName(methName, _) => methName } else defaultGetterToMethodOfMangled @@ -495,7 +496,7 @@ object NameOps { def defaultGetterIndex: Int = if (Config.semanticNames) name collect { - case DerivedTermName(methName, NameInfo.DefaultGetter(num)) => num + case DefaultGetterName(_, num) => num } getOrElse -1 else defaultGetterIndexOfMangled @@ -600,7 +601,7 @@ object NameOps { if (Config.semanticNames && name.isSimple) SuperAccessorName.tryUnmangle(name.lastPart) match { case scala.Some(original) => - name.mapLast(_ => original.asSimpleName).derived(NameInfo.SuperAccessor) + SuperAccessorName(name.mapLast(_ => original.asSimpleName)) case None => name } diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 407dc149a79a..4524f2061493 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -19,6 +19,7 @@ import java.util.HashMap //import annotation.volatile object Names { + import NameExtractors._ /** A common class for things that can be turned into names. * Instances are both names and strings, the latter via a decorator. @@ -74,8 +75,9 @@ object Names { def likeKinded(name: Name): ThisName def derived(info: NameInfo): ThisName - def exclude(kind: NameInfo.Kind): ThisName - def is(kind: NameInfo.Kind): Boolean + def derived(kind: ClassifiedNameExtractor): ThisName = derived(kind.info) + def exclude(kind: NameExtractor): ThisName + def is(kind: NameExtractor): Boolean def debugString: String def toText(printer: Printer): Text = printer.toText(this) @@ -128,7 +130,7 @@ object Names { def likeKinded(name: Name): TermName = name.toTermName - def info = NameInfo.TermName + def info: NameInfo = simpleTermNameInfo def underlying: TermName = unsupported("underlying") @sharable private var derivedNames: AnyRef /* SimpleMap | j.u.HashMap */ = @@ -169,26 +171,26 @@ object Names { * name as underlying name. */ def derived(info: NameInfo): TermName = { - val ownKind = this.info.kind - if (ownKind < info.kind || NameInfo.definesNewName(info.kind)) add(info) - else if (ownKind > info.kind) underlying.derived(info).add(this.info) + val ownTag = this.info.tag + if (ownTag < info.tag || definesNewName(info.tag)) add(info) + else if (ownTag > info.tag) underlying.derived(info).add(this.info) else { assert(info == this.info) this } } - def exclude(kind: NameInfo.Kind): TermName = { - val ownKind = this.info.kind - if (ownKind < kind || NameInfo.definesNewName(ownKind)) this - else if (ownKind > kind) underlying.exclude(kind).add(this.info) + def exclude(kind: NameExtractor): TermName = { + val ownTag = this.info.tag + if (ownTag < kind.tag || definesNewName(ownTag)) this + else if (ownTag > kind.tag) underlying.exclude(kind).add(this.info) else underlying } - def is(kind: NameInfo.Kind): Boolean = { - val ownKind = info.kind - ownKind == kind || - !NameInfo.definesNewName(ownKind) && ownKind > kind && underlying.is(kind) + def is(kind: NameExtractor): Boolean = { + val ownTag = this.info.tag + ownTag == kind.tag || + !definesNewName(ownTag) && ownTag > kind.tag && underlying.is(kind) } override def hashCode = System.identityHashCode(this) @@ -200,6 +202,9 @@ object Names { def apply(n: Int) = chrs(start + n) + //override def derived(info: NameInfo): TermName = add(info) + //override def is(kind: NameExtractor) = false + private def contains(ch: Char): Boolean = { var i = 0 while (i < length && chrs(start + i) != ch) i += 1 @@ -289,8 +294,8 @@ object Names { def likeKinded(name: Name): TypeName = name.toTypeName def derived(info: NameInfo): TypeName = toTermName.derived(info).toTypeName - def exclude(kind: NameInfo.Kind): TypeName = toTermName.exclude(kind).toTypeName - def is(kind: NameInfo.Kind) = toTermName.is(kind) + def exclude(kind: NameExtractor): TypeName = toTermName.exclude(kind).toTypeName + def is(kind: NameExtractor) = toTermName.is(kind) override def toString = toTermName.toString override def debugString = toTermName.debugString + "/T" @@ -306,7 +311,7 @@ object Names { def decode: Name = underlying.decode.derived(info.map(_.decode)) def firstPart = underlying.firstPart def lastPart = info match { - case qual: NameInfo.Qualified => qual.name + case qual: QualifiedInfo => qual.name case _ => underlying.lastPart } override def toString = info.mkString(underlying) @@ -319,26 +324,26 @@ object Names { def rewrite(f: PartialFunction[Name, Name]): ThisName = if (f.isDefinedAt(this)) likeKinded(f(this)) else info match { - case qual: NameInfo.Qualified => this + case qual: QualifiedInfo => 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 qual: QualifiedInfo => None case _ => underlying.collect(f) } def mapLast(f: SimpleTermName => SimpleTermName): ThisName = info match { - case qual: NameInfo.Qualified => underlying.derived(qual.map(f)) + case qual: QualifiedInfo => 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 qual: QualifiedInfo => underlying.mapParts(f).derived(qual.map(f)) case _ => underlying.mapParts(f).derived(info) } } @@ -506,17 +511,16 @@ 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 + if (x.tag != y.tag) x.tag - y.tag else x match { - case x: NameInfo.Qualified => + case x: QualifiedInfo => y match { - case y: NameInfo.Qualified => - val s = x.separator.compareTo(y.separator) - if (s == 0) compareSimpleNames(x.name, y.name) else s + case y: QualifiedInfo => + compareSimpleNames(x.name, y.name) } - case x: NameInfo.Numbered => + case x: NumberedInfo => y match { - case y: NameInfo.Numbered => + case y: NumberedInfo => x.num - y.num } case _ => diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index e5e2165ce2ba..70730b8411f7 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -18,6 +18,8 @@ object StdNames { object str { val EXPAND_SEPARATOR = "$$" val TRAIT_SETTER_SEPARATOR = "$_setter_$" + val SUPER_PREFIX = "super$" + val INITIALIZER_PREFIX = "initial$" } abstract class DefinedNames[N <: Name] { diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 845da95f2e7f..fa39c9782f28 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -4,7 +4,7 @@ package core import Periods._, Contexts._, Symbols._, Denotations._, Names._, NameOps._, Annotations._ import Types._, Flags._, Decorators._, DenotTransformers._, StdNames._, Scopes._, Comments._ -import NameOps._ +import NameOps._, NameExtractors._ import Scopes.Scope import collection.mutable import collection.immutable.BitSet @@ -406,14 +406,14 @@ object SymDenotations { } var prefix = encl.fullNameSeparated(separator) val fn = - if (Config.semanticNames && NameInfo.qualifier.contains(sep)) { + if (Config.semanticNames && separatorToQualified.contains(sep)) { if (sep == "$") // duplicate scalac's behavior: don't write a double '$$' for module class members. - prefix = prefix.exclude(NameInfo.ModuleClassKind) + prefix = prefix.exclude(ModuleClassName) name rewrite { case n: SimpleTermName => val n1 = if (filler.isEmpty) n else termName(filler ++ n) - prefix.derived(NameInfo.qualifier(sep)(n1)) + separatorToQualified(sep)(prefix.toTermName, n1) } } else { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index 61a2c7fc5f51..e82a9b618e79 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala @@ -4,8 +4,10 @@ package core package tasty import collection.mutable -import Names.{Name, chrs, DerivedTermName, SimpleTermName} -import Decorators._, NameOps._ +import Names.{Name, chrs, SimpleTermName} +import NameOps.NameDecorator +import NameExtractors._ +import Decorators._ import TastyBuffer._ import scala.io.Codec import TastyName._ @@ -27,20 +29,19 @@ class NameBuffer extends TastyBuffer(10000) { def nameIndex(name: Name, toTasty: SimpleTermName => TastyName): NameRef = { val tname = name.toTermName match { - case DerivedTermName(name1, NameInfo.ModuleClass) => + case ModuleClassName(name1) => ModuleClass(nameIndex(name1, toTasty)) - case DerivedTermName(name1, NameInfo.SuperAccessor) => + case SuperAccessorName(name1) => SuperAccessor(nameIndex(name1, toTasty)) - 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 DerivedTermName(prefix, NameInfo.DefaultGetter(num)) => + case QualifiedName(prefix, selector) => + Qualified(nameIndex(prefix, toTasty), nameIndex(selector)) + case FlattenedName(prefix, selector) => + Flattened(nameIndex(prefix, toTasty), nameIndex(selector)) + case XpandedName(prefix, selector) => + Expanded(nameIndex(prefix, toTasty), nameIndex(selector)) + case DefaultGetterName(prefix, num) => DefaultGetter(nameIndex(prefix, toTasty), num) - case DerivedTermName(prefix, NameInfo.Variant(sign)) => + case VariantName(prefix, sign) => Variant(nameIndex(prefix, toTasty), sign) case name1 => if (name1.isShadowedName) Shadowed(nameIndex(name1.revertShadowed, toTasty)) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index e73d6ed0d46c..d25adfd2983d 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -9,7 +9,7 @@ import TastyFormat._ import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annotations._, StdNames.tpnme, NameOps._ import collection.mutable import typer.Inliner -import NameOps._ +import NameOps._, NameExtractors._ import StdNames.nme import TastyBuffer._ import TypeApplications._ @@ -62,13 +62,13 @@ class TreePickler(pickler: TastyPickler) { private def pickleName(sym: Symbol)(implicit ctx: Context): Unit = { val nameRef = if (Config.semanticNames) { - if (sym is Flags.ExpandedName) assert(sym.name.is(NameInfo.ExpandKind)) + if (sym is Flags.ExpandedName) assert(sym.name.is(XpandedName)) nameIndex(sym.name) } else { def encodeSuper(name: Name): TastyName.NameRef = if (sym is Flags.SuperAccessor) { - val SuperAccessorName(n) = name + val NameOps.SuperAccessorName(n) = name nameIndex(TastyName.SuperAccessor(nameIndex(n))) } else nameIndex(name) if (sym is Flags.ExpandedName) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index e83a6f195dc7..f74cdc36a482 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -5,6 +5,7 @@ package tasty import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._ import StdNames._, Denotations._, Flags._, Constants._, Annotations._ +import NameExtractors._ import util.Positions._ import ast.{tpd, Trees, untpd} import Trees._ @@ -91,11 +92,11 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle case ModuleClass(original) => toTermName(original).moduleClassName.toTermName case SuperAccessor(accessed) => toTermName(accessed).superName case DefaultGetter(meth, num) => toTermName(meth).defaultGetterName(num) - case Variant(original, sign) => toTermName(original).derived(NameInfo.Variant(sign)) + case Variant(original, sign) => VariantName(toTermName(original), sign) } private def qualTermName(qual: NameRef, name: NameRef, sep: String) = - toTermName(qual).derived(NameInfo.qualifier(sep)(toTermName(name).asSimpleName)) + separatorToQualified(sep)(toTermName(qual), toTermName(name).asSimpleName) def toTermName(ref: NameRef): TermName = toTermName(tastyName(ref)) def toTypeName(ref: NameRef): TypeName = toTermName(ref).toTypeName From 0bb5bb3ca37b851e47f9388f5bf89c3d2a18351f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Mar 2017 16:02:08 +0200 Subject: [PATCH 25/68] Eliminate TastyNames --- .../src/dotty/tools/dotc/core/StdNames.scala | 1 + .../dotc/core/tasty/DottyUnpickler.scala | 6 +- .../tools/dotc/core/tasty/NameBuffer.scala | 94 +++++++------------ .../tools/dotc/core/tasty/TastyBuffer.scala | 3 + .../tools/dotc/core/tasty/TastyName.scala | 32 ------- .../tools/dotc/core/tasty/TastyPickler.scala | 5 +- .../tools/dotc/core/tasty/TastyPrinter.scala | 26 ++--- .../tools/dotc/core/tasty/TastyReader.scala | 1 - .../dotc/core/tasty/TastyUnpickler.scala | 60 +++++++----- .../tools/dotc/core/tasty/TreePickler.scala | 33 ++----- .../tools/dotc/core/tasty/TreeUnpickler.scala | 65 +++---------- 11 files changed, 107 insertions(+), 219 deletions(-) delete mode 100644 compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 70730b8411f7..bf404d63024d 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -20,6 +20,7 @@ object StdNames { val TRAIT_SETTER_SEPARATOR = "$_setter_$" val SUPER_PREFIX = "super$" val INITIALIZER_PREFIX = "initial$" + val SHADOWED_PREFIX = "(shadowed)" } abstract class DefinedNames[N <: Name] { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala index 2c93819d5be9..28916a781921 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala @@ -19,12 +19,12 @@ object DottyUnpickler { class TreeSectionUnpickler(posUnpickler: Option[PositionUnpickler]) extends SectionUnpickler[TreeUnpickler]("ASTs") { - def unpickle(reader: TastyReader, tastyName: TastyName.Table) = - new TreeUnpickler(reader, tastyName, posUnpickler) + def unpickle(reader: TastyReader, nameAtRef: NameTable) = + new TreeUnpickler(reader, nameAtRef, posUnpickler) } class PositionsSectionUnpickler extends SectionUnpickler[PositionUnpickler]("Positions") { - def unpickle(reader: TastyReader, tastyName: TastyName.Table) = + def unpickle(reader: TastyReader, nameAtRef: NameTable) = new PositionUnpickler(reader) } } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index e82a9b618e79..0101ff25d96d 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala @@ -4,63 +4,38 @@ package core package tasty import collection.mutable -import Names.{Name, chrs, SimpleTermName} +import Names.{Name, chrs, SimpleTermName, DerivedTermName} import NameOps.NameDecorator import NameExtractors._ import Decorators._ import TastyBuffer._ import scala.io.Codec -import TastyName._ import TastyFormat._ class NameBuffer extends TastyBuffer(10000) { import NameBuffer._ - private val nameRefs = new mutable.LinkedHashMap[TastyName, NameRef] + private val nameRefs = new mutable.LinkedHashMap[Name, NameRef] - def nameIndex(name: TastyName): NameRef = nameRefs.get(name) match { - case Some(ref) => - ref - case None => - val ref = NameRef(nameRefs.size) - nameRefs(name) = ref - ref - } - - def nameIndex(name: Name, toTasty: SimpleTermName => TastyName): NameRef = { - val tname = name.toTermName match { - case ModuleClassName(name1) => - ModuleClass(nameIndex(name1, toTasty)) - case SuperAccessorName(name1) => - SuperAccessor(nameIndex(name1, toTasty)) - case QualifiedName(prefix, selector) => - Qualified(nameIndex(prefix, toTasty), nameIndex(selector)) - case FlattenedName(prefix, selector) => - Flattened(nameIndex(prefix, toTasty), nameIndex(selector)) - case XpandedName(prefix, selector) => - Expanded(nameIndex(prefix, toTasty), nameIndex(selector)) - case DefaultGetterName(prefix, num) => - DefaultGetter(nameIndex(prefix, toTasty), num) - case VariantName(prefix, sign) => - Variant(nameIndex(prefix, toTasty), sign) - 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 = { - 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) + def nameIndex(name: Name): NameRef = { + val name1 = name.toTermName + nameRefs.get(name1) match { + case Some(ref) => + ref + case None => + name1 match { + case SignedName(original, Signature(params, result)) => + nameIndex(original); nameIndex(result); params.foreach(nameIndex) + case AnyQualifiedName(prefix, info) => + nameIndex(prefix); nameIndex(info.name) + case DerivedTermName(prefix, _) => + nameIndex(prefix) + case _ => + } + val ref = NameRef(nameRefs.size) + nameRefs(name1) = ref + ref + } } private def withLength(op: => Unit, lengthWidth: Int = 1): Unit = { @@ -71,43 +46,44 @@ class NameBuffer extends TastyBuffer(10000) { putNat(lengthAddr, length, lengthWidth) } - def writeNameRef(ref: NameRef) = writeNat(ref.index) + def writeNameRef(ref: NameRef): Unit = writeNat(ref.index) + def writeNameRef(name: Name): Unit = writeNameRef(nameRefs(name.toTermName)) - def pickleName(name: TastyName): Unit = name match { - case Simple(name) => + def pickleNameContents(name: Name): Unit = name.toTermName match { + case name: SimpleTermName => val bytes = if (name.length == 0) new Array[Byte](0) else Codec.toUTF8(chrs, name.start, name.length) writeByte(UTF8) writeNat(bytes.length) writeBytes(bytes, bytes.length) - case Qualified(qualified, selector) => + case QualifiedName(qualified, selector) => writeByte(QUALIFIED) withLength { writeNameRef(qualified); writeNameRef(selector) } - case Flattened(qualified, selector) => + case FlattenedName(qualified, selector) => writeByte(FLATTENED) withLength { writeNameRef(qualified); writeNameRef(selector) } - case Expanded(prefix, original) => + case XpandedName(prefix, original) => writeByte(EXPANDED) withLength { writeNameRef(prefix); writeNameRef(original) } - case Signed(original, params, result) => + case SignedName(original, Signature(params, result)) => writeByte(SIGNED) withLength( { writeNameRef(original); writeNameRef(result); params.foreach(writeNameRef) }, if ((params.length + 2) * maxIndexWidth <= maxNumInByte) 1 else 2) - case ModuleClass(module) => + case ModuleClassName(module) => writeByte(OBJECTCLASS) withLength { writeNameRef(module) } - case SuperAccessor(accessed) => + case SuperAccessorName(accessed) => writeByte(SUPERACCESSOR) withLength { writeNameRef(accessed) } - case DefaultGetter(method, paramNumber) => + case DefaultGetterName(method, paramNumber) => writeByte(DEFAULTGETTER) withLength { writeNameRef(method); writeNat(paramNumber) } - case Shadowed(original) => + case ShadowedName(original) => writeByte(SHADOWED) withLength { writeNameRef(original) } - case Variant(original, sign) => + case VariantName(original, sign) => writeByte(VARIANT) withLength { writeNameRef(original); writeNat(sign + 1) } } @@ -117,7 +93,7 @@ class NameBuffer extends TastyBuffer(10000) { for ((name, ref) <- nameRefs) { assert(ref.index == i) i += 1 - pickleName(name) + pickleNameContents(name) } } } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyBuffer.scala index 13bc95028e22..40782f5341ea 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyBuffer.scala @@ -26,6 +26,9 @@ object TastyBuffer { * the value of 4 gives a maximal array size of 256M. */ final val AddrWidth = 4 + + /** An address referring to a serialized name */ + case class NameRef(index: Int) extends AnyVal } import TastyBuffer._ diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala deleted file mode 100644 index 769ecfbfceba..000000000000 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala +++ /dev/null @@ -1,32 +0,0 @@ -package dotty.tools -package dotc -package core -package tasty - -import core.Names.SimpleTermName -import collection.mutable - -abstract class TastyName - -object TastyName { - - case class NameRef(index: Int) extends AnyVal - - case class Simple(name: SimpleTermName) extends TastyName - case class Qualified(qualified: NameRef, selector: 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 - case class Shadowed(original: NameRef) extends TastyName - case class Variant(original: NameRef, sign: Int) extends TastyName - - class Table extends (NameRef => TastyName) { - private val names = new mutable.ArrayBuffer[TastyName] - def add(name: TastyName) = names += name - def apply(ref: NameRef) = names(ref.index) - def contents: Iterable[TastyName] = names - } -} diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala index c844d522eaa9..cc2e4dd58a24 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala @@ -9,10 +9,11 @@ import TastyBuffer._ import java.util.UUID import core.Symbols.Symbol import ast.tpd +import Decorators._ class TastyPickler { - private val sections = new mutable.ArrayBuffer[(TastyName.NameRef, TastyBuffer)] + private val sections = new mutable.ArrayBuffer[(NameRef, TastyBuffer)] val uuid = UUID.randomUUID() private val headerBuffer = { @@ -28,7 +29,7 @@ class TastyPickler { val nameBuffer = new NameBuffer def newSection(name: String, buf: TastyBuffer) = - sections += ((nameBuffer.nameIndex(name), buf)) + sections += ((nameBuffer.nameIndex(name.toTermName), buf)) def assembleParts(): Array[Byte] = { def lengthWithLength(buf: TastyBuffer) = { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala index ce3722ff145a..a5c87088176c 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala @@ -4,34 +4,24 @@ package tasty import Contexts._, Decorators._ import printing.Texts._ -import TastyName._ +import Names.Name import StdNames._ import TastyUnpickler._ -import TastyBuffer.Addr +import TastyBuffer.{Addr, NameRef} import util.Positions.{Position, offsetToInt} import collection.mutable class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) { val unpickler = new TastyUnpickler(bytes) - import unpickler.{tastyName, unpickle} + import unpickler.{nameAtRef, unpickle} - def nameToString(name: TastyName): String = name match { - case Simple(name) => name.toString - case Qualified(qual, name) => nameRefToString(qual) + "." + nameRefToString(name) - case Signed(original, params, result) => - i"${nameRefToString(original)}@${params.map(nameRefToString)}%,%:${nameRefToString(result)}" - case Expanded(prefix, original) => s"$prefix${nme.EXPAND_SEPARATOR}$original" - case ModuleClass(original) => nameRefToString(original) + "/MODULECLASS" - case SuperAccessor(accessed) => nameRefToString(accessed) + "/SUPERACCESSOR" - case DefaultGetter(meth, num) => nameRefToString(meth) + "/DEFAULTGETTER" + num - case Shadowed(original) => nameRefToString(original) + "/SHADOWED" - } + def nameToString(name: Name): String = name.debugString - def nameRefToString(ref: NameRef): String = nameToString(tastyName(ref)) + def nameRefToString(ref: NameRef): String = nameToString(nameAtRef(ref)) def printNames() = - for ((name, idx) <- tastyName.contents.zipWithIndex) { + for ((name, idx) <- nameAtRef.contents.zipWithIndex) { val index = "%4d: ".format(idx) println(index + nameToString(name)) } @@ -46,7 +36,7 @@ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) { class TreeSectionUnpickler extends SectionUnpickler[Unit]("ASTs") { import TastyFormat._ - def unpickle(reader: TastyReader, tastyName: TastyName.Table): Unit = { + def unpickle(reader: TastyReader, tastyName: NameTable): Unit = { import reader._ var indent = 0 def newLine() = { @@ -116,7 +106,7 @@ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) { } class PositionSectionUnpickler extends SectionUnpickler[Unit]("Positions") { - def unpickle(reader: TastyReader, tastyName: TastyName.Table): Unit = { + def unpickle(reader: TastyReader, tastyName: NameTable): Unit = { print(s"${reader.endAddr.index - reader.currentAddr.index}") val positions = new PositionUnpickler(reader).positions println(s" position bytes:") diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyReader.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyReader.scala index e583c47939ea..af5e78891b89 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyReader.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyReader.scala @@ -4,7 +4,6 @@ package core package tasty import TastyBuffer._ -import TastyName.NameRef import collection.mutable /** A byte array buffer that can be filled with bytes or natural numbers in TASTY format, diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala index e6b43e6b4334..6dd22db88126 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala @@ -4,14 +4,23 @@ package tasty import scala.collection.mutable import TastyFormat._ -import Names.{Name, termName} +import TastyBuffer.NameRef +import Names.{Name, TermName, termName} +import NameExtractors._ import java.util.UUID object TastyUnpickler { class UnpickleException(msg: String) extends Exception(msg) abstract class SectionUnpickler[R](val name: String) { - def unpickle(reader: TastyReader, tastyName: TastyName.Table): R + def unpickle(reader: TastyReader, nameAtRef: NameTable): R + } + + class NameTable extends (NameRef => TermName) { + private val names = new mutable.ArrayBuffer[TermName] + def add(name: TermName) = names += name + def apply(ref: NameRef) = names(ref.index) + def contents: Iterable[TermName] = names } } @@ -23,18 +32,15 @@ class TastyUnpickler(reader: TastyReader) { def this(bytes: Array[Byte]) = this(new TastyReader(bytes)) private val sectionReader = new mutable.HashMap[String, TastyReader] - val tastyName = new TastyName.Table + val nameAtRef = new NameTable - def check(cond: Boolean, msg: => String) = + private def check(cond: Boolean, msg: => String) = if (!cond) throw new UnpickleException(msg) - def readString(): String = { - val TastyName.Simple(name) = tastyName(readNameRef()) - name.toString - } + private def readName(): TermName = nameAtRef(readNameRef()) + private def readString(): String = readName().toString - def readName(): TastyName = { - import TastyName._ + private def readNameContents(): TermName = { val tag = readByte() val length = readNat() val start = currentAddr @@ -42,28 +48,30 @@ class TastyUnpickler(reader: TastyReader) { val result = tag match { case UTF8 => goto(end) - Simple(termName(bytes, start.index, length)) + termName(bytes, start.index, length) case QUALIFIED => - Qualified(readNameRef(), readNameRef()) + QualifiedName(readName(), readName().asSimpleName) case FLATTENED => - Flattened(readNameRef(), readNameRef()) + FlattenedName(readName(), readName().asSimpleName) case EXPANDED => - Expanded(readNameRef(), readNameRef()) + XpandedName(readName(), readName().asSimpleName) case SIGNED => - val original = readNameRef() - val result = readNameRef() - val params = until(end)(readNameRef()) - Signed(original, params, result) + val original = readName() + val result = readName().toTypeName + val params = until(end)(readName().toTypeName) + var sig = Signature(params, result) + if (sig == Signature.NotAMethod) sig = Signature.NotAMethod + SignedName(original, sig) case OBJECTCLASS => - ModuleClass(readNameRef()) + ModuleClassName(readName()) case SUPERACCESSOR => - SuperAccessor(readNameRef()) + SuperAccessorName(readName()) case DEFAULTGETTER => - DefaultGetter(readNameRef(), readNat()) + DefaultGetterName(readName(), readNat()) case SHADOWED => - Shadowed(readNameRef()) + ShadowedName(readName()) case VARIANT => - Variant(readNameRef(), readNat() - 1) + VariantName(readName(), readNat() - 1) } assert(currentAddr == end, s"bad name $result $start $currentAddr $end") result @@ -81,10 +89,10 @@ class TastyUnpickler(reader: TastyReader) { new UUID(readUncompressedLong(), readUncompressedLong()) } - val uuid = readHeader() + private val uuid = readHeader() locally { - until(readEnd()) { tastyName.add(readName()) } + until(readEnd()) { nameAtRef.add(readNameContents()) } while (!isAtEnd) { val secName = readString() val secEnd = readEnd() @@ -95,5 +103,5 @@ class TastyUnpickler(reader: TastyReader) { def unpickle[R](sec: SectionUnpickler[R]): Option[R] = for (reader <- sectionReader.get(sec.name)) yield - sec.unpickle(reader, tastyName) + sec.unpickle(reader, nameAtRef) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index d25adfd2983d..d1f2a3766765 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -19,7 +19,7 @@ class TreePickler(pickler: TastyPickler) { val buf = new TreeBuffer pickler.newSection("ASTs", buf) import buf._ - import pickler.nameBuffer.{nameIndex, fullNameIndex} + import pickler.nameBuffer.nameIndex import ast.tpd._ private val symRefs = new mutable.HashMap[Symbol, Addr] @@ -53,11 +53,8 @@ class TreePickler(pickler: TastyPickler) { } private def pickleName(name: Name): Unit = writeNat(nameIndex(name).index) - private def pickleName(name: TastyName): Unit = writeNat(nameIndex(name).index) - private def pickleNameAndSig(name: Name, sig: Signature) = { - val Signature(params, result) = sig - pickleName(TastyName.Signed(nameIndex(name), params.map(fullNameIndex), fullNameIndex(result))) - } + private def pickleNameAndSig(name: Name, sig: Signature) = + pickleName(SignedName(name.toTermName, sig)) private def pickleName(sym: Symbol)(implicit ctx: Context): Unit = { val nameRef = @@ -65,19 +62,7 @@ class TreePickler(pickler: TastyPickler) { if (sym is Flags.ExpandedName) assert(sym.name.is(XpandedName)) nameIndex(sym.name) } - else { - def encodeSuper(name: Name): TastyName.NameRef = - if (sym is Flags.SuperAccessor) { - val NameOps.SuperAccessorName(n) = name - nameIndex(TastyName.SuperAccessor(nameIndex(n))) - } else nameIndex(name) - if (sym is Flags.ExpandedName) - nameIndex( - TastyName.Expanded( - nameIndex(sym.name.expandedPrefix), - encodeSuper(sym.name.unexpandedName))) - else encodeSuper(sym.name) - } + else ??? writeNat(nameRef.index) } @@ -132,7 +117,7 @@ class TreePickler(pickler: TastyPickler) { writeLongInt(java.lang.Double.doubleToRawLongBits(c.doubleValue)) case StringTag => writeByte(STRINGconst) - writeNat(nameIndex(c.stringValue).index) + pickleName(c.stringValue.toTermName) case NullTag => writeByte(NULLconst) case ClazzTag => @@ -184,7 +169,7 @@ class TreePickler(pickler: TastyPickler) { } if (sym.is(Flags.Package)) { writeByte(if (tpe.isType) TYPEREFpkg else TERMREFpkg) - pickleName(qualifiedName(sym)) + pickleName(sym.fullName) } else if (sym is Flags.BindDefinedType) { registerDef(sym) @@ -284,7 +269,7 @@ class TreePickler(pickler: TastyPickler) { def picklePackageRef(pkg: Symbol)(implicit ctx: Context): Unit = { writeByte(TERMREFpkg) - pickleName(qualifiedName(pkg)) + pickleName(pkg.fullName) } def pickleMethodic(tag: Int, tpe: LambdaType)(implicit ctx: Context) = { @@ -581,10 +566,6 @@ class TreePickler(pickler: TastyPickler) { pickleName(id.name) } - def qualifiedName(sym: Symbol)(implicit ctx: Context): TastyName = - 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 = { import Flags._ val flags = sym.flags diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index f74cdc36a482..11c04e2b47e3 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -23,9 +23,8 @@ import config.Config * @param tastyName the nametable * @param posUNpicklerOpt the unpickler for positions, if it exists */ -class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpicklerOpt: Option[PositionUnpickler]) { +class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpicklerOpt: Option[PositionUnpickler]) { import TastyFormat._ - import TastyName._ import TreeUnpickler._ import tpd._ @@ -76,31 +75,6 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle new TreeReader(reader).readTopLevel()(ctx.addMode(Mode.AllowDependentFunctions)) } - def toTermName(tname: TastyName): TermName = tname match { - case Simple(name) => 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 ModuleClass(original) => toTermName(original).moduleClassName.toTermName - case SuperAccessor(accessed) => toTermName(accessed).superName - case DefaultGetter(meth, num) => toTermName(meth).defaultGetterName(num) - case Variant(original, sign) => VariantName(toTermName(original), sign) - } - - private def qualTermName(qual: NameRef, name: NameRef, sep: String) = - separatorToQualified(sep)(toTermName(qual), toTermName(name).asSimpleName) - - def toTermName(ref: NameRef): TermName = toTermName(tastyName(ref)) - def toTypeName(ref: NameRef): TypeName = toTermName(ref).toTypeName - class Completer(owner: Symbol, reader: TastyReader) extends LazyType { import reader._ def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { @@ -178,17 +152,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle else tag } - def readName(): TermName = toTermName(readNameRef()) - - def readNameSplitSig()(implicit ctx: Context): Any /* TermName | (TermName, Signature) */ = - tastyName(readNameRef()) match { - case Signed(original, params, result) => - var sig = Signature(params map toTypeName, toTypeName(result)) - if (sig == Signature.NotAMethod) sig = Signature.NotAMethod - (toTermName(original), sig) - case name => - toTermName(name) - } + def readName(): TermName = nameAtRef(readNameRef()) // ------ Reading types ----------------------------------------------------- @@ -318,9 +282,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle val name = readName().toTypeName TypeRef(readType(), name) case TERMREF => - readNameSplitSig() match { - case name: TermName => TermRef.all(readType(), name) - case (name: TermName, sig: Signature) => TermRef.withSig(readType(), name, sig) + readName() match { + case SignedName(name, sig) => TermRef.withSig(readType(), name, sig) + case name => TermRef.all(readType(), name) } case THIS => ThisType.raw(readType().asInstanceOf[TypeRef]) @@ -451,8 +415,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle val start = currentAddr val tag = readByte() val end = readEnd() - val rawName = tastyName(readNameRef()) - var name: Name = toTermName(rawName) + var name: Name = readName() if (tag == TYPEDEF || tag == TYPEPARAM) name = name.toTypeName skipParams() val ttag = nextUnsharedTag @@ -464,13 +427,11 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle val rhsIsEmpty = noRhs(end) if (!rhsIsEmpty) skipTree() val (givenFlags, annots, privateWithin) = readModifiers(end) - def nameFlags(tname: TastyName): FlagSet = tname match { - case TastyName.Expanded(_, original) => ExpandedName | nameFlags(tastyName(original)) - case TastyName.SuperAccessor(original) => Flags.SuperAccessor | nameFlags(tastyName(original)) - case _ => EmptyFlags - } + val nameFlags = + (if (name.is(XpandedName)) ExpandedName else EmptyFlags) | + (if (name.is(NameExtractors.SuperAccessorName)) SuperAccessor else EmptyFlags) pickling.println(i"creating symbol $name at $start with flags $givenFlags") - val flags = normalizeFlags(tag, givenFlags | nameFlags(rawName), name, isAbsType, rhsIsEmpty) + val flags = normalizeFlags(tag, givenFlags | nameFlags, name, isAbsType, rhsIsEmpty) def adjustIfModule(completer: LazyType) = if (flags is Module) ctx.adjustModuleCompleter(completer, name) else completer val sym = @@ -918,9 +879,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle case SELECT => def readRest(name: Name, sig: Signature) = completeSelect(name, TermRef.withSig(_, name.asTermName, sig)) - readNameSplitSig match { - case name: Name => readRest(name, Signature.NotAMethod) - case (name: Name, sig: Signature) => readRest(name, sig) + readName() match { + case SignedName(name, sig) => readRest(name, sig) + case name => readRest(name, Signature.NotAMethod) } case SELECTtpt => val name = readName().toTypeName From 0ccc76eeb5a0706478087364a380f67ae69759cc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Mar 2017 16:43:58 +0200 Subject: [PATCH 26/68] Add missing file --- .../tools/dotc/core/NameExtractors.scala | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 compiler/src/dotty/tools/dotc/core/NameExtractors.scala diff --git a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala new file mode 100644 index 000000000000..2ffbf51e1d11 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala @@ -0,0 +1,148 @@ +package dotty.tools.dotc +package core + +import Names._ +import NameOps._ +import StdNames._ +import util.DotClass + +object NameExtractors { + + abstract class NameInfo extends DotClass { + def tag: Int + def mkString(underlying: TermName): String + def map(f: SimpleTermName => SimpleTermName): NameInfo = this + } + + val simpleTermNameInfo = new NameInfo { + def tag = 0 + def mkString(underlying: TermName): String = unsupported("mkString") + } + + abstract class NameExtractor(val tag: Int) extends DotClass { self => + def mkString(underlying: TermName, info: ThisInfo): String + def infoString: String + type ThisInfo <: Info + class Info extends NameInfo { this: ThisInfo => + def tag = self.tag + def mkString(underlying: TermName) = self.mkString(underlying, this) + override def toString = infoString + } + } + + abstract class ClassifiedNameExtractor(tag: Int, val infoString: String) extends NameExtractor(tag) { + type ThisInfo = Info + val info = new Info + def apply(qual: TermName) = + qual.derived(info) + def unapply(name: DerivedTermName): Option[TermName] = name match { + case DerivedTermName(underlying, `info`) => Some(underlying) + case _ => None + } + } + + class PrefixNameExtractor(tag: Int, prefix: String, infoString: String) extends ClassifiedNameExtractor(tag, infoString) { + def mkString(underlying: TermName, info: ThisInfo) = prefix ++ underlying + } + + class SuffixNameExtractor(tag: Int, suffix: String, infoString: String) extends ClassifiedNameExtractor(tag, infoString) { + def mkString(underlying: TermName, info: ThisInfo) = underlying.toString ++ suffix + } + + trait QualifiedInfo extends NameInfo { + val name: SimpleTermName + } + + abstract class QualifiedNameExtractor(tag: Int, val separator: String, val infoString: String) extends NameExtractor(tag) { + type ThisInfo = QualInfo + case class QualInfo(val name: SimpleTermName) extends Info with QualifiedInfo { + override def map(f: SimpleTermName => SimpleTermName): NameInfo = new QualInfo(f(name)) + override def toString = s"$infoString $name" + } + def apply(qual: TermName, name: SimpleTermName) = + qual.derived(new QualInfo(name)) + def unapply(name: DerivedTermName): Option[(TermName, SimpleTermName)] = name match { + case DerivedTermName(qual, info: this.QualInfo) => Some((qual, info.name)) + case _ => None + } + def mkString(underlying: TermName, info: ThisInfo) = + s"$underlying$separator${info.name}" + } + + object AnyQualifiedName { + def unapply(name: DerivedTermName): Option[(TermName, QualifiedNameExtractor # QualInfo)] = name match { + case DerivedTermName(qual, info: QualifiedNameExtractor # QualInfo) => + Some((name.underlying, info)) + case _ => None + } + } + + trait NumberedInfo { + def num: Int + } + + abstract class NumberedNameExtractor(tag: Int, val infoString: String) extends NameExtractor(tag) { + type ThisInfo = NumberedInfo + case class NumberedInfo(val num: Int) extends Info with NameExtractors.NumberedInfo { + override def toString = s"$infoString $num" + } + def apply(qual: TermName, num: Int) = + qual.derived(new NumberedInfo(num)) + def unapply(name: DerivedTermName): Option[(TermName, Int)] = name match { + case DerivedTermName(underlying, info: this.NumberedInfo) => Some((underlying, info.num)) + case _ => None + } + } + + object QualifiedName extends QualifiedNameExtractor(1, ".", "Qualified") + object FlattenedName extends QualifiedNameExtractor(2, "$", "Flattened") + object XpandedName extends QualifiedNameExtractor(3, str.EXPAND_SEPARATOR, "Expanded") + object TraitSetterName extends QualifiedNameExtractor(4, str.TRAIT_SETTER_SEPARATOR, "TraitSetter") + + object DefaultGetterName extends NumberedNameExtractor(5, "DefaultGetter") { + def mkString(underlying: TermName, info: ThisInfo) = { + val prefix = if (underlying.isConstructorName) nme.DEFAULT_GETTER_INIT else underlying + prefix.toString + nme.DEFAULT_GETTER + (info.num + 1) + } + } + + object VariantName extends NumberedNameExtractor(6, "Variant") { + val varianceToPrefix = Map(-1 -> '-', 0 -> '=', 1 -> '+') + val prefixToVariance = Map('-' -> -1, '=' -> 0, '+' -> 1) + def mkString(underlying: TermName, info: ThisInfo) = { + varianceToPrefix(info.num).toString + underlying + } + } + + val SuperAccessorName = new PrefixNameExtractor(7, str.SUPER_PREFIX, "SuperAccessor") + val InitializerName = new PrefixNameExtractor(8, str.INITIALIZER_PREFIX, "Initializer") + val ShadowedName = new PrefixNameExtractor(9, str.SHADOWED_PREFIX, "Shadowed") + val ModuleClassName = new SuffixNameExtractor(10, "$", "ModuleClass") + + object SignedName extends NameExtractor(63) { + + /** @param parts resultSig followed by paramsSig */ + case class SignedInfo(sig: Signature) extends Info { + override def toString = s"$infoString $sig" + } + type ThisInfo = SignedInfo + + def apply(qual: TermName, sig: Signature) = + qual.derived(new SignedInfo(sig)) + def unapply(name: DerivedTermName): Option[(TermName, Signature)] = name match { + case DerivedTermName(underlying, info: SignedInfo) => Some((underlying, info.sig)) + case _ => None + } + + def mkString(underlying: TermName, info: ThisInfo): String = unsupported("mkString") + def infoString: String = "Signed" + } + + def definesNewName(tag: Int) = tag <= TraitSetterName.tag + + val separatorToQualified: Map[String, QualifiedNameExtractor] = + Map("." -> QualifiedName, + "$" -> FlattenedName, + str.EXPAND_SEPARATOR -> XpandedName, + str.TRAIT_SETTER_SEPARATOR -> TraitSetterName) +} \ No newline at end of file From c599f7a693dbc363962d3f17f5eab5222136857f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Mar 2017 17:09:42 +0200 Subject: [PATCH 27/68] Drop Config.semanticNames option We now handle only semantic names. Also, name extractor tags and TASTY name tags are now aligned. --- .../src/dotty/tools/dotc/config/Config.scala | 2 - .../tools/dotc/core/NameExtractors.scala | 23 +-- .../src/dotty/tools/dotc/core/NameOps.scala | 145 +++++------------- .../tools/dotc/core/SymDenotations.scala | 4 +- .../dotc/core/classfile/ClassfileParser.scala | 3 +- .../tools/dotc/core/tasty/NameBuffer.scala | 63 ++++---- .../tools/dotc/core/tasty/TastyFormat.scala | 15 +- .../tools/dotc/core/tasty/TreePickler.scala | 12 +- .../dotty/tools/dotc/transform/Mixin.scala | 1 + .../tools/dotc/transform/ResolveSuper.scala | 11 +- .../src/dotty/tools/dotc/typer/Typer.scala | 3 +- 11 files changed, 97 insertions(+), 185 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index a225b3019180..46b1896f1add 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -10,8 +10,6 @@ object Config { final val checkCacheMembersNamed = false - final val semanticNames = true - /** When updating a constraint bound, check that the constrained parameter * does not appear at the top-level of either of its bounds. */ diff --git a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala index 2ffbf51e1d11..ec7f00d326de 100644 --- a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala +++ b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala @@ -5,6 +5,7 @@ import Names._ import NameOps._ import StdNames._ import util.DotClass +import tasty.TastyFormat._ object NameExtractors { @@ -15,7 +16,7 @@ object NameExtractors { } val simpleTermNameInfo = new NameInfo { - def tag = 0 + def tag = UTF8 def mkString(underlying: TermName): String = unsupported("mkString") } @@ -94,19 +95,19 @@ object NameExtractors { } } - object QualifiedName extends QualifiedNameExtractor(1, ".", "Qualified") - object FlattenedName extends QualifiedNameExtractor(2, "$", "Flattened") - object XpandedName extends QualifiedNameExtractor(3, str.EXPAND_SEPARATOR, "Expanded") - object TraitSetterName extends QualifiedNameExtractor(4, str.TRAIT_SETTER_SEPARATOR, "TraitSetter") + object QualifiedName extends QualifiedNameExtractor(QUALIFIED, ".", "Qualified") + object FlattenedName extends QualifiedNameExtractor(FLATTENED, "$", "Flattened") + object XpandedName extends QualifiedNameExtractor(EXPANDED, str.EXPAND_SEPARATOR, "Expanded") + object TraitSetterName extends QualifiedNameExtractor(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR, "TraitSetter") - object DefaultGetterName extends NumberedNameExtractor(5, "DefaultGetter") { + object DefaultGetterName extends NumberedNameExtractor(DEFAULTGETTER, "DefaultGetter") { def mkString(underlying: TermName, info: ThisInfo) = { val prefix = if (underlying.isConstructorName) nme.DEFAULT_GETTER_INIT else underlying prefix.toString + nme.DEFAULT_GETTER + (info.num + 1) } } - object VariantName extends NumberedNameExtractor(6, "Variant") { + object VariantName extends NumberedNameExtractor(VARIANT, "Variant") { val varianceToPrefix = Map(-1 -> '-', 0 -> '=', 1 -> '+') val prefixToVariance = Map('-' -> -1, '=' -> 0, '+' -> 1) def mkString(underlying: TermName, info: ThisInfo) = { @@ -114,10 +115,10 @@ object NameExtractors { } } - val SuperAccessorName = new PrefixNameExtractor(7, str.SUPER_PREFIX, "SuperAccessor") - val InitializerName = new PrefixNameExtractor(8, str.INITIALIZER_PREFIX, "Initializer") - val ShadowedName = new PrefixNameExtractor(9, str.SHADOWED_PREFIX, "Shadowed") - val ModuleClassName = new SuffixNameExtractor(10, "$", "ModuleClass") + val SuperAccessorName = new PrefixNameExtractor(SUPERACCESSOR, str.SUPER_PREFIX, "SuperAccessor") + val InitializerName = new PrefixNameExtractor(INITIALIZER, str.INITIALIZER_PREFIX, "Initializer") + val ShadowedName = new PrefixNameExtractor(SHADOWED, str.SHADOWED_PREFIX, "Shadowed") + val ModuleClassName = new SuffixNameExtractor(OBJECTCLASS, "$", "ModuleClass") object SignedName extends NameExtractor(63) { diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index b51955d9d1cf..c837bc25cc01 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -49,26 +49,6 @@ object NameOps { } } - class PrefixNameExtractor(pre: TermName, bldr: NameExtractors.PrefixNameExtractor) { - def apply(name: TermName): TermName = - if (Config.semanticNames) bldr(name) else pre ++ name - - def unapply(name: TermName): Option[TermName] = - if (Config.semanticNames) - name match { - case bldr(original) => Some(original) - case _ => None - } - else tryUnmangle(name) - - def tryUnmangle(name: TermName): Option[TermName] = - if (name startsWith pre) Some(name.drop(pre.length).asTermName) - else None - } - - object SuperAccessorName extends PrefixNameExtractor(nme.SUPER_PREFIX, NameExtractors.SuperAccessorName) - object InitializerName extends PrefixNameExtractor(nme.INITIALIZER_PREFIX, NameExtractors.InitializerName) - implicit class NameDecorator[N <: Name](val name: N) extends AnyVal { import nme._ @@ -82,14 +62,8 @@ object NameOps { def isLoopHeaderLabel = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX) def isProtectedAccessorName = name startsWith PROTECTED_PREFIX def isReplWrapperName = name.toSimpleName containsSlice INTERPRETER_IMPORT_WRAPPER - def isTraitSetterName = - if (Config.semanticNames) name.is(TraitSetterName) - else name containsSlice TRAIT_SETTER_SEPARATOR def isSetterName = name endsWith SETTER_SUFFIX def isSingletonName = name endsWith SINGLETON_SUFFIX - def isModuleClassName = - if (Config.semanticNames) name.is(ModuleClassName) - else name endsWith MODULE_SUFFIX def isAvoidClashName = name endsWith AVOID_CLASH_SUFFIX def isImportName = name startsWith IMPORT def isFieldName = name endsWith LOCAL_SUFFIX @@ -137,19 +111,13 @@ object NameOps { } /** Convert this module name to corresponding module class name */ - def moduleClassName: TypeName = - if (Config.semanticNames) name.derived(ModuleClassName).toTypeName - else (name ++ tpnme.MODULE_SUFFIX).toTypeName + def moduleClassName: TypeName = name.derived(ModuleClassName).toTypeName /** Convert this module class name to corresponding source module name */ def sourceModuleName: TermName = stripModuleClassSuffix.toTermName /** If name ends in module class suffix, drop it */ - def stripModuleClassSuffix: Name = - if (isModuleClassName) - if (Config.semanticNames) name.exclude(ModuleClassName) - else name dropRight MODULE_SUFFIX.length - else name + def stripModuleClassSuffix: Name = name.exclude(ModuleClassName) /** Append a suffix so that this name does not clash with another name in the same scope */ def avoidClashName: TermName = (name ++ AVOID_CLASH_SUFFIX).toTermName @@ -165,9 +133,7 @@ object NameOps { }.asInstanceOf[N] /** The superaccessor for method with given name */ - def superName: TermName = - if (Config.semanticNames) SuperAccessorName(name.toTermName) - else (nme.SUPER_PREFIX ++ name).toTermName + def superName: TermName = SuperAccessorName(name.toTermName) /** The expanded name of `name` relative to given class `base`. */ @@ -179,34 +145,24 @@ object NameOps { /** The expanded name of `name` relative to `basename` with given `separator` */ def expandedName(prefix: Name, separator: Name = nme.EXPAND_SEPARATOR): N = - likeTyped( - if (Config.semanticNames) { - def qualify(name: SimpleTermName) = - separatorToQualified(separator.toString)(prefix.toTermName, name) - name rewrite { - case name: SimpleTermName => - qualify(name) - case AnyQualifiedName(_, _) => - // Note: an expanded name may itself be expanded. For example, look at javap of scala.App.initCode - qualify(name.toSimpleName) - } + likeTyped { + def qualify(name: SimpleTermName) = + separatorToQualified(separator.toString)(prefix.toTermName, name) + name rewrite { + case name: SimpleTermName => + qualify(name) + case AnyQualifiedName(_, _) => + // Note: an expanded name may itself be expanded. For example, look at javap of scala.App.initCode + qualify(name.toSimpleName) } - else prefix ++ separator ++ name) + } def expandedName(prefix: Name): N = expandedName(prefix, nme.EXPAND_SEPARATOR) - /** 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 = - if (Config.semanticNames) - likeTyped { - name.rewrite { case XpandedName(_, unexp) => unexp } - } - else unexpandedNameOfMangled + /** Revert the expanded name. */ + def unexpandedName: N = likeTyped { + name.rewrite { case XpandedName(_, unexp) => unexp } + } def unexpandedNameOfMangled: N = likeTyped { var idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) @@ -219,13 +175,8 @@ object NameOps { if (idx < 0) name else (name drop (idx + nme.EXPAND_SEPARATOR.length)) } - def expandedPrefix: N = - if (Config.semanticNames) - likeTyped { - name.rewrite { case XpandedName(prefix, _) => prefix } - } - else expandedPrefixOfMangled - + def expandedPrefix: N = likeTyped { name.exclude(XpandedName) } + def expandedPrefixOfMangled: N = { val idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) assert(idx >= 0) @@ -233,11 +184,11 @@ object NameOps { } def unmangleExpandedName: N = - if (Config.semanticNames && name.isSimple) { + if (name.isSimple) { val unmangled = unexpandedNameOfMangled if (name eq unmangled) name else likeTyped( - XpandedName(expandedPrefixOfMangled.toTermName, unmangled.asSimpleName)) + XpandedName(expandedPrefixOfMangled.toTermName, unmangled.asSimpleName)) } else name @@ -253,7 +204,7 @@ object NameOps { def freshened(implicit ctx: Context): N = likeTyped( - if (name.isModuleClassName) name.stripModuleClassSuffix.freshened.moduleClassName + if (name.is(ModuleClassName)) name.stripModuleClassSuffix.freshened.moduleClassName else likeTyped(ctx.freshName(name ++ NameTransformer.NAME_JOIN_STRING))) /* /** Name with variance prefix: `+` for covariant, `-` for contravariant */ @@ -283,7 +234,7 @@ object NameOps { */ def unmangleClassName: N = - if (Config.semanticNames && name.isSimple && name.isTypeName) + if (name.isSimple && name.isTypeName) if (name.endsWith(MODULE_SUFFIX) && !tpnme.falseModuleClassNames.contains(name.asTypeName)) likeTyped(name.dropRight(MODULE_SUFFIX.length).moduleClassName) else name @@ -439,18 +390,11 @@ object NameOps { def fieldName: TermName = if (name.isSetterName) { - if (name.isTraitSetterName) { - if (Config.semanticNames) { - val TraitSetterName(_, original) = name - original.fieldName - } - else { - // 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 - } - } else getterName.fieldName + if (name.is(TraitSetterName)) { + val TraitSetterName(_, original) = name + original.fieldName + } + else getterName.fieldName } else name.mapLast(n => (n ++ LOCAL_SUFFIX).asSimpleName) @@ -469,19 +413,13 @@ object NameOps { * @note Default getter name suffixes start at 1, so `pos` has to be adjusted by +1 */ def defaultGetterName(pos: Int): TermName = - if (Config.semanticNames) DefaultGetterName(name, pos) - else { - val prefix = if (name.isConstructorName) DEFAULT_GETTER_INIT else name - prefix ++ DEFAULT_GETTER ++ (pos + 1).toString - } + DefaultGetterName(name, pos) /** Nominally, name from name$default$N, CONSTRUCTOR for */ def defaultGetterToMethod: TermName = - if (Config.semanticNames) - name rewrite { - case DefaultGetterName(methName, _) => methName - } - else defaultGetterToMethodOfMangled + name rewrite { + case DefaultGetterName(methName, _) => methName + } def defaultGetterToMethodOfMangled: TermName = { val p = name.indexOfSlice(DEFAULT_GETTER) @@ -494,11 +432,9 @@ object NameOps { /** If this is a default getter, its index (starting from 0), else -1 */ def defaultGetterIndex: Int = - if (Config.semanticNames) - name collect { - case DefaultGetterName(_, num) => num - } getOrElse -1 - else defaultGetterIndexOfMangled + name collect { + case DefaultGetterName(_, num) => num + } getOrElse -1 def defaultGetterIndexOfMangled: Int = { var i = name.length @@ -590,7 +526,7 @@ object NameOps { def inlineAccessorName = nme.INLINE_ACCESSOR_PREFIX ++ name ++ "$" def unmangleMethodName: TermName = - if (Config.semanticNames && name.isSimple) { + if (name.isSimple) { val idx = name.defaultGetterIndexOfMangled if (idx >= 0) name.defaultGetterToMethodOfMangled.defaultGetterName(idx) else name @@ -598,13 +534,8 @@ object NameOps { else name def unmangleSuperName: TermName = - if (Config.semanticNames && name.isSimple) - SuperAccessorName.tryUnmangle(name.lastPart) match { - case scala.Some(original) => - SuperAccessorName(name.mapLast(_ => original.asSimpleName)) - case None => - name - } + if (name.isSimple && name.startsWith(str.SUPER_PREFIX)) + SuperAccessorName(name.drop(str.SUPER_PREFIX.length).asTermName) else name } diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index fa39c9782f28..4e40d1e05005 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -406,7 +406,7 @@ object SymDenotations { } var prefix = encl.fullNameSeparated(separator) val fn = - if (Config.semanticNames && separatorToQualified.contains(sep)) { + if (separatorToQualified.contains(sep)) { if (sep == "$") // duplicate scalac's behavior: don't write a double '$$' for module class members. prefix = prefix.exclude(ModuleClassName) @@ -1233,7 +1233,7 @@ object SymDenotations { // ----- denotation fields and accessors ------------------------------ if (initFlags is (Module, butNot = Package)) - assert(name.isModuleClassName, s"module naming inconsistency: ${name.debugString}") + assert(name.is(ModuleClassName), s"module naming inconsistency: ${name.debugString}") /** The symbol asserted to have type ClassSymbol */ def classSymbol: ClassSymbol = symbol.asInstanceOf[ClassSymbol] diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 131c9cf9ba9b..c5194fb93aeb 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -5,6 +5,7 @@ package classfile import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._, Decorators._ import SymDenotations._, unpickleScala2.Scala2Unpickler._, Constants._, Annotations._, util.Positions._ +import NameExtractors.ModuleClassName import ast.tpd._ import java.io.{ File, IOException } import java.lang.Integer.toHexString @@ -950,7 +951,7 @@ class ClassfileParser( val start = starts(index) if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start) val name = getExternalName(in.getChar(start + 1)) - if (name.isModuleClassName && (name ne nme.nothingRuntimeClass) && (name ne nme.nullRuntimeClass)) + if (name.is(ModuleClassName) && (name ne nme.nothingRuntimeClass) && (name ne nme.nullRuntimeClass)) // Null$ and Nothing$ ARE classes c = ctx.requiredModule(name.sourceModuleName) else c = classNameToSymbol(name) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index 0101ff25d96d..74c4265f2f0c 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala @@ -49,43 +49,36 @@ class NameBuffer extends TastyBuffer(10000) { def writeNameRef(ref: NameRef): Unit = writeNat(ref.index) def writeNameRef(name: Name): Unit = writeNameRef(nameRefs(name.toTermName)) - def pickleNameContents(name: Name): Unit = name.toTermName match { - case name: SimpleTermName => - val bytes = - if (name.length == 0) new Array[Byte](0) - else Codec.toUTF8(chrs, name.start, name.length) - writeByte(UTF8) - writeNat(bytes.length) - writeBytes(bytes, bytes.length) - case QualifiedName(qualified, selector) => - writeByte(QUALIFIED) - withLength { writeNameRef(qualified); writeNameRef(selector) } - case FlattenedName(qualified, selector) => - writeByte(FLATTENED) - withLength { writeNameRef(qualified); writeNameRef(selector) } - case XpandedName(prefix, original) => - writeByte(EXPANDED) - withLength { writeNameRef(prefix); writeNameRef(original) } - case SignedName(original, Signature(params, result)) => - writeByte(SIGNED) - withLength( + def pickleNameContents(name: Name): Unit = { + writeByte(name.toTermName.info.tag) + name.toTermName match { + case name: SimpleTermName => + val bytes = + if (name.length == 0) new Array[Byte](0) + else Codec.toUTF8(chrs, name.start, name.length) + writeNat(bytes.length) + writeBytes(bytes, bytes.length) + case QualifiedName(qualified, selector) => + withLength { writeNameRef(qualified); writeNameRef(selector) } + case FlattenedName(qualified, selector) => + withLength { writeNameRef(qualified); writeNameRef(selector) } + case XpandedName(prefix, original) => + withLength { writeNameRef(prefix); writeNameRef(original) } + case SignedName(original, Signature(params, result)) => + withLength( { writeNameRef(original); writeNameRef(result); params.foreach(writeNameRef) }, if ((params.length + 2) * maxIndexWidth <= maxNumInByte) 1 else 2) - case ModuleClassName(module) => - writeByte(OBJECTCLASS) - withLength { writeNameRef(module) } - case SuperAccessorName(accessed) => - writeByte(SUPERACCESSOR) - withLength { writeNameRef(accessed) } - case DefaultGetterName(method, paramNumber) => - writeByte(DEFAULTGETTER) - withLength { writeNameRef(method); writeNat(paramNumber) } - case ShadowedName(original) => - writeByte(SHADOWED) - withLength { writeNameRef(original) } - case VariantName(original, sign) => - writeByte(VARIANT) - withLength { writeNameRef(original); writeNat(sign + 1) } + case ModuleClassName(module) => + withLength { writeNameRef(module) } + case SuperAccessorName(accessed) => + withLength { writeNameRef(accessed) } + case DefaultGetterName(method, paramNumber) => + withLength { writeNameRef(method); writeNat(paramNumber) } + case ShadowedName(original) => + withLength { writeNameRef(original) } + case VariantName(original, sign) => + withLength { writeNameRef(original); writeNat(sign + 1) } + } } override def assemble(): Unit = { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index d4f6782fb1c2..de70c04f3bf7 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -224,12 +224,15 @@ object TastyFormat { final val QUALIFIED = 2 final val FLATTENED = 3 final val EXPANDED = 4 - final val SIGNED = 5 - final val OBJECTCLASS = 6 - final val SUPERACCESSOR = 7 - final val DEFAULTGETTER = 8 - final val SHADOWED = 9 - final val VARIANT = 10 + final val TRAITSETTER = 5 + final val DEFAULTGETTER = 10 + final val VARIANT = 11 + final val SUPERACCESSOR = 20 + final val INITIALIZER = 21 + final val SHADOWED = 22 + final val OBJECTCLASS = 29 + + final val SIGNED = 63 // AST tags diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index d1f2a3766765..2da63829166a 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -56,16 +56,6 @@ class TreePickler(pickler: TastyPickler) { private def pickleNameAndSig(name: Name, sig: Signature) = pickleName(SignedName(name.toTermName, sig)) - private def pickleName(sym: Symbol)(implicit ctx: Context): Unit = { - val nameRef = - if (Config.semanticNames) { - if (sym is Flags.ExpandedName) assert(sym.name.is(XpandedName)) - nameIndex(sym.name) - } - else ??? - writeNat(nameRef.index) - } - private def pickleSymRef(sym: Symbol)(implicit ctx: Context) = symRefs.get(sym) match { case Some(label) => if (label != NoAddr) writeRef(label) else pickleForwardSymRef(sym) @@ -303,7 +293,7 @@ class TreePickler(pickler: TastyPickler) { registerDef(sym) writeByte(tag) withLength { - pickleName(sym) + pickleName(sym.name) pickleParams tpt match { case templ: Template => pickleTree(tpt) diff --git a/compiler/src/dotty/tools/dotc/transform/Mixin.scala b/compiler/src/dotty/tools/dotc/transform/Mixin.scala index fd4370d3e319..e9ec4890c90c 100644 --- a/compiler/src/dotty/tools/dotc/transform/Mixin.scala +++ b/compiler/src/dotty/tools/dotc/transform/Mixin.scala @@ -13,6 +13,7 @@ import Decorators._ import DenotTransformers._ import StdNames._ import NameOps._ +import NameExtractors._ import Phases._ import ast.untpd import ast.Trees._ diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala index b6c28f570e92..9e22a6b469d6 100644 --- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -13,6 +13,7 @@ import Decorators._ import DenotTransformers._ import StdNames._ import NameOps._ +import NameExtractors._ import ast.Trees._ import util.Positions._ import Names._ @@ -95,15 +96,7 @@ object ResolveSuper { def rebindSuper(base: Symbol, acc: Symbol)(implicit ctx: Context): Symbol = { var bcs = base.info.baseClasses.dropWhile(acc.owner != _).tail var sym: Symbol = NoSymbol - val unexpandedAccName = - 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 + val SuperAccessorName(memberName) = acc.name.unexpandedName // 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") while (bcs.nonEmpty && sym == NoSymbol) { val other = bcs.head.info.nonPrivateDecl(memberName) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index a7b8200b5335..8674c8fbd8a5 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -18,6 +18,7 @@ import SymDenotations._ import Annotations._ import Names._ import NameOps._ +import NameExtractors._ import Flags._ import Decorators._ import ErrorReporting._ @@ -572,7 +573,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def canAssign(sym: Symbol) = // allow assignments from the primary constructor to class fields sym.is(Mutable, butNot = Accessor) || ctx.owner.isPrimaryConstructor && !sym.is(Method) && sym.owner == ctx.owner.owner || - ctx.owner.name.isTraitSetterName || ctx.owner.isStaticConstructor + ctx.owner.name.is(TraitSetterName) || ctx.owner.isStaticConstructor lhsCore.tpe match { case ref: TermRef if canAssign(ref.symbol) => assignType(cpy.Assign(tree)(lhs1, typed(tree.rhs, ref.info))) From 0efd6b93cf45be4cb211093185fef2923f53ef67 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Mar 2017 17:33:11 +0200 Subject: [PATCH 28/68] Fix PrefixNameExtractor mkString --- compiler/src/dotty/tools/dotc/core/NameExtractors.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala index ec7f00d326de..ae7d65829986 100644 --- a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala +++ b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala @@ -6,6 +6,7 @@ import NameOps._ import StdNames._ import util.DotClass import tasty.TastyFormat._ +import Decorators._ object NameExtractors { @@ -43,7 +44,8 @@ object NameExtractors { } class PrefixNameExtractor(tag: Int, prefix: String, infoString: String) extends ClassifiedNameExtractor(tag, infoString) { - def mkString(underlying: TermName, info: ThisInfo) = prefix ++ underlying + def mkString(underlying: TermName, info: ThisInfo) = + underlying.mapLast(n => termName(prefix + n)).toString } class SuffixNameExtractor(tag: Int, suffix: String, infoString: String) extends ClassifiedNameExtractor(tag, infoString) { From 21ab9a1355036aa953db4e1f87c8f0f9a06506b5 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Mar 2017 18:23:07 +0200 Subject: [PATCH 29/68] Get rid of ExpandedName flag --- .../backend/jvm/DottyBackendInterface.scala | 2 +- .../src/dotty/tools/dotc/ast/Desugar.scala | 2 +- .../dotty/tools/dotc/core/Definitions.scala | 2 +- .../src/dotty/tools/dotc/core/Flags.scala | 23 ++++++++----------- .../tools/dotc/core/NameExtractors.scala | 6 ++--- .../src/dotty/tools/dotc/core/NameOps.scala | 10 ++++---- .../src/dotty/tools/dotc/core/Signature.scala | 8 +++++++ .../tools/dotc/core/SymDenotations.scala | 6 ++--- .../tools/dotc/core/TypeApplications.scala | 9 +++----- .../tools/dotc/core/tasty/NameBuffer.scala | 2 +- .../dotc/core/tasty/TastyUnpickler.scala | 2 +- .../tools/dotc/core/tasty/TreePickler.scala | 3 ++- .../tools/dotc/core/tasty/TreeUnpickler.scala | 1 - .../core/unpickleScala2/PickleBuffer.scala | 2 +- .../core/unpickleScala2/Scala2Unpickler.scala | 7 ++++-- .../tools/dotc/printing/RefinedPrinter.scala | 5 ++-- .../dotc/transform/AugmentScala2Traits.scala | 7 +++--- .../dotty/tools/dotc/transform/Mixin.scala | 2 +- .../tools/dotc/transform/SuperAccessors.scala | 2 +- .../dotty/tools/dotc/transform/SymUtils.scala | 4 ++++ 20 files changed, 57 insertions(+), 48 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 309d97261b2f..45bbca01755c 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -421,7 +421,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma val Flag_METHOD: Flags = Flags.Method.bits val ExcludedForwarderFlags: Flags = { Flags.Specialized | Flags.Lifted | Flags.Protected | Flags.JavaStatic | - Flags.ExpandedName | Flags.Bridge | Flags.VBridge | Flags.Private | Flags.Macro + Flags.Bridge | Flags.VBridge | Flags.Private | Flags.Macro }.bits diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 66fc6bf84276..e2679ef56ab5 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -244,7 +244,7 @@ object desugar { def typeDef(tdef: TypeDef)(implicit ctx: Context): Tree = { if (tdef.mods is PrivateLocalParam) { val tparam = cpy.TypeDef(tdef)(name = tdef.name.expandedName(ctx.owner)) - .withMods(tdef.mods &~ PrivateLocal | ExpandedName) + .withMods(tdef.mods &~ PrivateLocal) val alias = cpy.TypeDef(tdef)(rhs = refOfDef(tparam)) .withMods(tdef.mods & VarianceFlags | PrivateLocalParamAccessor | Synthetic) Thicket(tparam, alias) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index b70fcb093ff3..670b919acbe4 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -67,7 +67,7 @@ class Definitions { enterTypeField(cls, name, flags | ClassTypeParamCreationFlags, scope) private def enterSyntheticTypeParam(cls: ClassSymbol, paramFlags: FlagSet, scope: MutableScope, suffix: String = "T0") = - enterTypeParam(cls, suffix.toTypeName.expandedName(cls), ExpandedName | paramFlags, scope) + enterTypeParam(cls, suffix.toTypeName.expandedName(cls), paramFlags, scope) // NOTE: Ideally we would write `parentConstrs: => Type*` but SIP-24 is only // implemented in Dotty and not in Scala 2. diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 29f1078a2f9d..8a1e14c638c1 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -272,9 +272,6 @@ object Flags { */ final val Synthetic = commonFlag(18, "") - /** Symbol's name is expanded */ - final val ExpandedName = commonFlag(19, "") - /** A covariant type variable / an outer accessor */ final val CovariantOrOuter = commonFlag(20, "") final val Covariant = typeFlag(20, "") @@ -308,7 +305,6 @@ object Flags { final val CaseAccessor = termFlag(25, "") /** A binding for a type parameter of a base class or trait. - * TODO: Replace with combination of isType, ExpandedName, and Override? */ final val BaseTypeArg = typeFlag(25, "") @@ -409,9 +405,6 @@ object Flags { final val Scala2ExistentialCommon = commonFlag(55, "") final val Scala2Existential = Scala2ExistentialCommon.toTypeFlags - /** An overloaded symbol (Scala 2.x only) */ - final val Scala2Overloaded = termFlag(56, "") - /** A module variable (Scala 2.x only) */ final val Scala2ModuleVar = termFlag(57, "") @@ -424,6 +417,13 @@ object Flags { /** A method that is known to have inherited default parameters */ final val InheritedDefaultParams = termFlag(60, "") + /** Translation of Scala2's EXPANDEDNAME flag. This flag is never stored in + * symbols, is only used locally when reading the flags of a Scala2 symbol. + * It's therefore safe to share the code with `InheritedDefaultParams` because + * the latter is never present in Scala2 unpickle info. + */ + final val Scala2ExpandedName = InheritedDefaultParams.toCommonFlags + /** A method that is known to have no default parameters */ final val NoDefaultParams = termFlag(61, "") @@ -475,7 +475,7 @@ object Flags { /** Flags that are passed from a type parameter of a class to a refinement symbol * that sets the type parameter */ - final val RetainedTypeArgFlags = VarianceFlags | ExpandedName | Protected | Local + final val RetainedTypeArgFlags = VarianceFlags | Protected | Local /** Modules always have these flags set */ final val ModuleCreationFlags = ModuleVal | Lazy | Final | Stable @@ -502,7 +502,7 @@ object Flags { */ final val RetainedModuleValAndClassFlags: FlagSet = AccessFlags | Package | Case | - Synthetic | ExpandedName | JavaDefined | JavaStatic | Artifact | + Synthetic | JavaDefined | JavaStatic | Artifact | Erroneous | Lifted | MixedIn | Specialized /** Flags that can apply to a module val */ @@ -550,9 +550,6 @@ object Flags { /** A private accessor */ final val PrivateAccessor = allOf(Private, Accessor) - /** A type parameter with synthesized name */ - final val ExpandedTypeParam = allOf(ExpandedName, TypeParam) - /** An inline method */ final val InlineMethod = allOf(Inline, Method) @@ -578,7 +575,7 @@ object Flags { final val FinalOrInline = Final | Inline /** If symbol of a type alias has these flags, prefer the alias */ - final val AliasPreferred = TypeParam | BaseTypeArg | ExpandedName + final val AliasPreferred = TypeParam | BaseTypeArg /** A covariant type parameter instance */ final val LocalCovariant = allOf(Local, Covariant) diff --git a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala index ae7d65829986..eaac30bf5ccb 100644 --- a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala +++ b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala @@ -45,7 +45,7 @@ object NameExtractors { class PrefixNameExtractor(tag: Int, prefix: String, infoString: String) extends ClassifiedNameExtractor(tag, infoString) { def mkString(underlying: TermName, info: ThisInfo) = - underlying.mapLast(n => termName(prefix + n)).toString + underlying.mapLast(n => termName(prefix + n.toString)).toString } class SuffixNameExtractor(tag: Int, suffix: String, infoString: String) extends ClassifiedNameExtractor(tag, infoString) { @@ -99,7 +99,7 @@ object NameExtractors { object QualifiedName extends QualifiedNameExtractor(QUALIFIED, ".", "Qualified") object FlattenedName extends QualifiedNameExtractor(FLATTENED, "$", "Flattened") - object XpandedName extends QualifiedNameExtractor(EXPANDED, str.EXPAND_SEPARATOR, "Expanded") + object ExpandedName extends QualifiedNameExtractor(EXPANDED, str.EXPAND_SEPARATOR, "Expanded") object TraitSetterName extends QualifiedNameExtractor(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR, "TraitSetter") object DefaultGetterName extends NumberedNameExtractor(DEFAULTGETTER, "DefaultGetter") { @@ -146,6 +146,6 @@ object NameExtractors { val separatorToQualified: Map[String, QualifiedNameExtractor] = Map("." -> QualifiedName, "$" -> FlattenedName, - str.EXPAND_SEPARATOR -> XpandedName, + str.EXPAND_SEPARATOR -> ExpandedName, str.TRAIT_SETTER_SEPARATOR -> TraitSetterName) } \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index c837bc25cc01..f467fbcd51dd 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -138,7 +138,7 @@ object NameOps { /** The expanded name of `name` relative to given class `base`. */ def expandedName(base: Symbol, separator: Name)(implicit ctx: Context): N = - expandedName(if (base is Flags.ExpandedName) base.name else base.fullNameSeparated("$"), separator) + expandedName(if (base.name.is(ExpandedName)) base.name else base.fullNameSeparated("$"), separator) def expandedName(base: Symbol)(implicit ctx: Context): N = expandedName(base, nme.EXPAND_SEPARATOR) @@ -161,7 +161,7 @@ object NameOps { /** Revert the expanded name. */ def unexpandedName: N = likeTyped { - name.rewrite { case XpandedName(_, unexp) => unexp } + name.rewrite { case ExpandedName(_, unexp) => unexp } } def unexpandedNameOfMangled: N = likeTyped { @@ -175,8 +175,8 @@ object NameOps { if (idx < 0) name else (name drop (idx + nme.EXPAND_SEPARATOR.length)) } - def expandedPrefix: N = likeTyped { name.exclude(XpandedName) } - + def expandedPrefix: N = likeTyped { name.exclude(ExpandedName) } + def expandedPrefixOfMangled: N = { val idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) assert(idx >= 0) @@ -188,7 +188,7 @@ object NameOps { val unmangled = unexpandedNameOfMangled if (name eq unmangled) name else likeTyped( - XpandedName(expandedPrefixOfMangled.toTermName, unmangled.asSimpleName)) + ExpandedName(expandedPrefixOfMangled.toTermName, unmangled.asSimpleName)) } else name diff --git a/compiler/src/dotty/tools/dotc/core/Signature.scala b/compiler/src/dotty/tools/dotc/core/Signature.scala index fcd1e23767df..4699cecf2421 100644 --- a/compiler/src/dotty/tools/dotc/core/Signature.scala +++ b/compiler/src/dotty/tools/dotc/core/Signature.scala @@ -34,6 +34,14 @@ import scala.annotation.tailrec case class Signature(paramsSig: List[TypeName], resSig: TypeName) { import Signature._ +/* FIXME does not compile under dotty, we get a missing param error + def checkUnqual(name: TypeName) = name mapParts { part => + assert(!part.contains('.'), name) + part + } + paramsSig.foreach(checkUnqual) + checkUnqual(resSig) +*/ /** Two names are consistent if they are the same or one of them is tpnme.Uninstantiated */ private def consistent(name1: TypeName, name2: TypeName) = name1 == name2 || name1 == tpnme.Uninstantiated || name2 == tpnme.Uninstantiated diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 4e40d1e05005..bbebdd21df87 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -367,7 +367,7 @@ object SymDenotations { /** The expanded name of this denotation. */ final def expandedName(implicit ctx: Context) = - if (is(ExpandedName) || isConstructor) name + if (name.is(ExpandedName) || isConstructor) name else { def legalize(name: Name): Name = // JVM method names may not contain `<' or `>' characters if (is(Method)) name.replace('<', '(').replace('>', ')') else name @@ -1210,9 +1210,7 @@ object SymDenotations { /** If denotation is private, remove the Private flag and expand the name if necessary */ def ensureNotPrivate(implicit ctx: Context) = if (is(Private)) - copySymDenotation( - name = expandedName, - initFlags = this.flags &~ Private | ExpandedName) + copySymDenotation(name = expandedName, initFlags = this.flags &~ Private) else this } diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 94b726491ea5..0220928a2f94 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -11,6 +11,7 @@ import util.Stats._ import util.common._ import Names._ import NameOps._ +import NameExtractors._ import Flags._ import StdNames.tpnme import util.Positions.Position @@ -464,11 +465,6 @@ class TypeApplications(val self: Type) extends AnyVal { self case _ => val v = tparam.paramVariance - /* Not neeeded. - if (v > 0 && !(tparam is Local) && !(tparam is ExpandedTypeParam)) TypeBounds.upper(self) - else if (v < 0 && !(tparam is Local) && !(tparam is ExpandedTypeParam)) TypeBounds.lower(self) - else - */ TypeAlias(self, v) } @@ -510,13 +506,14 @@ class TypeApplications(val self: Type) extends AnyVal { */ final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type = ctx.traceIndented(s"btwa ${self.show} wrt $base", core, show = true) { def default = self.baseTypeRef(base).appliedTo(baseArgInfos(base)) + def isExpandedTypeParam(sym: Symbol) = sym.is(TypeParam) && sym.name.is(ExpandedName) self match { case tp: TypeRef => tp.info match { case TypeBounds(_, hi) => hi.baseTypeWithArgs(base) case _ => default } - case tp @ RefinedType(parent, name, _) if !tp.member(name).symbol.is(ExpandedTypeParam) => + case tp @ RefinedType(parent, name, _) if !isExpandedTypeParam(tp.member(name).symbol) => tp.wrapIfMember(parent.baseTypeWithArgs(base)) case tp: TermRef => tp.underlying.baseTypeWithArgs(base) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index 74c4265f2f0c..a09a219649f7 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala @@ -62,7 +62,7 @@ class NameBuffer extends TastyBuffer(10000) { withLength { writeNameRef(qualified); writeNameRef(selector) } case FlattenedName(qualified, selector) => withLength { writeNameRef(qualified); writeNameRef(selector) } - case XpandedName(prefix, original) => + case ExpandedName(prefix, original) => withLength { writeNameRef(prefix); writeNameRef(original) } case SignedName(original, Signature(params, result)) => withLength( diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala index 6dd22db88126..d20e890c2124 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala @@ -54,7 +54,7 @@ class TastyUnpickler(reader: TastyReader) { case FLATTENED => FlattenedName(readName(), readName().asSimpleName) case EXPANDED => - XpandedName(readName(), readName().asSimpleName) + ExpandedName(readName(), readName().asSimpleName) case SIGNED => val original = readName() val result = readName().toTypeName diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 2da63829166a..e697ff028448 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -13,6 +13,7 @@ import NameOps._, NameExtractors._ import StdNames.nme import TastyBuffer._ import TypeApplications._ +import transform.SymUtils._ import config.Config class TreePickler(pickler: TastyPickler) { @@ -141,7 +142,7 @@ class TreePickler(pickler: TastyPickler) { withLength { pickleType(tycon); args.foreach(pickleType(_)) } case ConstantType(value) => pickleConstant(value) - case tpe: TypeRef if tpe.info.isAlias && tpe.symbol.is(Flags.AliasPreferred) => + case tpe: TypeRef if tpe.info.isAlias && tpe.symbol.isAliasPreferred => pickleType(tpe.superType) case tpe: WithFixedSym => val sym = tpe.symbol diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 11c04e2b47e3..d8497f39d99f 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -428,7 +428,6 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi if (!rhsIsEmpty) skipTree() val (givenFlags, annots, privateWithin) = readModifiers(end) val nameFlags = - (if (name.is(XpandedName)) ExpandedName else EmptyFlags) | (if (name.is(NameExtractors.SuperAccessorName)) SuperAccessor else EmptyFlags) pickling.println(i"creating symbol $name at $start with flags $givenFlags") val flags = normalizeFlags(tag, givenFlags | nameFlags, name, isAbsType, rhsIsEmpty) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala index 6ee9f1f9e254..773c6760e20c 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala @@ -229,7 +229,7 @@ object PickleBuffer { MODULEVAR -> Scala2ModuleVar, LAZY -> Lazy, MIXEDIN -> (MixedIn, Scala2Existential), - EXPANDEDNAME -> ExpandedName, + EXPANDEDNAME -> Scala2ExpandedName, IMPLCLASS -> (Scala2PreSuper, ImplClass), SPECIALIZED -> Specialized, VBRIDGE -> VBridge, diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index c37d60b4177c..aed0e97f1853 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -437,7 +437,10 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas if (name == nme.TRAIT_CONSTRUCTOR) nme.CONSTRUCTOR else name.asTermName.unmangleMethodName } - if (flags is ExpandedName) name = name.unmangleExpandedName + if (flags is Scala2ExpandedName) { + name = name.unmangleExpandedName + flags = flags &~ Scala2ExpandedName + } if (flags is SuperAccessor) name = name.asTermName.unmangleSuperName def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass) @@ -476,7 +479,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas var flags1 = flags if (flags is TypeParam) { name1 = name1.expandedName(owner) - flags1 |= owner.typeParamCreationFlags | ExpandedName + flags1 |= owner.typeParamCreationFlags } ctx.newSymbol(owner, name1, flags1, localMemberUnpickler, coord = start) case CLASSsym => diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 798a1c854b75..f6399d3b788f 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -13,6 +13,7 @@ import Trees._ import TypeApplications._ import Decorators._ import config.Config +import transform.SymUtils._ import scala.annotation.switch import language.implicitConversions @@ -63,7 +64,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { override protected def simpleNameString(sym: Symbol): String = { val name = if (ctx.property(XprintMode).isEmpty) sym.originalName else sym.name - nameString(if (sym is ExpandedTypeParam) name.asTypeName.unexpandedName else name) + nameString(if (sym.is(TypeParam)) name.asTypeName.unexpandedName else name) } override def fullNameString(sym: Symbol): String = @@ -131,7 +132,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (defn.isTupleClass(cls)) return toTextTuple(args) return (toTextLocal(tycon) ~ "[" ~ Text(args map argText, ", ") ~ "]").close case tp: TypeRef => - val hideType = !ctx.settings.debugAlias.value && (tp.symbol is AliasPreferred) + val hideType = !ctx.settings.debugAlias.value && (tp.symbol.isAliasPreferred) if (hideType && !ctx.phase.erasedTypes && !tp.symbol.isCompleting) { tp.info match { case TypeAlias(alias) => return toText(alias) diff --git a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala index 9c01aaa9aabf..594d85bfa9da 100644 --- a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala +++ b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala @@ -14,6 +14,7 @@ import DenotTransformers._ import Annotations._ import StdNames._ import NameOps._ +import NameExtractors._ import ast.Trees._ /** This phase augments Scala2 traits with implementation classes and with additional members @@ -66,7 +67,7 @@ class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransform meth.copy( owner = implClass, name = mold.name.asTermName, - flags = Method | JavaStatic | mold.flags & ExpandedName, + flags = Method | JavaStatic, info = fullyParameterizedType(mold.info, mixin)) } @@ -75,7 +76,7 @@ class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransform name = getter.ensureNotPrivate.name .expandedName(getter.owner, nme.TRAIT_SETTER_SEPARATOR) .asTermName.setterName, - flags = Method | Accessor | ExpandedName, + flags = Method | Accessor, info = MethodType(getter.info.resultType :: Nil, defn.UnitType)) for (sym <- mixin.info.decls) { @@ -89,7 +90,7 @@ class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransform else if (!sym.is(Deferred) && !sym.setter.exists && !sym.info.resultType.isInstanceOf[ConstantType]) traitSetter(sym.asTerm).enteredAfter(thisTransform) - if ((sym.is(PrivateAccessor, butNot = ExpandedName) && + if ((sym.is(PrivateAccessor) && !sym.name.is(ExpandedName) && (sym.isGetter || sym.isSetter)) // strangely, Scala 2 fields are also methods that have Accessor set. || sym.is(SuperAccessor)) // scala2 superaccessors are pickled as private, but are compiled as public expanded sym.ensureNotPrivate.installAfter(thisTransform) diff --git a/compiler/src/dotty/tools/dotc/transform/Mixin.scala b/compiler/src/dotty/tools/dotc/transform/Mixin.scala index e9ec4890c90c..fc23d96ee06a 100644 --- a/compiler/src/dotty/tools/dotc/transform/Mixin.scala +++ b/compiler/src/dotty/tools/dotc/transform/Mixin.scala @@ -220,7 +220,7 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform => ref(mixin.implClass).select(implClassGetter).appliedTo(This(cls)) } - if (isCurrent(getter) || getter.is(ExpandedName)) { + if (isCurrent(getter) || getter.name.is(ExpandedName)) { val rhs = if (was(getter, ParamAccessor)) nextArgument() else if (isScala2x) diff --git a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index 728c1696b867..32923f0f5a14 100644 --- a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -79,7 +79,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { .suchThat(_.signature == superInfo.signature).symbol .orElse { ctx.debuglog(s"add super acc ${sym.showLocated} to $clazz") - val deferredOrPrivate = if (clazz is Trait) Deferred | ExpandedName else Private + val deferredOrPrivate = if (clazz is Trait) Deferred else Private val acc = ctx.newSymbol( clazz, superName, SuperAccessor | Artifact | Method | deferredOrPrivate, superInfo, coord = sym.coord).enteredAfter(thisTransformer) diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index 105f54d3afd1..f6ff539feea8 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -10,6 +10,7 @@ import Decorators._ import Names._ import StdNames._ import NameOps._ +import NameExtractors._ import Flags._ import Annotations._ @@ -51,6 +52,9 @@ class SymUtils(val self: Symbol) extends AnyVal { def isAnyOverride(implicit ctx: Context) = self.is(Override) || self.is(AbsOverride) // careful: AbsOverride is a term only flag. combining with Override would catch only terms. + def isAliasPreferred(implicit ctx: Context) = + self.is(AliasPreferred) || self.name.is(ExpandedName) + /** If this is a constructor, its owner: otherwise this. */ final def skipConstructor(implicit ctx: Context): Symbol = if (self.isConstructor) self.owner else self From ea96ecda77ab99969a65b66173260e66b199be74 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Mar 2017 18:55:50 +0200 Subject: [PATCH 30/68] Get rid of SuperAccessor flag --- compiler/src/dotty/tools/dotc/core/Flags.scala | 4 ++-- .../dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 4 +--- .../tools/dotc/core/unpickleScala2/PickleBuffer.scala | 2 +- .../dotc/core/unpickleScala2/Scala2Unpickler.scala | 10 +++++++--- compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala | 3 ++- .../tools/dotc/transform/AugmentScala2Traits.scala | 2 +- .../src/dotty/tools/dotc/transform/ExpandSAMs.scala | 2 +- .../src/dotty/tools/dotc/transform/ResolveSuper.scala | 4 ++-- .../dotty/tools/dotc/transform/SuperAccessors.scala | 2 +- compiler/src/dotty/tools/dotc/transform/SymUtils.scala | 2 ++ .../src/dotty/tools/dotc/transform/ValueClasses.scala | 3 ++- compiler/src/dotty/tools/dotc/typer/RefChecks.scala | 2 +- 12 files changed, 23 insertions(+), 17 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 8a1e14c638c1..ef326171991f 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -311,12 +311,12 @@ object Flags { final val CaseAccessorOrBaseTypeArg = CaseAccessor.toCommonFlags /** A super accessor */ - final val SuperAccessor = termFlag(26, "") + final val Scala2SuperAccessor = termFlag(26, "") /** An unpickled Scala 2.x class */ final val Scala2x = typeFlag(26, "") - final val SuperAccessorOrScala2x = SuperAccessor.toCommonFlags + final val SuperAccessorOrScala2x = Scala2x.toCommonFlags /** A method that has default params */ final val DefaultParameterized = termFlag(27, "") diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index d8497f39d99f..8a9b6809317a 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -427,10 +427,8 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val rhsIsEmpty = noRhs(end) if (!rhsIsEmpty) skipTree() val (givenFlags, annots, privateWithin) = readModifiers(end) - val nameFlags = - (if (name.is(NameExtractors.SuperAccessorName)) SuperAccessor else EmptyFlags) pickling.println(i"creating symbol $name at $start with flags $givenFlags") - val flags = normalizeFlags(tag, givenFlags | nameFlags, name, isAbsType, rhsIsEmpty) + val flags = normalizeFlags(tag, givenFlags, name, isAbsType, rhsIsEmpty) def adjustIfModule(completer: LazyType) = if (flags is Module) ctx.adjustModuleCompleter(completer, name) else completer val sym = diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala index 773c6760e20c..2a789dca99a1 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala @@ -224,7 +224,7 @@ object PickleBuffer { DEFAULTPARAM -> (DefaultParameterized, Trait), BRIDGE -> Bridge, ACCESSOR -> Accessor, - SUPERACCESSOR -> SuperAccessor, + SUPERACCESSOR -> Scala2SuperAccessor, PARAMACCESSOR -> ParamAccessor, MODULEVAR -> Scala2ModuleVar, LAZY -> Lazy, diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index aed0e97f1853..976eb5df4ee8 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -18,6 +18,7 @@ import printing.Printer import io.AbstractFile import util.common._ import typer.Checking.checkNonCyclic +import transform.SymUtils._ import PickleBuffer._ import PickleFormat._ import Decorators._ @@ -441,7 +442,10 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas name = name.unmangleExpandedName flags = flags &~ Scala2ExpandedName } - if (flags is SuperAccessor) name = name.asTermName.unmangleSuperName + if (flags is Scala2SuperAccessor) { + name = name.asTermName.unmangleSuperName + flags = flags &~ Scala2SuperAccessor + } def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass) def isModuleClassRoot = (name == moduleClassRoot.name) && (owner == moduleClassRoot.owner) && (flags is Module) @@ -555,9 +559,9 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas else tp1 if (denot.isConstructor) addConstructorTypeParams(denot) if (atEnd) { - assert(!(denot is SuperAccessor), denot) + assert(!denot.isSuperAccessor, denot) } else { - assert(denot is (SuperAccessor | ParamAccessor), denot) + assert(denot.is(ParamAccessor) || denot.isSuperAccessor, denot) def disambiguate(alt: Symbol) = { // !!! DEBUG ctx.debugTraceIndented(s"disambiguating ${denot.info} =:= ${denot.owner.thisType.memberInfo(alt)} ${denot.owner}") { denot.info matches denot.owner.thisType.memberInfo(alt) diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index 8d704f9a24f9..324aecdf0321 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -7,6 +7,7 @@ import Annotations._, Contexts._, Flags._, Phases._, Trees._, Types._, Symbols._ import Names._, NameOps._, StdNames._ import typer.Inliner import typer.ErrorReporting.cyclicErrorMsg +import transform.SymUtils._ import dotty.tools.io.Path import java.io.PrintWriter @@ -539,7 +540,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder val abs = sym.is(Abstract) || sym.is(Deferred) || absOver val over = sym.is(Override) || absOver new api.Modifiers(abs, over, sym.is(Final), sym.is(Sealed), - sym.is(Implicit), sym.is(Lazy), sym.is(Macro), sym.is(SuperAccessor)) + sym.is(Implicit), sym.is(Lazy), sym.is(Macro), sym.isSuperAccessor) } def apiAnnotations(s: Symbol): List[api.Annotation] = { diff --git a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala index 594d85bfa9da..fa79d995c4eb 100644 --- a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala +++ b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala @@ -92,7 +92,7 @@ class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransform traitSetter(sym.asTerm).enteredAfter(thisTransform) if ((sym.is(PrivateAccessor) && !sym.name.is(ExpandedName) && (sym.isGetter || sym.isSetter)) // strangely, Scala 2 fields are also methods that have Accessor set. - || sym.is(SuperAccessor)) // scala2 superaccessors are pickled as private, but are compiled as public expanded + || sym.isSuperAccessor) // scala2 superaccessors are pickled as private, but are compiled as public expanded sym.ensureNotPrivate.installAfter(thisTransform) } ctx.log(i"Scala2x trait decls of $mixin = ${mixin.info.decls.toList.map(_.showDcl)}%\n %") diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 7b15b7e546f2..f63cba3f1f7b 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -38,7 +38,7 @@ class ExpandSAMs extends MiniPhaseTransform { thisTransformer => case tpe @ SAMType(_) if isPlatformSam(tpe.classSymbol.asClass) => tree case tpe => - val Seq(samDenot) = tpe.abstractTermMembers.filter(!_.symbol.is(SuperAccessor)) + val Seq(samDenot) = tpe.abstractTermMembers.filter(!_.symbol.isSuperAccessor) cpy.Block(tree)(stats, AnonClass(tpe :: Nil, fn.symbol.asTerm :: Nil, samDenot.symbol.asTerm.name :: Nil)) } diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala index 9e22a6b469d6..1df10cac2917 100644 --- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -60,7 +60,7 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th import ops._ def superAccessors(mixin: ClassSymbol): List[Tree] = - for (superAcc <- mixin.info.decls.filter(_ is SuperAccessor).toList) + for (superAcc <- mixin.info.decls.filter(_.isSuperAccessor).toList) yield polyDefDef(implementation(superAcc.asTerm), forwarder(rebindSuper(cls, superAcc))) def methodOverrides(mixin: ClassSymbol): List[Tree] = @@ -74,7 +74,7 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = { val meth = ddef.symbol.asTerm - if (meth.is(SuperAccessor, butNot = Deferred)) { + if (meth.isSuperAccessor && !meth.is(Deferred)) { assert(ddef.rhs.isEmpty) val cls = meth.owner.asClass val ops = new MixinOps(cls, thisTransform) diff --git a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index 32923f0f5a14..bae1b897e238 100644 --- a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -81,7 +81,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { ctx.debuglog(s"add super acc ${sym.showLocated} to $clazz") val deferredOrPrivate = if (clazz is Trait) Deferred else Private val acc = ctx.newSymbol( - clazz, superName, SuperAccessor | Artifact | Method | deferredOrPrivate, + clazz, superName, Artifact | Method | deferredOrPrivate, superInfo, coord = sym.coord).enteredAfter(thisTransformer) // Diagnostic for SI-7091 if (!accDefs.contains(clazz)) diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index f6ff539feea8..1b3018d9b083 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -55,6 +55,8 @@ class SymUtils(val self: Symbol) extends AnyVal { def isAliasPreferred(implicit ctx: Context) = self.is(AliasPreferred) || self.name.is(ExpandedName) + def isSuperAccessor(implicit ctx: Context) = self.name.is(SuperAccessorName) + /** If this is a constructor, its owner: otherwise this. */ final def skipConstructor(implicit ctx: Context): Symbol = if (self.isConstructor) self.owner else self diff --git a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala index b16d05644706..b398c2767218 100644 --- a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala +++ b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala @@ -8,6 +8,7 @@ import SymDenotations._ import Contexts._ import Flags._ import StdNames._ +import SymUtils._ /** Methods that apply to user-defined value classes */ object ValueClasses { @@ -24,7 +25,7 @@ object ValueClasses { d.isRealMethod && isDerivedValueClass(d.owner) && !d.isConstructor && - !d.is(SuperAccessor) && + !d.isSuperAccessor && !d.is(Macro) /** The member that of a derived value class that unboxes it. */ diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index d61f5fa68c48..49bc24c80342 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -405,7 +405,7 @@ object RefChecks { def ignoreDeferred(member: SingleDenotation) = member.isType || - member.symbol.is(SuperAccessor) || // not yet synthesized + member.symbol.isSuperAccessor || // not yet synthesized member.symbol.is(JavaDefined) && hasJavaErasedOverriding(member.symbol) // 2. Check that only abstract classes have deferred members From 1d6f5f7f33f9e4be29553cb7ef1e6f054a64dc6b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Mar 2017 21:47:07 +0200 Subject: [PATCH 31/68] Streamline pickling and unpickling of names --- .../dotty/tools/dotc/core/NameExtractors.scala | 10 ++++++++-- .../dotty/tools/dotc/core/tasty/NameBuffer.scala | 16 ++++------------ .../tools/dotc/core/tasty/TastyUnpickler.scala | 16 ++++++---------- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala index eaac30bf5ccb..f84ee565d370 100644 --- a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala +++ b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala @@ -7,9 +7,12 @@ import StdNames._ import util.DotClass import tasty.TastyFormat._ import Decorators._ +import collection.mutable object NameExtractors { + private val extractors = new mutable.HashMap[Int, ClassifiedNameExtractor] + abstract class NameInfo extends DotClass { def tag: Int def mkString(underlying: TermName): String @@ -41,6 +44,7 @@ object NameExtractors { case DerivedTermName(underlying, `info`) => Some(underlying) case _ => None } + extractors(tag) = this } class PrefixNameExtractor(tag: Int, prefix: String, infoString: String) extends ClassifiedNameExtractor(tag, infoString) { @@ -73,8 +77,8 @@ object NameExtractors { } object AnyQualifiedName { - def unapply(name: DerivedTermName): Option[(TermName, QualifiedNameExtractor # QualInfo)] = name match { - case DerivedTermName(qual, info: QualifiedNameExtractor # QualInfo) => + def unapply(name: DerivedTermName): Option[(TermName, QualifiedInfo)] = name match { + case DerivedTermName(qual, info: QualifiedInfo) => Some((name.underlying, info)) case _ => None } @@ -143,6 +147,8 @@ object NameExtractors { def definesNewName(tag: Int) = tag <= TraitSetterName.tag + def extractorOfTag(tag: Int) = extractors(tag) + val separatorToQualified: Map[String, QualifiedNameExtractor] = Map("." -> QualifiedName, "$" -> FlattenedName, diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index a09a219649f7..df43eabb2c23 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala @@ -58,26 +58,18 @@ class NameBuffer extends TastyBuffer(10000) { else Codec.toUTF8(chrs, name.start, name.length) writeNat(bytes.length) writeBytes(bytes, bytes.length) - case QualifiedName(qualified, selector) => - withLength { writeNameRef(qualified); writeNameRef(selector) } - case FlattenedName(qualified, selector) => - withLength { writeNameRef(qualified); writeNameRef(selector) } - case ExpandedName(prefix, original) => - withLength { writeNameRef(prefix); writeNameRef(original) } + case AnyQualifiedName(prefix, info) => + withLength { writeNameRef(prefix); writeNameRef(info.name) } case SignedName(original, Signature(params, result)) => withLength( { writeNameRef(original); writeNameRef(result); params.foreach(writeNameRef) }, if ((params.length + 2) * maxIndexWidth <= maxNumInByte) 1 else 2) - case ModuleClassName(module) => - withLength { writeNameRef(module) } - case SuperAccessorName(accessed) => - withLength { writeNameRef(accessed) } case DefaultGetterName(method, paramNumber) => withLength { writeNameRef(method); writeNat(paramNumber) } - case ShadowedName(original) => - withLength { writeNameRef(original) } case VariantName(original, sign) => withLength { writeNameRef(original); writeNat(sign + 1) } + case DerivedTermName(original, info) => + withLength { writeNameRef(original) } } } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala index d20e890c2124..7ebf3a2eaea9 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala @@ -55,6 +55,10 @@ class TastyUnpickler(reader: TastyReader) { FlattenedName(readName(), readName().asSimpleName) case EXPANDED => ExpandedName(readName(), readName().asSimpleName) + case DEFAULTGETTER => + DefaultGetterName(readName(), readNat()) + case VARIANT => + VariantName(readName(), readNat() - 1) case SIGNED => val original = readName() val result = readName().toTypeName @@ -62,16 +66,8 @@ class TastyUnpickler(reader: TastyReader) { var sig = Signature(params, result) if (sig == Signature.NotAMethod) sig = Signature.NotAMethod SignedName(original, sig) - case OBJECTCLASS => - ModuleClassName(readName()) - case SUPERACCESSOR => - SuperAccessorName(readName()) - case DEFAULTGETTER => - DefaultGetterName(readName(), readNat()) - case SHADOWED => - ShadowedName(readName()) - case VARIANT => - VariantName(readName(), readNat() - 1) + case _ => + extractorOfTag(tag)(readName()) } assert(currentAddr == end, s"bad name $result $start $currentAddr $end") result From 0021ffb0f1a0a857b7cdc8cdf769ae727dcb4b2c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Mar 2017 21:55:26 +0200 Subject: [PATCH 32/68] Add ShadowedName and AvoidClashName --- .../dotty/tools/dotc/core/NameExtractors.scala | 7 +++++-- compiler/src/dotty/tools/dotc/core/NameOps.scala | 15 +-------------- compiler/src/dotty/tools/dotc/core/Names.scala | 10 +++++----- compiler/src/dotty/tools/dotc/core/StdNames.scala | 4 ++-- .../dotty/tools/dotc/core/SymDenotations.scala | 2 +- compiler/src/dotty/tools/dotc/core/Types.scala | 7 ++++--- .../dotty/tools/dotc/core/tasty/TastyFormat.scala | 2 ++ .../dotty/tools/dotc/core/tasty/TreePickler.scala | 2 +- .../tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- .../src/dotty/tools/dotc/transform/Erasure.scala | 3 ++- .../tools/dotc/transform/FirstTransform.scala | 4 ++-- 11 files changed, 26 insertions(+), 32 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala index f84ee565d370..6045f0c1053b 100644 --- a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala +++ b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala @@ -1,4 +1,5 @@ -package dotty.tools.dotc +package dotty.tools +package dotc package core import Names._ @@ -11,7 +12,7 @@ import collection.mutable object NameExtractors { - private val extractors = new mutable.HashMap[Int, ClassifiedNameExtractor] + @sharable private val extractors = new mutable.HashMap[Int, ClassifiedNameExtractor] abstract class NameInfo extends DotClass { def tag: Int @@ -124,6 +125,8 @@ object NameExtractors { val SuperAccessorName = new PrefixNameExtractor(SUPERACCESSOR, str.SUPER_PREFIX, "SuperAccessor") val InitializerName = new PrefixNameExtractor(INITIALIZER, str.INITIALIZER_PREFIX, "Initializer") val ShadowedName = new PrefixNameExtractor(SHADOWED, str.SHADOWED_PREFIX, "Shadowed") + val LocalDummyName = new PrefixNameExtractor(LOCALDUMMY, str.LOCAL_DUMMY_PREFIX, "LocalDummy") + val AvoidClashName = new SuffixNameExtractor(AVOIDCLASH, str.AVOID_CLASH_SUFFIX, "AvoidClash") val ModuleClassName = new SuffixNameExtractor(OBJECTCLASS, "$", "ModuleClass") object SignedName extends NameExtractor(63) { diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index f467fbcd51dd..031cda1bd380 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -64,10 +64,8 @@ object NameOps { def isReplWrapperName = name.toSimpleName containsSlice INTERPRETER_IMPORT_WRAPPER def isSetterName = name endsWith SETTER_SUFFIX def isSingletonName = name endsWith SINGLETON_SUFFIX - def isAvoidClashName = name endsWith AVOID_CLASH_SUFFIX def isImportName = name startsWith IMPORT def isFieldName = name endsWith LOCAL_SUFFIX - def isShadowedName = name.startsWith(nme.SHADOWED) def isDefaultGetterName = name.isTermName && name.asTermName.defaultGetterIndex >= 0 def isScala2LocalSuffix = name.endsWith(" ") def isModuleVarName(name: Name): Boolean = @@ -119,17 +117,10 @@ object NameOps { /** If name ends in module class suffix, drop it */ def stripModuleClassSuffix: Name = name.exclude(ModuleClassName) - /** Append a suffix so that this name does not clash with another name in the same scope */ - def avoidClashName: TermName = (name ++ AVOID_CLASH_SUFFIX).toTermName - - /** If name ends in "avoid clash" suffix, drop it */ - def stripAvoidClashSuffix: Name = - if (isAvoidClashName) name dropRight AVOID_CLASH_SUFFIX.length else name - /** If flags is a ModuleClass but not a Package, add module class suffix */ def adjustIfModuleClass(flags: Flags.FlagSet): N = { if (flags is (ModuleClass, butNot = Package)) name.asTypeName.moduleClassName - else stripAvoidClashSuffix + else likeTyped(name.toTermName.exclude(AvoidClashName)) }.asInstanceOf[N] /** The superaccessor for method with given name */ @@ -192,10 +183,6 @@ object NameOps { } else name - def shadowedName: N = likeTyped(nme.SHADOWED ++ name) - - def revertShadowed: N = likeTyped(name.drop(nme.SHADOWED.length)) - def implClassName: N = likeTyped(name ++ tpnme.IMPL_CLASS_SUFFIX) def errorName: N = likeTyped(name ++ nme.ERROR) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 4524f2061493..d1788b6f934f 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -167,13 +167,16 @@ object Names { } } + private def rewrap(underlying: TermName) = + if (underlying eq this.underlying) this else underlying.add(info) + /** Return derived name with given `info` and the current * name as underlying name. */ def derived(info: NameInfo): TermName = { val ownTag = this.info.tag if (ownTag < info.tag || definesNewName(info.tag)) add(info) - else if (ownTag > info.tag) underlying.derived(info).add(this.info) + else if (ownTag > info.tag) rewrap(underlying.derived(info)) else { assert(info == this.info) this @@ -183,7 +186,7 @@ object Names { def exclude(kind: NameExtractor): TermName = { val ownTag = this.info.tag if (ownTag < kind.tag || definesNewName(ownTag)) this - else if (ownTag > kind.tag) underlying.exclude(kind).add(this.info) + else if (ownTag > kind.tag) rewrap(underlying.exclude(kind)) else underlying } @@ -202,9 +205,6 @@ object Names { def apply(n: Int) = chrs(start + n) - //override def derived(info: NameInfo): TermName = add(info) - //override def is(kind: NameExtractor) = false - private def contains(ch: Char): Boolean = { var i = 0 while (i < length && chrs(start + i) != ch) i += 1 diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index bf404d63024d..09e808c7d5a8 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -21,6 +21,8 @@ object StdNames { val SUPER_PREFIX = "super$" val INITIALIZER_PREFIX = "initial$" val SHADOWED_PREFIX = "(shadowed)" + val AVOID_CLASH_SUFFIX = "$_avoid_name_clash_$" + val LOCAL_DUMMY_PREFIX = "_" // owner of local blocks } abstract class DefinedNames[N <: Name] { @@ -117,7 +119,6 @@ object StdNames { val INTERPRETER_WRAPPER_SUFFIX: N = "$object" val LOCALDUMMY_PREFIX: N = " @@ -1804,7 +1805,7 @@ object Types { fixDenot(TermRef.withSig(prefix, name, sig), prefix) override def shadowed(implicit ctx: Context): NamedType = - fixDenot(TermRef.withSig(prefix, name.shadowedName, sig), prefix) + fixDenot(TermRef.withSig(prefix, name.derived(ShadowedName), sig), prefix) override def equals(that: Any) = that match { case that: TermRefWithSignature => diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index de70c04f3bf7..792c11cee0a5 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -230,6 +230,8 @@ object TastyFormat { final val SUPERACCESSOR = 20 final val INITIALIZER = 21 final val SHADOWED = 22 + final val LOCALDUMMY = 23 + final val AVOIDCLASH = 27 final val OBJECTCLASS = 29 final val SIGNED = 63 diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index e697ff028448..355eef1cae3b 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -352,7 +352,7 @@ class TreePickler(pickler: TastyPickler) { case Select(qual, name) => writeByte(if (name.isTypeName) SELECTtpt else SELECT) val realName = tree.tpe match { - case tp: NamedType if tp.name.isShadowedName => tp.name + case tp: NamedType if tp.name.is(ShadowedName) => tp.name case _ => name } val sig = tree.tpe.signature diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 8a9b6809317a..b8e6bbdf0987 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -857,7 +857,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val localCtx = if (name == nme.CONSTRUCTOR) ctx.addMode(Mode.InSuperCall) else ctx val qual = readTerm()(localCtx) - val unshadowed = if (name.isShadowedName) name.revertShadowed else name + val unshadowed = name.exclude(ShadowedName) untpd.Select(qual, unshadowed).withType(tpf(qual.tpe.widenIfUnstable)) } diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index d641200855da..e9fe42e78909 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -11,6 +11,7 @@ import core.Types._ import core.Names._ import core.StdNames._ import core.NameOps._ +import core.NameExtractors.ShadowedName import core.Decorators._ import core.Constants._ import core.Definitions._ @@ -363,7 +364,7 @@ object Erasure extends TypeTestsCasts{ def select(qual: Tree, sym: Symbol): Tree = { val name = tree.typeOpt match { - case tp: NamedType if tp.name.isShadowedName => sym.name.shadowedName + case tp: NamedType if tp.name.is(ShadowedName) => sym.name.derived(ShadowedName) case _ => sym.name } untpd.cpy.Select(tree)(qual, sym.name) diff --git a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala index 8328e43de746..803504944207 100644 --- a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -19,8 +19,8 @@ import dotty.tools.dotc.core.Denotations.SingleDenotation import scala.collection.mutable import DenotTransformers._ import typer.Checking -import Names.Name import NameOps._ +import NameExtractors.AvoidClashName import StdNames._ @@ -129,7 +129,7 @@ class FirstTransform extends MiniPhaseTransform with InfoTransformer with Annota case _ => false } - val uniqueName = if (nameClash) objName.avoidClashName else objName + val uniqueName = if (nameClash) AvoidClashName(objName) else objName Thicket(stat :: ModuleDef(registerCompanion(uniqueName, stat.symbol), Nil).trees) case stat => stat } From 1e49ddad97c4e8207913857511ae62467f8cd3ce Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 28 Mar 2017 13:07:11 +0200 Subject: [PATCH 33/68] Redefine definesNewName Make it a method of info instead of a convention over tags, because it's less fragile that way. Also, add UniqueName extractor. --- .../dotty/tools/dotc/core/NameExtractors.scala | 15 ++++++++++++--- compiler/src/dotty/tools/dotc/core/Names.scala | 6 +++--- .../dotty/tools/dotc/core/tasty/TastyFormat.scala | 5 +++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala index 6045f0c1053b..2c5f5c1645af 100644 --- a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala +++ b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala @@ -16,6 +16,7 @@ object NameExtractors { abstract class NameInfo extends DotClass { def tag: Int + def definesNewName: Boolean = false def mkString(underlying: TermName): String def map(f: SimpleTermName => SimpleTermName): NameInfo = this } @@ -64,6 +65,7 @@ object NameExtractors { abstract class QualifiedNameExtractor(tag: Int, val separator: String, val infoString: String) extends NameExtractor(tag) { type ThisInfo = QualInfo case class QualInfo(val name: SimpleTermName) extends Info with QualifiedInfo { + override def definesNewName = true override def map(f: SimpleTermName => SimpleTermName): NameInfo = new QualInfo(f(name)) override def toString = s"$infoString $name" } @@ -89,9 +91,10 @@ object NameExtractors { def num: Int } - abstract class NumberedNameExtractor(tag: Int, val infoString: String) extends NameExtractor(tag) { + abstract class NumberedNameExtractor(tag: Int, val infoString: String) extends NameExtractor(tag) { self => type ThisInfo = NumberedInfo case class NumberedInfo(val num: Int) extends Info with NameExtractors.NumberedInfo { + override def definesNewName = self.definesNewName override def toString = s"$infoString $num" } def apply(qual: TermName, num: Int) = @@ -100,6 +103,14 @@ object NameExtractors { case DerivedTermName(underlying, info: this.NumberedInfo) => Some((underlying, info.num)) case _ => None } + def definesNewName = false + } + + class UniqueNameExtractor(sep: String) extends NumberedNameExtractor(UNIQUE, "Unique") { + val separator = if (sep.isEmpty) "$" else sep + override def definesNewName = !sep.isEmpty + def mkString(underlying: TermName, info: ThisInfo) = + underlying.toString + separator + info.num } object QualifiedName extends QualifiedNameExtractor(QUALIFIED, ".", "Qualified") @@ -148,8 +159,6 @@ object NameExtractors { def infoString: String = "Signed" } - def definesNewName(tag: Int) = tag <= TraitSetterName.tag - def extractorOfTag(tag: Int) = extractors(tag) val separatorToQualified: Map[String, QualifiedNameExtractor] = diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index d1788b6f934f..81429a8d9e00 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -175,7 +175,7 @@ object Names { */ def derived(info: NameInfo): TermName = { val ownTag = this.info.tag - if (ownTag < info.tag || definesNewName(info.tag)) add(info) + if (ownTag < info.tag || info.definesNewName) add(info) else if (ownTag > info.tag) rewrap(underlying.derived(info)) else { assert(info == this.info) @@ -185,7 +185,7 @@ object Names { def exclude(kind: NameExtractor): TermName = { val ownTag = this.info.tag - if (ownTag < kind.tag || definesNewName(ownTag)) this + if (ownTag < kind.tag || info.definesNewName) this else if (ownTag > kind.tag) rewrap(underlying.exclude(kind)) else underlying } @@ -193,7 +193,7 @@ object Names { def is(kind: NameExtractor): Boolean = { val ownTag = this.info.tag ownTag == kind.tag || - !definesNewName(ownTag) && ownTag > kind.tag && underlying.is(kind) + !info.definesNewName && ownTag > kind.tag && underlying.is(kind) } override def hashCode = System.identityHashCode(this) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 792c11cee0a5..d0fee04df7b9 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -225,8 +225,9 @@ object TastyFormat { final val FLATTENED = 3 final val EXPANDED = 4 final val TRAITSETTER = 5 - final val DEFAULTGETTER = 10 - final val VARIANT = 11 + final val UNIQUE = 10 + final val DEFAULTGETTER = 11 + final val VARIANT = 12 final val SUPERACCESSOR = 20 final val INITIALIZER = 21 final val SHADOWED = 22 From ca5652cc5a74f00277ce942a001fa6e931ee3728 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 28 Mar 2017 22:25:09 +0200 Subject: [PATCH 34/68] Make freshName semantic --- .../src/dotty/tools/dotc/ast/Desugar.scala | 10 +- compiler/src/dotty/tools/dotc/ast/tpd.scala | 3 +- .../src/dotty/tools/dotc/core/Contexts.scala | 3 - .../dotty/tools/dotc/core/Denotations.scala | 4 +- .../tools/dotc/core/NameExtractors.scala | 138 ++++++++++++------ .../src/dotty/tools/dotc/core/NameOps.scala | 27 ++-- .../src/dotty/tools/dotc/core/Names.scala | 23 +-- .../src/dotty/tools/dotc/core/StdNames.scala | 15 +- .../tools/dotc/core/SymDenotations.scala | 6 +- .../src/dotty/tools/dotc/core/Symbols.scala | 3 +- .../src/dotty/tools/dotc/core/Types.scala | 8 +- .../tools/dotc/core/tasty/NameBuffer.scala | 34 +++-- .../tools/dotc/core/tasty/TastyFormat.scala | 3 +- .../dotc/core/tasty/TastyUnpickler.scala | 10 +- .../dotty/tools/dotc/parsing/Parsers.scala | 7 +- .../tools/dotc/printing/PlainPrinter.scala | 2 +- .../tools/dotc/transform/CapturedVars.scala | 3 +- .../dotty/tools/dotc/transform/LazyVals.scala | 14 +- .../dotty/tools/dotc/transform/LiftTry.scala | 3 +- .../tools/dotc/transform/MoveStatics.scala | 1 + .../dotc/transform/NonLocalReturns.scala | 3 +- .../tools/dotc/transform/PatternMatcher.scala | 24 +-- .../dotty/tools/dotc/transform/TailRec.scala | 37 ++--- .../dotc/transform/TryCatchPatterns.scala | 3 +- .../dotty/tools/dotc/typer/EtaExpansion.scala | 9 +- .../src/dotty/tools/dotc/typer/Inliner.scala | 4 +- .../dotty/tools/dotc/typer/ProtoTypes.scala | 3 +- .../tools/dotc/util/FreshNameCreator.scala | 17 ++- 28 files changed, 244 insertions(+), 173 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index e2679ef56ab5..3671ccb73965 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -6,6 +6,7 @@ import core._ import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ import Decorators._ +import NameExtractors.{UniqueName, EvidenceParamName} import language.higherKinds import typer.FrontEnd import collection.mutable.ListBuffer @@ -128,7 +129,7 @@ object desugar { def makeImplicitParameters(tpts: List[Tree], forPrimaryConstructor: Boolean)(implicit ctx: Context) = for (tpt <- tpts) yield { val paramFlags: FlagSet = if (forPrimaryConstructor) PrivateLocalParamAccessor else Param - val epname = ctx.freshName(nme.EVIDENCE_PARAM_PREFIX).toTermName + val epname = EvidenceParamName.fresh() ValDef(epname, tpt, EmptyTree).withFlags(paramFlags | Implicit) } @@ -230,7 +231,7 @@ object desugar { private def evidenceParams(meth: DefDef)(implicit ctx: Context): List[ValDef] = meth.vparamss.reverse match { case (vparams @ (vparam :: _)) :: _ if vparam.mods is Implicit => - vparams.dropWhile(!_.name.startsWith(nme.EVIDENCE_PARAM_PREFIX)) + vparams.dropWhile(!_.name.is(EvidenceParamName)) case _ => Nil } @@ -635,7 +636,6 @@ object desugar { case (named, tpt) :: Nil => derivedValDef(original, named, tpt, matchExpr, mods) case _ => - val tmpName = ctx.freshName().toTermName val patMods = mods & Lazy | Synthetic | (if (ctx.owner.isClass) PrivateLocal else EmptyFlags) val firstDef = @@ -810,7 +810,7 @@ object desugar { val selectPos = Position(left.pos.start, op.pos.end, op.pos.start) Apply(Select(left, op.name).withPos(selectPos), args) } else { - val x = ctx.freshName().toTermName + val x = UniqueName.fresh() val selectPos = Position(op.pos.start, right.pos.end, op.pos.start) new InfixOpBlock( ValDef(x, TypeTree(), left).withMods(synthetic), @@ -888,7 +888,7 @@ object desugar { case id: Ident if isVarPattern(id) && id.name != nme.WILDCARD => (id, id) case Typed(id: Ident, _) if isVarPattern(id) && id.name != nme.WILDCARD => (pat, id) case _ => - val name = ctx.freshName().toTermName + val name = UniqueName.fresh() (Bind(name, pat), Ident(name)) } diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index ff66c8c8e9af..e4c6dd6796f6 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -12,6 +12,7 @@ import Denotations._, Decorators._, DenotTransformers._ import collection.mutable import util.{Property, SourceFile, NoSource} import typer.ErrorReporting._ +import NameExtractors.TempResultName import scala.annotation.tailrec import scala.io.Codec @@ -897,7 +898,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def evalOnce(tree: Tree)(within: Tree => Tree)(implicit ctx: Context) = { if (isIdempotentExpr(tree)) within(tree) else { - val vdef = SyntheticValDef(ctx.freshName("ev$").toTermName, tree) + val vdef = SyntheticValDef(TempResultName.fresh(), tree) Block(vdef :: Nil, within(Ident(vdef.namedType))) } } diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 8707b66f9228..c80ad876a6ab 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -174,9 +174,6 @@ object Contexts { protected def freshNames_=(freshNames: FreshNameCreator) = _freshNames = freshNames def freshNames: FreshNameCreator = _freshNames - def freshName(prefix: String = ""): String = freshNames.newName(prefix) - def freshName(prefix: Name): String = freshName(prefix.toString) - /** A map in which more contextual properties can be stored */ private var _moreProperties: Map[Key[Any], Any] = _ protected def moreProperties_=(moreProperties: Map[Key[Any], Any]) = _moreProperties = moreProperties diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 60a506291341..42837122aeac 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -1193,8 +1193,8 @@ object Denotations { recur(underlying, n => wrap(ModuleClassName(n))) case QualifiedName(prefix, selector) => select(recur(prefix), wrap(selector)) - case AnyQualifiedName(prefix, info) => - recur(prefix, n => wrap(info.mkString(n).toTermName)) + case qn @ AnyQualifiedName(prefix, _) => + recur(prefix, n => wrap(qn.info.mkString(n).toTermName)) case path: SimpleTermName => def recurSimple(len: Int, wrap: TermName => Name): Denotation = { val point = path.lastIndexOf('.', len - 1) diff --git a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala index 2c5f5c1645af..1439ce002a2e 100644 --- a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala +++ b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala @@ -8,33 +8,38 @@ import StdNames._ import util.DotClass import tasty.TastyFormat._ import Decorators._ +import Contexts.Context import collection.mutable object NameExtractors { - @sharable private val extractors = new mutable.HashMap[Int, ClassifiedNameExtractor] + @sharable private val simpleExtractors = new mutable.HashMap[Int, ClassifiedNameExtractor] + @sharable private val uniqueExtractors = new mutable.HashMap[String, UniqueNameExtractor] + @sharable private val qualifiedExtractors = new mutable.HashMap[String, QualifiedNameExtractor] abstract class NameInfo extends DotClass { - def tag: Int - def definesNewName: Boolean = false + def extractor: NameExtractor def mkString(underlying: TermName): String def map(f: SimpleTermName => SimpleTermName): NameInfo = this } - val simpleTermNameInfo = new NameInfo { - def tag = UTF8 - def mkString(underlying: TermName): String = unsupported("mkString") - } - abstract class NameExtractor(val tag: Int) extends DotClass { self => - def mkString(underlying: TermName, info: ThisInfo): String - def infoString: String type ThisInfo <: Info class Info extends NameInfo { this: ThisInfo => - def tag = self.tag + def extractor = self def mkString(underlying: TermName) = self.mkString(underlying, this) override def toString = infoString } + def definesNewName = false + def mkString(underlying: TermName, info: ThisInfo): String + def infoString: String + } + + object SimpleTermNameExtractor extends NameExtractor(UTF8) { self => + type ThisInfo = Info + val info = new Info + def mkString(underlying: TermName, info: ThisInfo) = unsupported("mkString") + def infoString = unsupported("infoString") } abstract class ClassifiedNameExtractor(tag: Int, val infoString: String) extends NameExtractor(tag) { @@ -46,15 +51,17 @@ object NameExtractors { case DerivedTermName(underlying, `info`) => Some(underlying) case _ => None } - extractors(tag) = this + simpleExtractors(tag) = this } - class PrefixNameExtractor(tag: Int, prefix: String, infoString: String) extends ClassifiedNameExtractor(tag, infoString) { + class PrefixNameExtractor(tag: Int, prefix: String, optInfoString: String = "") + extends ClassifiedNameExtractor(tag, if (optInfoString.isEmpty) s"Prefix $prefix" else optInfoString) { def mkString(underlying: TermName, info: ThisInfo) = underlying.mapLast(n => termName(prefix + n.toString)).toString } - class SuffixNameExtractor(tag: Int, suffix: String, infoString: String) extends ClassifiedNameExtractor(tag, infoString) { + class SuffixNameExtractor(tag: Int, suffix: String, optInfoString: String = "") + extends ClassifiedNameExtractor(tag, if (optInfoString.isEmpty) s"Suffix $suffix" else optInfoString) { def mkString(underlying: TermName, info: ThisInfo) = underlying.toString ++ suffix } @@ -62,10 +69,10 @@ object NameExtractors { val name: SimpleTermName } - abstract class QualifiedNameExtractor(tag: Int, val separator: String, val infoString: String) extends NameExtractor(tag) { + class QualifiedNameExtractor(tag: Int, val separator: String) + extends NameExtractor(tag) { type ThisInfo = QualInfo case class QualInfo(val name: SimpleTermName) extends Info with QualifiedInfo { - override def definesNewName = true override def map(f: SimpleTermName => SimpleTermName): NameInfo = new QualInfo(f(name)) override def toString = s"$infoString $name" } @@ -75,26 +82,32 @@ object NameExtractors { case DerivedTermName(qual, info: this.QualInfo) => Some((qual, info.name)) case _ => None } + + override def definesNewName = true + def mkString(underlying: TermName, info: ThisInfo) = s"$underlying$separator${info.name}" + def infoString = s"Qualified $separator" + + qualifiedExtractors(separator) = this } object AnyQualifiedName { - def unapply(name: DerivedTermName): Option[(TermName, QualifiedInfo)] = name match { + def unapply(name: DerivedTermName): Option[(TermName, SimpleTermName)] = name match { case DerivedTermName(qual, info: QualifiedInfo) => - Some((name.underlying, info)) + Some((name.underlying, info.name)) case _ => None } } trait NumberedInfo { def num: Int + def extractor: NameExtractor } abstract class NumberedNameExtractor(tag: Int, val infoString: String) extends NameExtractor(tag) { self => type ThisInfo = NumberedInfo case class NumberedInfo(val num: Int) extends Info with NameExtractors.NumberedInfo { - override def definesNewName = self.definesNewName override def toString = s"$infoString $num" } def apply(qual: TermName, num: Int) = @@ -103,20 +116,66 @@ object NameExtractors { case DerivedTermName(underlying, info: this.NumberedInfo) => Some((underlying, info.num)) case _ => None } - def definesNewName = false } - class UniqueNameExtractor(sep: String) extends NumberedNameExtractor(UNIQUE, "Unique") { - val separator = if (sep.isEmpty) "$" else sep - override def definesNewName = !sep.isEmpty - def mkString(underlying: TermName, info: ThisInfo) = - underlying.toString + separator + info.num + case class UniqueNameExtractor(val separator: String) + extends NumberedNameExtractor(UNIQUE, s"Unique $separator") { + override def definesNewName = true + def mkString(underlying: TermName, info: ThisInfo) = { + val safePrefix = str.sanitize(underlying.toString + separator) + safePrefix + info.num + } + + def fresh(prefix: TermName = EmptyTermName)(implicit ctx: Context): TermName = + ctx.freshNames.newName(prefix, this) + + uniqueExtractors(separator) = this + } + + object AnyUniqueName { + def unapply(name: DerivedTermName): Option[(TermName, String, Int)] = name match { + case DerivedTermName(qual, info: NumberedInfo) => + info.extractor match { + case unique: UniqueNameExtractor => Some((qual, unique.separator, info.num)) + case _ => None + } + case _ => None + } } - object QualifiedName extends QualifiedNameExtractor(QUALIFIED, ".", "Qualified") - object FlattenedName extends QualifiedNameExtractor(FLATTENED, "$", "Flattened") - object ExpandedName extends QualifiedNameExtractor(EXPANDED, str.EXPAND_SEPARATOR, "Expanded") - object TraitSetterName extends QualifiedNameExtractor(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR, "TraitSetter") + val QualifiedName = new QualifiedNameExtractor(QUALIFIED, ".") + val FlattenedName = new QualifiedNameExtractor(FLATTENED, "$") + val ExpandedName = new QualifiedNameExtractor(EXPANDED, str.EXPAND_SEPARATOR) + val TraitSetterName = new QualifiedNameExtractor(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR) + + val UniqueName = new UniqueNameExtractor("$") { + override def mkString(underlying: TermName, info: ThisInfo) = + if (underlying.isEmpty) "$" + info.num + "$" else super.mkString(underlying, info) + } + + val InlineAccessorName = new UniqueNameExtractor("$_inlineAccessor_$") + val TempResultName = new UniqueNameExtractor("ev$") + val EvidenceParamName = new UniqueNameExtractor("evidence$") + val DepParamName = new UniqueNameExtractor("") + val LazyImplicitName = new UniqueNameExtractor("$_lazy_implicit_$") + val LazyLocalName = new UniqueNameExtractor("$lzy") + val LazyLocalInitName = new UniqueNameExtractor("$lzyINIT") + val LazyFieldOffsetName = new UniqueNameExtractor("$OFFSET") + val LazyBitMapName = new UniqueNameExtractor(nme.BITMAP_PREFIX.toString) + val NonLocalReturnKeyName = new UniqueNameExtractor("nonLocalReturnKey") + val WildcardParamName = new UniqueNameExtractor("_$") + val TailLabelName = new UniqueNameExtractor("tailLabel") + val ExceptionBinderName = new UniqueNameExtractor("ex") + val SkolemName = new UniqueNameExtractor("?") + val LiftedTreeName = new UniqueNameExtractor("liftedTree") + + val PatMatStdBinderName = new UniqueNameExtractor("x") + val PatMatPiName = new UniqueNameExtractor("pi") // FIXME: explain what this is + val PatMatPName = new UniqueNameExtractor("p") // FIXME: explain what this is + val PatMatOName = new UniqueNameExtractor("o") // FIXME: explain what this is + val PatMatCaseName = new UniqueNameExtractor("case") + val PatMatMatchFailName = new UniqueNameExtractor("matchFail") + val PatMatSelectorName = new UniqueNameExtractor("selector") object DefaultGetterName extends NumberedNameExtractor(DEFAULTGETTER, "DefaultGetter") { def mkString(underlying: TermName, info: ThisInfo) = { @@ -133,12 +192,11 @@ object NameExtractors { } } - val SuperAccessorName = new PrefixNameExtractor(SUPERACCESSOR, str.SUPER_PREFIX, "SuperAccessor") - val InitializerName = new PrefixNameExtractor(INITIALIZER, str.INITIALIZER_PREFIX, "Initializer") - val ShadowedName = new PrefixNameExtractor(SHADOWED, str.SHADOWED_PREFIX, "Shadowed") - val LocalDummyName = new PrefixNameExtractor(LOCALDUMMY, str.LOCAL_DUMMY_PREFIX, "LocalDummy") - val AvoidClashName = new SuffixNameExtractor(AVOIDCLASH, str.AVOID_CLASH_SUFFIX, "AvoidClash") - val ModuleClassName = new SuffixNameExtractor(OBJECTCLASS, "$", "ModuleClass") + val SuperAccessorName = new PrefixNameExtractor(SUPERACCESSOR, "super$") + val InitializerName = new PrefixNameExtractor(INITIALIZER, "initial$") + val ShadowedName = new PrefixNameExtractor(SHADOWED, "(shadowed)") + val AvoidClashName = new SuffixNameExtractor(AVOIDCLASH, "$_avoid_name_clash_$") + val ModuleClassName = new SuffixNameExtractor(OBJECTCLASS, "$", optInfoString = "ModuleClass") object SignedName extends NameExtractor(63) { @@ -159,11 +217,7 @@ object NameExtractors { def infoString: String = "Signed" } - def extractorOfTag(tag: Int) = extractors(tag) - - val separatorToQualified: Map[String, QualifiedNameExtractor] = - Map("." -> QualifiedName, - "$" -> FlattenedName, - str.EXPAND_SEPARATOR -> ExpandedName, - str.TRAIT_SETTER_SEPARATOR -> TraitSetterName) + def simpleExtractorOfTag : collection.Map[Int, ClassifiedNameExtractor] = simpleExtractors + def qualifiedExtractorOfSeparator: collection.Map[String, QualifiedNameExtractor] = qualifiedExtractors + def uniqueExtractorOfSeparator : collection.Map[String, UniqueNameExtractor] = uniqueExtractors } \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 031cda1bd380..6f2c753138d0 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -71,9 +71,7 @@ object NameOps { def isModuleVarName(name: Name): Boolean = name.stripAnonNumberSuffix endsWith MODULE_VAR_SUFFIX def isSelectorName = name.startsWith(" ") && name.tail.forall(_.isDigit) - def isLazyLocal = name.endsWith(nme.LAZY_LOCAL) def isOuterSelect = name.endsWith(nme.OUTER_SELECT) - def isInlineAccessor = name.startsWith(nme.INLINE_ACCESSOR_PREFIX) /** Is name a variable name? */ def isVariableName: Boolean = name.length > 0 && { @@ -112,16 +110,16 @@ object NameOps { def moduleClassName: TypeName = name.derived(ModuleClassName).toTypeName /** Convert this module class name to corresponding source module name */ - def sourceModuleName: TermName = stripModuleClassSuffix.toTermName + def sourceModuleName: TermName = name.toTermName.exclude(ModuleClassName) /** If name ends in module class suffix, drop it */ def stripModuleClassSuffix: Name = name.exclude(ModuleClassName) /** If flags is a ModuleClass but not a Package, add module class suffix */ - def adjustIfModuleClass(flags: Flags.FlagSet): N = { + def adjustIfModuleClass(flags: Flags.FlagSet): N = likeTyped { if (flags is (ModuleClass, butNot = Package)) name.asTypeName.moduleClassName - else likeTyped(name.toTermName.exclude(AvoidClashName)) - }.asInstanceOf[N] + else name.toTermName.exclude(AvoidClashName) + } /** The superaccessor for method with given name */ def superName: TermName = SuperAccessorName(name.toTermName) @@ -138,7 +136,7 @@ object NameOps { def expandedName(prefix: Name, separator: Name = nme.EXPAND_SEPARATOR): N = likeTyped { def qualify(name: SimpleTermName) = - separatorToQualified(separator.toString)(prefix.toTermName, name) + qualifiedExtractorOfSeparator(separator.toString)(prefix.toTermName, name) name rewrite { case name: SimpleTermName => qualify(name) @@ -220,6 +218,13 @@ object NameOps { } */ + def freshened(implicit ctx: Context): N = likeTyped { + name.toTermName match { + case ModuleClassName(original) => ModuleClassName(original.freshened) + case name => UniqueName.fresh(name) + } + } + def unmangleClassName: N = if (name.isSimple && name.isTypeName) if (name.endsWith(MODULE_SUFFIX) && !tpnme.falseModuleClassNames.contains(name.asTypeName)) @@ -504,14 +509,6 @@ object NameOps { case name => name } - def lazyLocalName = name ++ nme.LAZY_LOCAL - def nonLazyName = { - assert(name.isLazyLocal) - name.dropRight(nme.LAZY_LOCAL.length) - } - - def inlineAccessorName = nme.INLINE_ACCESSOR_PREFIX ++ name ++ "$" - def unmangleMethodName: TermName = if (name.isSimple) { val idx = name.defaultGetterIndexOfMangled diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 81429a8d9e00..e4ebe61c2afe 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -130,7 +130,7 @@ object Names { def likeKinded(name: Name): TermName = name.toTermName - def info: NameInfo = simpleTermNameInfo + def info: NameInfo = SimpleTermNameExtractor.info def underlying: TermName = unsupported("underlying") @sharable private var derivedNames: AnyRef /* SimpleMap | j.u.HashMap */ = @@ -174,9 +174,10 @@ object Names { * name as underlying name. */ def derived(info: NameInfo): TermName = { - val ownTag = this.info.tag - if (ownTag < info.tag || info.definesNewName) add(info) - else if (ownTag > info.tag) rewrap(underlying.derived(info)) + val thisKind = this.info.extractor + val thatKind = info.extractor + if (thisKind.tag < thatKind.tag || thatKind.definesNewName) add(info) + else if (thisKind.tag > thatKind.tag) rewrap(underlying.derived(info)) else { assert(info == this.info) this @@ -184,16 +185,16 @@ object Names { } def exclude(kind: NameExtractor): TermName = { - val ownTag = this.info.tag - if (ownTag < kind.tag || info.definesNewName) this - else if (ownTag > kind.tag) rewrap(underlying.exclude(kind)) + val thisKind = this.info.extractor + if (thisKind.tag < kind.tag || thisKind.definesNewName) this + else if (thisKind.tag > kind.tag) rewrap(underlying.exclude(kind)) else underlying } def is(kind: NameExtractor): Boolean = { - val ownTag = this.info.tag - ownTag == kind.tag || - !info.definesNewName && ownTag > kind.tag && underlying.is(kind) + val thisKind = this.info.extractor + thisKind == kind || + !thisKind.definesNewName && thisKind.tag > kind.tag && underlying.is(kind) } override def hashCode = System.identityHashCode(this) @@ -511,7 +512,7 @@ object Names { implicit val NameOrdering: Ordering[Name] = new Ordering[Name] { private def compareInfos(x: NameInfo, y: NameInfo): Int = - if (x.tag != y.tag) x.tag - y.tag + if (x.extractor.tag != y.extractor.tag) x.extractor.tag - y.extractor.tag else x match { case x: QualifiedInfo => y match { diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 09e808c7d5a8..598d556502f0 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -22,7 +22,8 @@ object StdNames { val INITIALIZER_PREFIX = "initial$" val SHADOWED_PREFIX = "(shadowed)" val AVOID_CLASH_SUFFIX = "$_avoid_name_clash_$" - val LOCAL_DUMMY_PREFIX = "_" // owner of local blocks + + def sanitize(str: String) = str.replaceAll("""[<>]""", """\$""") } abstract class DefinedNames[N <: Name] { @@ -96,7 +97,7 @@ object StdNames { val ANON_CLASS: N = "$anon" val ANON_FUN: N = "$anonfun" - val BITMAP_PREFIX: N = "bitmap$" + val BITMAP_PREFIX: N = "bitmap$" // @darkdimius: $bitmap? Also, the next 4 names are unused. val BITMAP_NORMAL: N = BITMAP_PREFIX // initialization bitmap for public/protected lazy vals val BITMAP_TRANSIENT: N = BITMAP_PREFIX + "trans$" // initialization bitmap for transient lazy vals val BITMAP_CHECKINIT: N = BITMAP_PREFIX + "init$" // initialization bitmap for checkinit values @@ -106,13 +107,10 @@ object StdNames { val DO_WHILE_PREFIX: N = "doWhile$" val EMPTY: N = "" val EMPTY_PACKAGE: N = Names.EMPTY_PACKAGE.toString - val EVIDENCE_PARAM_PREFIX: N = "evidence$" - val DEP_PARAM_PREFIX = "" val EXCEPTION_RESULT_PREFIX: N = "exceptionResult" val EXPAND_SEPARATOR: N = str.EXPAND_SEPARATOR val IMPL_CLASS_SUFFIX: N = "$class" val IMPORT: N = "" - val INLINE_ACCESSOR_PREFIX = "$inlineAccessor$" val INTERPRETER_IMPORT_WRAPPER: N = "$iw" val INTERPRETER_LINE_PREFIX: N = "line" val INTERPRETER_VAR_PREFIX: N = "res" @@ -121,7 +119,6 @@ object StdNames { val MODULE_SUFFIX: N = NameTransformer.MODULE_SUFFIX_STRING val MODULE_VAR_SUFFIX: N = "$module" val NAME_JOIN: N = NameTransformer.NAME_JOIN_STRING - val USCORE_PARAM_PREFIX: N = "_$" val OPS_PACKAGE: N = "" val OVERLOADED: N = "" val PACKAGE: N = "package" @@ -139,9 +136,6 @@ object StdNames { val COMPANION_CLASS_METHOD: N = "companion$class" 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" - val DOLLAR_NEW: N = "$new" // value types (and AnyRef) are all used as terms as well // as (at least) arguments to the @specialize annotation. @@ -249,8 +243,6 @@ object StdNames { val EVT2U: N = "evt2u$" val EQEQ_LOCAL_VAR: N = "eqEqTemp$" val FAKE_LOCAL_THIS: N = "this$" - val LAZY_LOCAL: N = "$lzy" - val LAZY_LOCAL_INIT: N = "$lzyINIT" val LAZY_FIELD_OFFSET: N = "OFFSET$" val LAZY_SLOW_SUFFIX: N = "$lzycompute" val LOCAL_SUFFIX: N = "$$local" @@ -448,7 +440,6 @@ object StdNames { val lang: N = "lang" val length: N = "length" val lengthCompare: N = "lengthCompare" - val liftedTree: N = "liftedTree" val `macro` : N = "macro" val macroThis : N = "_this" val macroContext : N = "c" diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index eb16b2188f1e..5e5a5df2d307 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -406,14 +406,14 @@ object SymDenotations { } var prefix = encl.fullNameSeparated(separator) val fn = - if (separatorToQualified.contains(sep)) { + if (qualifiedExtractorOfSeparator.contains(sep)) { if (sep == "$") // duplicate scalac's behavior: don't write a double '$$' for module class members. prefix = prefix.exclude(ModuleClassName) name rewrite { case n: SimpleTermName => val n1 = if (filler.isEmpty) n else termName(filler ++ n) - separatorToQualified(sep)(prefix.toTermName, n1) + qualifiedExtractorOfSeparator(sep)(prefix.toTermName, n1) } } else { @@ -1541,7 +1541,7 @@ object SymDenotations { !(this is Frozen) || (scope ne this.unforcedDecls) || sym.hasAnnotation(defn.ScalaStaticAnnot) || - sym.name.isInlineAccessor || + sym.name.is(InlineAccessorName) || isUsecase, i"trying to enter $sym in $this, frozen = ${this is Frozen}") scope.enter(sym) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 95ff1cb75b9a..69d6e8db3c8a 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -19,6 +19,7 @@ import util.Positions._ import DenotTransformers._ import StdNames._ import NameOps._ +import NameExtractors.LazyImplicitName import ast.tpd.Tree import ast.TreeTypeMap import Constants.Constant @@ -260,7 +261,7 @@ trait Symbols { this: Context => /** Create a synthetic lazy implicit value */ def newLazyImplicit(info: Type) = - newSymbol(owner, freshName(nme.LAZY_IMPLICIT_PREFIX).toTermName, Lazy, info) + newSymbol(owner, LazyImplicitName.fresh(), Lazy, info) /** Create a symbol representing a selftype declaration for class `cls`. */ def newSelfSym(cls: ClassSymbol, name: TermName = nme.WILDCARD, selfInfo: Type = NoType): TermSymbol = diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index b2502ee94750..3f5a3092200d 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -7,7 +7,7 @@ import Symbols._ import Flags._ import Names._ import StdNames._, NameOps._ -import NameExtractors.ShadowedName +import NameExtractors.{ShadowedName, SkolemName} import Scopes._ import Constants._ import Contexts._ @@ -3001,9 +3001,9 @@ object Types { override def hashCode: Int = identityHash override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] - private var myRepr: String = null - def repr(implicit ctx: Context) = { - if (myRepr == null) myRepr = ctx.freshName("?") + private var myRepr: Name = null + def repr(implicit ctx: Context): Name = { + if (myRepr == null) myRepr = SkolemName.fresh() myRepr } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index df43eabb2c23..2fd078befaaf 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala @@ -26,10 +26,13 @@ class NameBuffer extends TastyBuffer(10000) { name1 match { case SignedName(original, Signature(params, result)) => nameIndex(original); nameIndex(result); params.foreach(nameIndex) - case AnyQualifiedName(prefix, info) => - nameIndex(prefix); nameIndex(info.name) - case DerivedTermName(prefix, _) => - nameIndex(prefix) + case AnyQualifiedName(prefix, name) => + nameIndex(prefix); nameIndex(name) + case AnyUniqueName(original, separator, num) => + nameIndex(separator.toTermName) + if (original.nonEmpty) nameIndex(original) + case DerivedTermName(original, _) => + nameIndex(original) case _ => } val ref = NameRef(nameRefs.size) @@ -50,7 +53,8 @@ class NameBuffer extends TastyBuffer(10000) { def writeNameRef(name: Name): Unit = writeNameRef(nameRefs(name.toTermName)) def pickleNameContents(name: Name): Unit = { - writeByte(name.toTermName.info.tag) + val tag = name.toTermName.info.extractor.tag + writeByte(tag) name.toTermName match { case name: SimpleTermName => val bytes = @@ -58,17 +62,23 @@ class NameBuffer extends TastyBuffer(10000) { else Codec.toUTF8(chrs, name.start, name.length) writeNat(bytes.length) writeBytes(bytes, bytes.length) - case AnyQualifiedName(prefix, info) => - withLength { writeNameRef(prefix); writeNameRef(info.name) } - case SignedName(original, Signature(params, result)) => - withLength( - { writeNameRef(original); writeNameRef(result); params.foreach(writeNameRef) }, - if ((params.length + 2) * maxIndexWidth <= maxNumInByte) 1 else 2) + case AnyQualifiedName(prefix, name) => + withLength { writeNameRef(prefix); writeNameRef(name) } + case AnyUniqueName(original, separator, num) => + withLength { + writeNameRef(separator.toTermName) + writeNat(num) + if (original.nonEmpty) writeNameRef(original) + } case DefaultGetterName(method, paramNumber) => withLength { writeNameRef(method); writeNat(paramNumber) } case VariantName(original, sign) => withLength { writeNameRef(original); writeNat(sign + 1) } - case DerivedTermName(original, info) => + case SignedName(original, Signature(params, result)) => + withLength( + { writeNameRef(original); writeNameRef(result); params.foreach(writeNameRef) }, + if ((params.length + 2) * maxIndexWidth <= maxNumInByte) 1 else 2) + case DerivedTermName(original, _) => withLength { writeNameRef(original) } } } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index d0fee04df7b9..18d4a6344b71 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -33,11 +33,11 @@ Macro-format: QUALIFIED Length qualified_NameRef selector_NameRef SIGNED Length original_NameRef resultSig_NameRef paramSig_NameRef* EXPANDED Length original_NameRef + UNIQUE Length separator_NameRef num_Nat original_NameRef? OBJECTCLASS Length module_NameRef SUPERACCESSOR Length accessed_NameRef DEFAULTGETTER Length method_NameRef paramNumber_Nat SHADOWED Length original_NameRef - MANGLED Length mangle_NameRef name_NameRef ... NameRef = Nat // ordinal number of name in name table, starting from 1. @@ -231,7 +231,6 @@ object TastyFormat { final val SUPERACCESSOR = 20 final val INITIALIZER = 21 final val SHADOWED = 22 - final val LOCALDUMMY = 23 final val AVOIDCLASH = 27 final val OBJECTCLASS = 29 diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala index 7ebf3a2eaea9..756b7db5c8e7 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala @@ -5,7 +5,7 @@ package tasty import scala.collection.mutable import TastyFormat._ import TastyBuffer.NameRef -import Names.{Name, TermName, termName} +import Names.{Name, TermName, termName, EmptyTermName} import NameExtractors._ import java.util.UUID @@ -55,6 +55,12 @@ class TastyUnpickler(reader: TastyReader) { FlattenedName(readName(), readName().asSimpleName) case EXPANDED => ExpandedName(readName(), readName().asSimpleName) + case UNIQUE => + val separator = readName().toString + val num = readNat() + val originals = until(end)(readName()) + val original = if (originals.isEmpty) EmptyTermName else originals.head + uniqueExtractorOfSeparator(separator)(original, num) case DEFAULTGETTER => DefaultGetterName(readName(), readNat()) case VARIANT => @@ -67,7 +73,7 @@ class TastyUnpickler(reader: TastyReader) { if (sig == Signature.NotAMethod) sig = Signature.NotAMethod SignedName(original, sig) case _ => - extractorOfTag(tag)(readName()) + simpleExtractorOfTag(tag)(readName()) } assert(currentAddr == end, s"bad name $result $start $currentAddr $end") result diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 3e3673e5e11a..d0451dd60388 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -12,6 +12,7 @@ import core._ import Flags._ import Contexts._ import Names._ +import NameExtractors.WildcardParamName import ast.{Positioned, Trees, untpd} import ast.Trees._ import Decorators._ @@ -1168,7 +1169,7 @@ object Parsers { def bindingName(): TermName = if (in.token == USCORE) { in.nextToken() - ctx.freshName(nme.USCORE_PARAM_PREFIX).toTermName + WildcardParamName.fresh() } else ident() @@ -1224,7 +1225,7 @@ object Parsers { path(thisOK = true) case USCORE => val start = in.skipToken() - val pname = ctx.freshName(nme.USCORE_PARAM_PREFIX).toTermName + val pname = WildcardParamName.fresh() val param = ValDef(pname, TypeTree(), EmptyTree).withFlags(SyntheticTermParam) .withPos(Position(start)) placeholderParams = param :: placeholderParams @@ -1705,7 +1706,7 @@ object Parsers { if (isConcreteOwner || in.token != USCORE) ident().toTypeName else { in.nextToken() - ctx.freshName(nme.USCORE_PARAM_PREFIX).toTypeName + WildcardParamName.fresh().toTypeName } val hkparams = typeParamClauseOpt(ParamOwner.TypeParam) val bounds = diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 20e657ce705c..ec9257acf52f 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -264,7 +264,7 @@ class PlainPrinter(_ctx: Context) extends Printer { if (idx >= 0) selfRecName(idx + 1) else "{...}.this" // TODO move underlying type to an addendum, e.g. ... z3 ... where z3: ... case tp: SkolemType => - if (homogenizedView) toText(tp.info) else tp.repr + if (homogenizedView) toText(tp.info) else toText(tp.repr) } } diff --git a/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala b/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala index cd05589c3d3b..368250cdfc5e 100644 --- a/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala +++ b/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala @@ -12,6 +12,7 @@ import core.SymDenotations._ import core.StdNames.nme import core.Names._ import core.NameOps._ +import core.NameExtractors.TempResultName import ast.Trees._ import SymUtils._ import collection.{ mutable, immutable } @@ -138,7 +139,7 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer { thisTransfo val Select(_, nme.elem) = qual recur(qual) case Select(_, nme.elem) if refInfo.boxedRefClasses.contains(lhs.symbol.maybeOwner) => - val tempDef = transformFollowing(SyntheticValDef(ctx.freshName("ev$").toTermName, tree.rhs)) + val tempDef = transformFollowing(SyntheticValDef(TempResultName.fresh(), tree.rhs)) transformFollowing(Block(tempDef :: Nil, cpy.Assign(tree)(lhs, ref(tempDef.symbol)))) case _ => tree diff --git a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala index 2035fb04b0bf..357baa3df0e3 100644 --- a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala @@ -10,6 +10,7 @@ import Contexts._ import Symbols._ import Decorators._ import NameOps._ +import NameExtractors._ import StdNames.nme import rewrite.Rewrites.patch import util.Positions.Position @@ -106,7 +107,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { */ def transformSyntheticModule(tree: ValOrDefDef)(implicit ctx: Context) = { val sym = tree.symbol - val holderSymbol = ctx.newSymbol(sym.owner, sym.asTerm.name.lazyLocalName, + val holderSymbol = ctx.newSymbol(sym.owner, LazyLocalName.fresh(sym.asTerm.name), Flags.Synthetic, sym.info.widen.resultType).enteredAfter(this) val field = ValDef(holderSymbol, tree.rhs.changeOwnerAfter(sym, holderSymbol, this)) val getter = DefDef(sym.asTerm, ref(holderSymbol)) @@ -119,8 +120,9 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { */ def transformLocalDef(x: ValOrDefDef)(implicit ctx: Context) = { val valueInitter = x.rhs - val holderName = ctx.freshName(x.name.asTermName.lazyLocalName).toTermName - val initName = ctx.freshName(x.name ++ StdNames.nme.LAZY_LOCAL_INIT).toTermName + val xname = x.name.asTermName + val holderName = LazyLocalName.fresh(xname) + val initName = LazyLocalInitName.fresh(xname) val tpe = x.tpe.widen.resultType.widen val holderType = @@ -211,7 +213,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { val claz = x.symbol.owner.asClass val tpe = x.tpe.widen.resultType.widen assert(!(x.symbol is Flags.Mutable)) - val containerName = ctx.freshName(x.name.asTermName.lazyLocalName).toTermName + val containerName = LazyLocalName.fresh(x.name.asTermName) val containerSymbol = ctx.newSymbol(claz, containerName, x.symbol.flags &~ containerFlagsMask | containerFlags | Flags.Private, tpe, coord = x.symbol.coord @@ -223,7 +225,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { Thicket(containerTree, slowPath) } else { - val flagName = ctx.freshName(x.name ++ StdNames.nme.BITMAP_PREFIX).toTermName + val flagName = LazyBitMapName.fresh(x.name.asTermName) val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags | Flags.Private, defn.BooleanType).enteredAfter(this) val flag = ValDef(flagSymbol, Literal(Constants.Constant(false))) val slowPath = DefDef(x.symbol.asTerm, mkNonThreadSafeDef(ref(containerSymbol), ref(flagSymbol), x.rhs)) @@ -376,7 +378,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { appendOffsetDefs += (claz -> new OffsetInfo(List(offsetTree), ord)) } - val containerName = ctx.freshName(x.name.asTermName.lazyLocalName).toTermName + val containerName = LazyLocalName.fresh(x.name.asTermName) val containerSymbol = ctx.newSymbol(claz, containerName, x.symbol.flags &~ containerFlagsMask | containerFlags, tpe, coord = x.symbol.coord).enteredAfter(this) val containerTree = ValDef(containerSymbol, defaultValue(tpe)) diff --git a/compiler/src/dotty/tools/dotc/transform/LiftTry.scala b/compiler/src/dotty/tools/dotc/transform/LiftTry.scala index d011956146e8..61554f5ce55f 100644 --- a/compiler/src/dotty/tools/dotc/transform/LiftTry.scala +++ b/compiler/src/dotty/tools/dotc/transform/LiftTry.scala @@ -8,6 +8,7 @@ import core.Contexts._ import core.Types._ import core.Flags._ import core.Decorators._ +import core.NameExtractors.LiftedTreeName import NonLocalReturns._ /** Lifts try's that might be executed on non-empty expression stacks @@ -56,7 +57,7 @@ class LiftTry extends MiniPhase with IdentityDenotTransformer { thisTransform => if (needLift) { ctx.debuglog(i"lifting tree at ${tree.pos}, current owner = ${ctx.owner}") val fn = ctx.newSymbol( - ctx.owner, ctx.freshName("liftedTree").toTermName, Synthetic | Method, + ctx.owner, LiftedTreeName.fresh(), Synthetic | Method, MethodType(Nil, tree.tpe.widenIfUnstable), coord = tree.pos) tree.changeOwnerAfter(ctx.owner, fn, thisTransform) Block(DefDef(fn, tree) :: Nil, ref(fn).appliedToNone) diff --git a/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala b/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala index b0ee0930d38d..652320639ecf 100644 --- a/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala +++ b/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala @@ -55,6 +55,7 @@ class MoveStatics extends MiniPhaseTransform with SymTransformer { thisTransform } def move(module: TypeDef, companion: TypeDef): List[Tree] = { + assert(companion ne module) if (!module.symbol.is(Flags.Module)) move(companion, module) else { val allMembers = diff --git a/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala b/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala index 7680e283e530..945504743c3f 100644 --- a/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala +++ b/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala @@ -5,6 +5,7 @@ import core._ import Contexts._, Symbols._, Types._, Flags._, Decorators._, StdNames._, Constants._, Phases._ import TreeTransforms._ import ast.Trees._ +import NameExtractors.NonLocalReturnKeyName import collection.mutable object NonLocalReturns { @@ -38,7 +39,7 @@ class NonLocalReturns extends MiniPhaseTransform { thisTransformer => private def nonLocalReturnKey(meth: Symbol)(implicit ctx: Context) = nonLocalReturnKeys.getOrElseUpdate(meth, ctx.newSymbol( - meth, ctx.freshName("nonLocalReturnKey").toTermName, Synthetic, defn.ObjectType, coord = meth.pos)) + meth, NonLocalReturnKeyName.fresh(), Synthetic, defn.ObjectType, coord = meth.pos)) /** Generate a non-local return throw with given return expression from given method. * I.e. for the method's non-local return key, generate: diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index dbc7666f77f7..f93eac0a268a 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -11,6 +11,7 @@ import core.Symbols._ import core.Types._ import core.Constants._ import core.StdNames._ +import core.NameExtractors._ import dotty.tools.dotc.ast.{untpd, TreeTypeMap, tpd} import dotty.tools.dotc.core import dotty.tools.dotc.core.DenotTransformers.DenotTransformer @@ -70,16 +71,14 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { class OptimizingMatchTranslator extends MatchOptimizer/*(val typer: analyzer.Typer)*/ with MatchTranslator trait CodegenCore { - private var ctr = 0 // left for debugging // assert(owner ne null); assert(owner ne NoSymbol) - def freshSym(pos: Position, tp: Type = NoType, prefix: String = "x", owner: Symbol = ctx.owner) = { - ctr += 1 - ctx.newSymbol(owner, ctx.freshName(prefix + ctr).toTermName, Flags.Synthetic | Flags.Case, tp, coord = pos) + def freshSym(pos: Position, tp: Type = NoType, unique: UniqueNameExtractor = PatMatStdBinderName, owner: Symbol = ctx.owner) = { + ctx.newSymbol(owner, unique.fresh(), Flags.Synthetic | Flags.Case, tp, coord = pos) } - def newSynthCaseLabel(name: String, tpe: Type, owner: Symbol = ctx.owner) = - ctx.newSymbol(owner, ctx.freshName(name).toTermName, Flags.Label | Flags.Synthetic | Flags.Method, tpe).asTerm + def newSynthCaseLabel(unique: UniqueNameExtractor, tpe: Type, owner: Symbol = ctx.owner) = + ctx.newSymbol(owner, unique.fresh(), Flags.Label | Flags.Synthetic | Flags.Method, tpe).asTerm //NoSymbol.newLabel(freshName(name), NoPosition) setFlag treeInfo.SYNTH_CASE_FLAGS // codegen relevant to the structure of the translation (how extractors are combined) @@ -189,7 +188,8 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { //NoSymbol.newValueParameter(newTermName("x"), NoPosition, newFlags = SYNTHETIC) setInfo restpe.withoutAnnotations - val caseSyms: List[TermSymbol] = cases.scanLeft(ctx.owner.asTerm)((curOwner, nextTree) => newSynthCaseLabel(ctx.freshName("case"), MethodType(Nil, restpe), curOwner)).tail + val caseSyms: List[TermSymbol] = cases.scanLeft(ctx.owner.asTerm)((curOwner, nextTree) => + newSynthCaseLabel(PatMatCaseName, MethodType(Nil, restpe), curOwner)).tail // must compute catchAll after caseLabels (side-effects nextCase) // catchAll.isEmpty iff no synthetic default case needed (the (last) user-defined case is a default) @@ -197,7 +197,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { val catchAllDef = matchFailGen.map { _(scrutSym) } .getOrElse(Throw(New(defn.MatchErrorType, List(ref(scrutSym))))) - val matchFail = newSynthCaseLabel(ctx.freshName("matchFail"), MethodType(Nil, restpe)) + val matchFail = newSynthCaseLabel(PatMatMatchFailName, MethodType(Nil, restpe)) val catchAllDefBody = DefDef(matchFail, catchAllDef) val nextCases = (caseSyms.tail ::: List(matchFail)).map(ref(_).ensureApplied) @@ -249,7 +249,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { val isEmptyDenot = extractorMember(prev.tpe, nme.isEmpty) assert(getDenot.exists && isEmptyDenot.exists, i"${prev.tpe}") - val tmpSym = freshSym(prev.pos, prev.tpe, "o") + val tmpSym = freshSym(prev.pos, prev.tpe, PatMatOName) val prevValue = ref(tmpSym).select(getDenot.symbol).ensureApplied Block( @@ -1056,9 +1056,9 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { } def newBoundTree(tree: Tree, pt: Type): BoundTree = tree match { - case SymbolBound(sym, Typed(subpat, tpe)) => BoundTree(freshSym(tree.pos, pt, prefix = "pi"), tree) + case SymbolBound(sym, Typed(subpat, tpe)) => BoundTree(freshSym(tree.pos, pt, PatMatPiName), tree) case SymbolBound(sym, expr) => BoundTree(sym, expr) - case _ => BoundTree(freshSym(tree.pos, pt, prefix = "p"), tree) + case _ => BoundTree(freshSym(tree.pos, pt, PatMatPName), tree) } final case class BoundTree(binder: Symbol, tree: Tree) { @@ -1204,7 +1204,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { val selectorTp = sel.tpe.widen.deAnonymize/*withoutAnnotations*/ - val selectorSym = freshSym(sel.pos, selectorTp, "selector") + val selectorSym = freshSym(sel.pos, selectorTp, PatMatSelectorName) val (nonSyntheticCases, defaultOverride) = cases match { case init :+ last if isSyntheticDefaultCase(last) => (init, Some(((scrut: Symbol) => last.body))) diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index 8a695bf2270b..87e9c1013755 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -1,16 +1,17 @@ -package dotty.tools.dotc.transform - -import dotty.tools.dotc.ast.Trees._ -import dotty.tools.dotc.ast.{TreeTypeMap, tpd} -import dotty.tools.dotc.core.Contexts.Context -import dotty.tools.dotc.core.Decorators._ -import dotty.tools.dotc.core.DenotTransformers.DenotTransformer -import dotty.tools.dotc.core.Denotations.SingleDenotation -import dotty.tools.dotc.core.Symbols._ -import dotty.tools.dotc.core.Types._ -import dotty.tools.dotc.core._ -import dotty.tools.dotc.transform.TailRec._ -import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo} +package dotty.tools.dotc +package transform + +import ast.Trees._ +import ast.{TreeTypeMap, tpd} +import core._ +import Contexts.Context +import Decorators._ +import DenotTransformers.DenotTransformer +import Denotations.SingleDenotation +import Symbols._ +import Types._ +import NameExtractors.TailLabelName +import TreeTransforms.{MiniPhaseTransform, TransformerInfo} /** * A Tail Rec Transformer @@ -62,6 +63,7 @@ import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, Transforme *

*/ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParameterization { thisTransform => + import TailRec._ import dotty.tools.dotc.ast.tpd._ @@ -70,7 +72,6 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete override def phaseName: String = "tailrec" override def treeTransformPhase = thisTransform // TODO Make sure tailrec runs at next phase. - final val labelPrefix = "tailLabel" final val labelFlags = Flags.Synthetic | Flags.Label /** Symbols of methods that have @tailrec annotatios inside */ @@ -87,12 +88,12 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete tree } - private def mkLabel(method: Symbol, abstractOverClass: Boolean)(implicit c: Context): TermSymbol = { - val name = c.freshName(labelPrefix) + private def mkLabel(method: Symbol, abstractOverClass: Boolean)(implicit ctx: Context): TermSymbol = { + val name = TailLabelName.fresh() if (method.owner.isClass) - c.newSymbol(method, name.toTermName, labelFlags, fullyParameterizedType(method.info, method.enclosingClass.asClass, abstractOverClass, liftThisType = false)) - else c.newSymbol(method, name.toTermName, labelFlags, method.info) + ctx.newSymbol(method, name.toTermName, labelFlags, fullyParameterizedType(method.info, method.enclosingClass.asClass, abstractOverClass, liftThisType = false)) + else ctx.newSymbol(method, name.toTermName, labelFlags, method.info) } override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { diff --git a/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala b/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala index 9a6ecef51e6b..a651c0c74aa5 100644 --- a/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala +++ b/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala @@ -5,6 +5,7 @@ import core.Symbols._ import core.StdNames._ import ast.Trees._ import core.Types._ +import core.NameExtractors.ExceptionBinderName import dotty.tools.dotc.core.Decorators._ import dotty.tools.dotc.core.Flags import dotty.tools.dotc.core.Contexts.Context @@ -83,7 +84,7 @@ class TryCatchPatterns extends MiniPhaseTransform { implicit ctx: Context, info: TransformerInfo): Option[CaseDef] = { if (patternMatchCases.isEmpty) None else { - val exName = ctx.freshName("ex").toTermName + val exName = ExceptionBinderName.fresh() val fallbackSelector = ctx.newSymbol(ctx.owner, exName, Flags.Synthetic | Flags.Case, defn.ThrowableType, coord = pos) val sel = Ident(fallbackSelector.termRef).withPos(pos) diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index 5aee0fd5479e..3f3a0cce3f06 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -12,6 +12,7 @@ import Symbols._ import Decorators._ import Names._ import StdNames._ +import NameExtractors.UniqueName import Trees._ import Inferencing._ import util.Positions._ @@ -21,10 +22,10 @@ object EtaExpansion { import tpd._ - private def lift(defs: mutable.ListBuffer[Tree], expr: Tree, prefix: String = "")(implicit ctx: Context): Tree = + private def lift(defs: mutable.ListBuffer[Tree], expr: Tree, prefix: TermName = EmptyTermName)(implicit ctx: Context): Tree = if (isPureExpr(expr)) expr else { - val name = ctx.freshName(prefix).toTermName + val name = UniqueName.fresh(prefix) val liftedType = fullyDefinedType(expr.tpe.widen, "lifted expression", expr.pos) val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, liftedType, coord = positionCoord(expr.pos)) defs += ValDef(sym, expr) @@ -48,7 +49,7 @@ object EtaExpansion { } /** Lift a function argument, stripping any NamedArg wrapper */ - def liftArg(defs: mutable.ListBuffer[Tree], arg: Tree, prefix: String = "")(implicit ctx: Context): Tree = + def liftArg(defs: mutable.ListBuffer[Tree], arg: Tree, prefix: TermName = EmptyTermName)(implicit ctx: Context): Tree = arg match { case arg @ NamedArg(name, arg1) => cpy.NamedArg(arg)(name, lift(defs, arg1, prefix)) case arg => lift(defs, arg, prefix) @@ -62,7 +63,7 @@ object EtaExpansion { case mt: MethodType => (args, mt.paramNames, mt.paramInfos).zipped map { (arg, name, tp) => if (tp.isInstanceOf[ExprType]) arg - else liftArg(defs, arg, if (name contains '$') "" else name.toString + "$") + else liftArg(defs, arg, if (name contains '$') EmptyTermName else name) } case _ => args map (liftArg(defs, _)) diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index f6d65fbb99cc..ad65af98cd42 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -15,6 +15,7 @@ import StdNames.nme import Contexts.Context import Names.{Name, TermName} import NameOps._ +import NameExtractors.InlineAccessorName import SymDenotations.SymDenotation import Annotations._ import transform.ExplicitOuter @@ -49,8 +50,7 @@ object Inliner { sym.is(AccessFlags) || sym.privateWithin.exists /** The name of the next accessor to be generated */ - def accessorName(implicit ctx: Context) = - ctx.freshNames.newName(inlineMethod.name.asTermName.inlineAccessorName.toString) + def accessorName(implicit ctx: Context) = InlineAccessorName.fresh(inlineMethod.name.asTermName) /** A fresh accessor symbol. * diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index ab342dc176ec..03357fee31f6 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -5,6 +5,7 @@ package typer import core._ import ast._ import Contexts._, Types._, Flags._, Denotations._, Names._, StdNames._, NameOps._, Symbols._ +import NameExtractors.DepParamName import Trees._ import Constants._ import Scopes._ @@ -401,7 +402,7 @@ object ProtoTypes { /** Create a new TypeParamRef that represents a dependent method parameter singleton */ def newDepTypeParamRef(tp: Type)(implicit ctx: Context): TypeParamRef = { - val poly = PolyType(ctx.freshName(nme.DEP_PARAM_PREFIX).toTypeName :: Nil)( + val poly = PolyType(DepParamName.fresh().toTypeName :: Nil)( pt => TypeBounds.upper(AndType(tp, defn.SingletonType)) :: Nil, pt => defn.AnyType) ctx.typeComparer.addToConstraint(poly, Nil) diff --git a/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala b/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala index 8892a570e15c..529e30f05a02 100644 --- a/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala +++ b/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala @@ -3,9 +3,12 @@ package dotc package util import scala.collection.mutable +import core.Names.TermName +import core.NameExtractors.UniqueNameExtractor +import core.StdNames.str -trait FreshNameCreator { - def newName(prefix: String = ""): String +abstract class FreshNameCreator { + def newName(prefix: TermName, unique: UniqueNameExtractor): TermName } object FreshNameCreator { @@ -18,11 +21,11 @@ object FreshNameCreator { * that the returned name has never been returned by a previous * call to this function (provided the prefix does not end in a digit). */ - def newName(prefix: String): String = { - val safePrefix = prefix.replaceAll("""[<>]""", """\$""") - counters(safePrefix) += 1 - val counter = counters(safePrefix) - if (prefix.isEmpty) "$" + counter + "$" else safePrefix + counter + def newName(prefix: TermName, unique: UniqueNameExtractor): TermName = { + val key = str.sanitize(prefix.toString + unique.separator) + counters(key) += 1 + val counter = counters(key) + prefix.derived(unique.NumberedInfo(counter)) } } } From 3fe4e061ef90b8dde10b2e9542f17a34c0fbcb5d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 28 Mar 2017 22:35:15 +0200 Subject: [PATCH 35/68] Rename NameExtractor -> NameKind --- .../src/dotty/tools/dotc/ast/Desugar.scala | 2 +- compiler/src/dotty/tools/dotc/ast/tpd.scala | 2 +- .../dotty/tools/dotc/core/Denotations.scala | 2 +- .../tools/dotc/core/NameExtractors.scala | 131 +++++++++--------- .../src/dotty/tools/dotc/core/NameOps.scala | 4 +- .../src/dotty/tools/dotc/core/Names.scala | 28 ++-- .../tools/dotc/core/SymDenotations.scala | 6 +- .../src/dotty/tools/dotc/core/Symbols.scala | 2 +- .../tools/dotc/core/TypeApplications.scala | 2 +- .../src/dotty/tools/dotc/core/Types.scala | 2 +- .../dotc/core/classfile/ClassfileParser.scala | 2 +- .../tools/dotc/core/tasty/NameBuffer.scala | 4 +- .../dotc/core/tasty/TastyUnpickler.scala | 6 +- .../tools/dotc/core/tasty/TreePickler.scala | 2 +- .../tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- .../dotty/tools/dotc/parsing/Parsers.scala | 3 +- .../dotc/transform/AugmentScala2Traits.scala | 2 +- .../tools/dotc/transform/CapturedVars.scala | 2 +- .../dotty/tools/dotc/transform/Erasure.scala | 2 +- .../tools/dotc/transform/FirstTransform.scala | 2 +- .../dotty/tools/dotc/transform/LazyVals.scala | 2 +- .../dotty/tools/dotc/transform/LiftTry.scala | 2 +- .../dotty/tools/dotc/transform/Mixin.scala | 2 +- .../dotc/transform/NonLocalReturns.scala | 2 +- .../tools/dotc/transform/PatternMatcher.scala | 6 +- .../tools/dotc/transform/ResolveSuper.scala | 2 +- .../dotty/tools/dotc/transform/SymUtils.scala | 2 +- .../dotty/tools/dotc/transform/TailRec.scala | 2 +- .../dotc/transform/TryCatchPatterns.scala | 2 +- .../dotty/tools/dotc/typer/EtaExpansion.scala | 2 +- .../src/dotty/tools/dotc/typer/Inliner.scala | 2 +- .../dotty/tools/dotc/typer/ProtoTypes.scala | 2 +- .../src/dotty/tools/dotc/typer/Typer.scala | 2 +- .../tools/dotc/util/FreshNameCreator.scala | 6 +- 34 files changed, 121 insertions(+), 123 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 3671ccb73965..288fadfd0863 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -6,7 +6,7 @@ import core._ import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ import Decorators._ -import NameExtractors.{UniqueName, EvidenceParamName} +import NameKinds.{UniqueName, EvidenceParamName} import language.higherKinds import typer.FrontEnd import collection.mutable.ListBuffer diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index e4c6dd6796f6..cd0115a99ac2 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -12,7 +12,7 @@ import Denotations._, Decorators._, DenotTransformers._ import collection.mutable import util.{Property, SourceFile, NoSource} import typer.ErrorReporting._ -import NameExtractors.TempResultName +import NameKinds.TempResultName import scala.annotation.tailrec import scala.io.Codec diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 42837122aeac..fca77fc066d7 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -6,7 +6,7 @@ import SymDenotations.{ SymDenotation, ClassDenotation, NoDenotation } import Contexts.{Context, ContextBase} import Names._ import NameOps._ -import NameExtractors._ +import NameKinds._ import StdNames._ import Symbols.NoSymbol import Symbols._ diff --git a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala index 1439ce002a2e..7350087a5b5f 100644 --- a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala +++ b/compiler/src/dotty/tools/dotc/core/NameExtractors.scala @@ -11,22 +11,22 @@ import Decorators._ import Contexts.Context import collection.mutable -object NameExtractors { +object NameKinds { - @sharable private val simpleExtractors = new mutable.HashMap[Int, ClassifiedNameExtractor] - @sharable private val uniqueExtractors = new mutable.HashMap[String, UniqueNameExtractor] - @sharable private val qualifiedExtractors = new mutable.HashMap[String, QualifiedNameExtractor] + @sharable private val simpleNameKinds = new mutable.HashMap[Int, ClassifiedNameKind] + @sharable private val uniqueNameKinds = new mutable.HashMap[String, UniqueNameKind] + @sharable private val qualifiedNameKinds = new mutable.HashMap[String, QualifiedNameKind] abstract class NameInfo extends DotClass { - def extractor: NameExtractor + def kind: NameKind def mkString(underlying: TermName): String def map(f: SimpleTermName => SimpleTermName): NameInfo = this } - abstract class NameExtractor(val tag: Int) extends DotClass { self => + abstract class NameKind(val tag: Int) extends DotClass { self => type ThisInfo <: Info class Info extends NameInfo { this: ThisInfo => - def extractor = self + def kind = self def mkString(underlying: TermName) = self.mkString(underlying, this) override def toString = infoString } @@ -35,14 +35,14 @@ object NameExtractors { def infoString: String } - object SimpleTermNameExtractor extends NameExtractor(UTF8) { self => + object SimpleTermNameKind extends NameKind(UTF8) { self => type ThisInfo = Info val info = new Info def mkString(underlying: TermName, info: ThisInfo) = unsupported("mkString") def infoString = unsupported("infoString") } - abstract class ClassifiedNameExtractor(tag: Int, val infoString: String) extends NameExtractor(tag) { + abstract class ClassifiedNameKind(tag: Int, val infoString: String) extends NameKind(tag) { type ThisInfo = Info val info = new Info def apply(qual: TermName) = @@ -51,17 +51,17 @@ object NameExtractors { case DerivedTermName(underlying, `info`) => Some(underlying) case _ => None } - simpleExtractors(tag) = this + simpleNameKinds(tag) = this } - class PrefixNameExtractor(tag: Int, prefix: String, optInfoString: String = "") - extends ClassifiedNameExtractor(tag, if (optInfoString.isEmpty) s"Prefix $prefix" else optInfoString) { + class PrefixNameKind(tag: Int, prefix: String, optInfoString: String = "") + extends ClassifiedNameKind(tag, if (optInfoString.isEmpty) s"Prefix $prefix" else optInfoString) { def mkString(underlying: TermName, info: ThisInfo) = underlying.mapLast(n => termName(prefix + n.toString)).toString } - class SuffixNameExtractor(tag: Int, suffix: String, optInfoString: String = "") - extends ClassifiedNameExtractor(tag, if (optInfoString.isEmpty) s"Suffix $suffix" else optInfoString) { + class SuffixNameKind(tag: Int, suffix: String, optInfoString: String = "") + extends ClassifiedNameKind(tag, if (optInfoString.isEmpty) s"Suffix $suffix" else optInfoString) { def mkString(underlying: TermName, info: ThisInfo) = underlying.toString ++ suffix } @@ -69,8 +69,8 @@ object NameExtractors { val name: SimpleTermName } - class QualifiedNameExtractor(tag: Int, val separator: String) - extends NameExtractor(tag) { + class QualifiedNameKind(tag: Int, val separator: String) + extends NameKind(tag) { type ThisInfo = QualInfo case class QualInfo(val name: SimpleTermName) extends Info with QualifiedInfo { override def map(f: SimpleTermName => SimpleTermName): NameInfo = new QualInfo(f(name)) @@ -89,7 +89,7 @@ object NameExtractors { s"$underlying$separator${info.name}" def infoString = s"Qualified $separator" - qualifiedExtractors(separator) = this + qualifiedNameKinds(separator) = this } object AnyQualifiedName { @@ -100,14 +100,13 @@ object NameExtractors { } } - trait NumberedInfo { + trait NumberedInfo extends NameInfo { def num: Int - def extractor: NameExtractor } - abstract class NumberedNameExtractor(tag: Int, val infoString: String) extends NameExtractor(tag) { self => + abstract class NumberedNameKind(tag: Int, val infoString: String) extends NameKind(tag) { self => type ThisInfo = NumberedInfo - case class NumberedInfo(val num: Int) extends Info with NameExtractors.NumberedInfo { + case class NumberedInfo(val num: Int) extends Info with NameKinds.NumberedInfo { override def toString = s"$infoString $num" } def apply(qual: TermName, num: Int) = @@ -118,8 +117,8 @@ object NameExtractors { } } - case class UniqueNameExtractor(val separator: String) - extends NumberedNameExtractor(UNIQUE, s"Unique $separator") { + case class UniqueNameKind(val separator: String) + extends NumberedNameKind(UNIQUE, s"Unique $separator") { override def definesNewName = true def mkString(underlying: TermName, info: ThisInfo) = { val safePrefix = str.sanitize(underlying.toString + separator) @@ -129,62 +128,62 @@ object NameExtractors { def fresh(prefix: TermName = EmptyTermName)(implicit ctx: Context): TermName = ctx.freshNames.newName(prefix, this) - uniqueExtractors(separator) = this + uniqueNameKinds(separator) = this } object AnyUniqueName { def unapply(name: DerivedTermName): Option[(TermName, String, Int)] = name match { case DerivedTermName(qual, info: NumberedInfo) => - info.extractor match { - case unique: UniqueNameExtractor => Some((qual, unique.separator, info.num)) + info.kind match { + case unique: UniqueNameKind => Some((qual, unique.separator, info.num)) case _ => None } case _ => None } } - val QualifiedName = new QualifiedNameExtractor(QUALIFIED, ".") - val FlattenedName = new QualifiedNameExtractor(FLATTENED, "$") - val ExpandedName = new QualifiedNameExtractor(EXPANDED, str.EXPAND_SEPARATOR) - val TraitSetterName = new QualifiedNameExtractor(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR) + val QualifiedName = new QualifiedNameKind(QUALIFIED, ".") + val FlattenedName = new QualifiedNameKind(FLATTENED, "$") + val ExpandedName = new QualifiedNameKind(EXPANDED, str.EXPAND_SEPARATOR) + val TraitSetterName = new QualifiedNameKind(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR) - val UniqueName = new UniqueNameExtractor("$") { + val UniqueName = new UniqueNameKind("$") { override def mkString(underlying: TermName, info: ThisInfo) = if (underlying.isEmpty) "$" + info.num + "$" else super.mkString(underlying, info) } - val InlineAccessorName = new UniqueNameExtractor("$_inlineAccessor_$") - val TempResultName = new UniqueNameExtractor("ev$") - val EvidenceParamName = new UniqueNameExtractor("evidence$") - val DepParamName = new UniqueNameExtractor("") - val LazyImplicitName = new UniqueNameExtractor("$_lazy_implicit_$") - val LazyLocalName = new UniqueNameExtractor("$lzy") - val LazyLocalInitName = new UniqueNameExtractor("$lzyINIT") - val LazyFieldOffsetName = new UniqueNameExtractor("$OFFSET") - val LazyBitMapName = new UniqueNameExtractor(nme.BITMAP_PREFIX.toString) - val NonLocalReturnKeyName = new UniqueNameExtractor("nonLocalReturnKey") - val WildcardParamName = new UniqueNameExtractor("_$") - val TailLabelName = new UniqueNameExtractor("tailLabel") - val ExceptionBinderName = new UniqueNameExtractor("ex") - val SkolemName = new UniqueNameExtractor("?") - val LiftedTreeName = new UniqueNameExtractor("liftedTree") - - val PatMatStdBinderName = new UniqueNameExtractor("x") - val PatMatPiName = new UniqueNameExtractor("pi") // FIXME: explain what this is - val PatMatPName = new UniqueNameExtractor("p") // FIXME: explain what this is - val PatMatOName = new UniqueNameExtractor("o") // FIXME: explain what this is - val PatMatCaseName = new UniqueNameExtractor("case") - val PatMatMatchFailName = new UniqueNameExtractor("matchFail") - val PatMatSelectorName = new UniqueNameExtractor("selector") - - object DefaultGetterName extends NumberedNameExtractor(DEFAULTGETTER, "DefaultGetter") { + val InlineAccessorName = new UniqueNameKind("$_inlineAccessor_$") + val TempResultName = new UniqueNameKind("ev$") + val EvidenceParamName = new UniqueNameKind("evidence$") + val DepParamName = new UniqueNameKind("") + val LazyImplicitName = new UniqueNameKind("$_lazy_implicit_$") + val LazyLocalName = new UniqueNameKind("$lzy") + val LazyLocalInitName = new UniqueNameKind("$lzyINIT") + val LazyFieldOffsetName = new UniqueNameKind("$OFFSET") + val LazyBitMapName = new UniqueNameKind(nme.BITMAP_PREFIX.toString) + val NonLocalReturnKeyName = new UniqueNameKind("nonLocalReturnKey") + val WildcardParamName = new UniqueNameKind("_$") + val TailLabelName = new UniqueNameKind("tailLabel") + val ExceptionBinderName = new UniqueNameKind("ex") + val SkolemName = new UniqueNameKind("?") + val LiftedTreeName = new UniqueNameKind("liftedTree") + + val PatMatStdBinderName = new UniqueNameKind("x") + val PatMatPiName = new UniqueNameKind("pi") // FIXME: explain what this is + val PatMatPName = new UniqueNameKind("p") // FIXME: explain what this is + val PatMatOName = new UniqueNameKind("o") // FIXME: explain what this is + val PatMatCaseName = new UniqueNameKind("case") + val PatMatMatchFailName = new UniqueNameKind("matchFail") + val PatMatSelectorName = new UniqueNameKind("selector") + + object DefaultGetterName extends NumberedNameKind(DEFAULTGETTER, "DefaultGetter") { def mkString(underlying: TermName, info: ThisInfo) = { val prefix = if (underlying.isConstructorName) nme.DEFAULT_GETTER_INIT else underlying prefix.toString + nme.DEFAULT_GETTER + (info.num + 1) } } - object VariantName extends NumberedNameExtractor(VARIANT, "Variant") { + object VariantName extends NumberedNameKind(VARIANT, "Variant") { val varianceToPrefix = Map(-1 -> '-', 0 -> '=', 1 -> '+') val prefixToVariance = Map('-' -> -1, '=' -> 0, '+' -> 1) def mkString(underlying: TermName, info: ThisInfo) = { @@ -192,13 +191,13 @@ object NameExtractors { } } - val SuperAccessorName = new PrefixNameExtractor(SUPERACCESSOR, "super$") - val InitializerName = new PrefixNameExtractor(INITIALIZER, "initial$") - val ShadowedName = new PrefixNameExtractor(SHADOWED, "(shadowed)") - val AvoidClashName = new SuffixNameExtractor(AVOIDCLASH, "$_avoid_name_clash_$") - val ModuleClassName = new SuffixNameExtractor(OBJECTCLASS, "$", optInfoString = "ModuleClass") + val SuperAccessorName = new PrefixNameKind(SUPERACCESSOR, "super$") + val InitializerName = new PrefixNameKind(INITIALIZER, "initial$") + val ShadowedName = new PrefixNameKind(SHADOWED, "(shadowed)") + val AvoidClashName = new SuffixNameKind(AVOIDCLASH, "$_avoid_name_clash_$") + val ModuleClassName = new SuffixNameKind(OBJECTCLASS, "$", optInfoString = "ModuleClass") - object SignedName extends NameExtractor(63) { + object SignedName extends NameKind(63) { /** @param parts resultSig followed by paramsSig */ case class SignedInfo(sig: Signature) extends Info { @@ -217,7 +216,7 @@ object NameExtractors { def infoString: String = "Signed" } - def simpleExtractorOfTag : collection.Map[Int, ClassifiedNameExtractor] = simpleExtractors - def qualifiedExtractorOfSeparator: collection.Map[String, QualifiedNameExtractor] = qualifiedExtractors - def uniqueExtractorOfSeparator : collection.Map[String, UniqueNameExtractor] = uniqueExtractors + def simpleNameKindOfTag : collection.Map[Int, ClassifiedNameKind] = simpleNameKinds + def qualifiedNameKindOfSeparator: collection.Map[String, QualifiedNameKind] = qualifiedNameKinds + def uniqueNameKindOfSeparator : collection.Map[String, UniqueNameKind] = uniqueNameKinds } \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 6f2c753138d0..356b41efb902 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -4,7 +4,7 @@ package core import java.security.MessageDigest import scala.annotation.switch import scala.io.Codec -import Names._, StdNames._, Contexts._, Symbols._, Flags._, NameExtractors._ +import Names._, StdNames._, Contexts._, Symbols._, Flags._, NameKinds._ import Decorators.PreNamedString import util.{Chars, NameTransformer} import Chars.isOperatorPart @@ -136,7 +136,7 @@ object NameOps { def expandedName(prefix: Name, separator: Name = nme.EXPAND_SEPARATOR): N = likeTyped { def qualify(name: SimpleTermName) = - qualifiedExtractorOfSeparator(separator.toString)(prefix.toTermName, name) + qualifiedNameKindOfSeparator(separator.toString)(prefix.toTermName, name) name rewrite { case name: SimpleTermName => qualify(name) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index e4ebe61c2afe..37df9cd241b8 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -19,7 +19,7 @@ import java.util.HashMap //import annotation.volatile object Names { - import NameExtractors._ + import NameKinds._ /** A common class for things that can be turned into names. * Instances are both names and strings, the latter via a decorator. @@ -75,9 +75,9 @@ object Names { def likeKinded(name: Name): ThisName def derived(info: NameInfo): ThisName - def derived(kind: ClassifiedNameExtractor): ThisName = derived(kind.info) - def exclude(kind: NameExtractor): ThisName - def is(kind: NameExtractor): Boolean + def derived(kind: ClassifiedNameKind): ThisName = derived(kind.info) + def exclude(kind: NameKind): ThisName + def is(kind: NameKind): Boolean def debugString: String def toText(printer: Printer): Text = printer.toText(this) @@ -130,7 +130,7 @@ object Names { def likeKinded(name: Name): TermName = name.toTermName - def info: NameInfo = SimpleTermNameExtractor.info + def info: NameInfo = SimpleTermNameKind.info def underlying: TermName = unsupported("underlying") @sharable private var derivedNames: AnyRef /* SimpleMap | j.u.HashMap */ = @@ -174,8 +174,8 @@ object Names { * name as underlying name. */ def derived(info: NameInfo): TermName = { - val thisKind = this.info.extractor - val thatKind = info.extractor + val thisKind = this.info.kind + val thatKind = info.kind if (thisKind.tag < thatKind.tag || thatKind.definesNewName) add(info) else if (thisKind.tag > thatKind.tag) rewrap(underlying.derived(info)) else { @@ -184,15 +184,15 @@ object Names { } } - def exclude(kind: NameExtractor): TermName = { - val thisKind = this.info.extractor + def exclude(kind: NameKind): TermName = { + val thisKind = this.info.kind if (thisKind.tag < kind.tag || thisKind.definesNewName) this else if (thisKind.tag > kind.tag) rewrap(underlying.exclude(kind)) else underlying } - def is(kind: NameExtractor): Boolean = { - val thisKind = this.info.extractor + def is(kind: NameKind): Boolean = { + val thisKind = this.info.kind thisKind == kind || !thisKind.definesNewName && thisKind.tag > kind.tag && underlying.is(kind) } @@ -295,8 +295,8 @@ object Names { def likeKinded(name: Name): TypeName = name.toTypeName def derived(info: NameInfo): TypeName = toTermName.derived(info).toTypeName - def exclude(kind: NameExtractor): TypeName = toTermName.exclude(kind).toTypeName - def is(kind: NameExtractor) = toTermName.is(kind) + def exclude(kind: NameKind): TypeName = toTermName.exclude(kind).toTypeName + def is(kind: NameKind) = toTermName.is(kind) override def toString = toTermName.toString override def debugString = toTermName.debugString + "/T" @@ -512,7 +512,7 @@ object Names { implicit val NameOrdering: Ordering[Name] = new Ordering[Name] { private def compareInfos(x: NameInfo, y: NameInfo): Int = - if (x.extractor.tag != y.extractor.tag) x.extractor.tag - y.extractor.tag + if (x.kind.tag != y.kind.tag) x.kind.tag - y.kind.tag else x match { case x: QualifiedInfo => y match { diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 5e5a5df2d307..3d0b306c0d32 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -4,7 +4,7 @@ package core import Periods._, Contexts._, Symbols._, Denotations._, Names._, NameOps._, Annotations._ import Types._, Flags._, Decorators._, DenotTransformers._, StdNames._, Scopes._, Comments._ -import NameOps._, NameExtractors._ +import NameOps._, NameKinds._ import Scopes.Scope import collection.mutable import collection.immutable.BitSet @@ -406,14 +406,14 @@ object SymDenotations { } var prefix = encl.fullNameSeparated(separator) val fn = - if (qualifiedExtractorOfSeparator.contains(sep)) { + if (qualifiedNameKindOfSeparator.contains(sep)) { if (sep == "$") // duplicate scalac's behavior: don't write a double '$$' for module class members. prefix = prefix.exclude(ModuleClassName) name rewrite { case n: SimpleTermName => val n1 = if (filler.isEmpty) n else termName(filler ++ n) - qualifiedExtractorOfSeparator(sep)(prefix.toTermName, n1) + qualifiedNameKindOfSeparator(sep)(prefix.toTermName, n1) } } else { diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 69d6e8db3c8a..e0d9aca2bbc0 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -19,7 +19,7 @@ import util.Positions._ import DenotTransformers._ import StdNames._ import NameOps._ -import NameExtractors.LazyImplicitName +import NameKinds.LazyImplicitName import ast.tpd.Tree import ast.TreeTypeMap import Constants.Constant diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 0220928a2f94..82051b66c0a7 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -11,7 +11,7 @@ import util.Stats._ import util.common._ import Names._ import NameOps._ -import NameExtractors._ +import NameKinds._ import Flags._ import StdNames.tpnme import util.Positions.Position diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 3f5a3092200d..c8c1886cc512 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -7,7 +7,7 @@ import Symbols._ import Flags._ import Names._ import StdNames._, NameOps._ -import NameExtractors.{ShadowedName, SkolemName} +import NameKinds.{ShadowedName, SkolemName} import Scopes._ import Constants._ import Contexts._ diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index c5194fb93aeb..13315eb3e409 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -5,7 +5,7 @@ package classfile import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._, Decorators._ import SymDenotations._, unpickleScala2.Scala2Unpickler._, Constants._, Annotations._, util.Positions._ -import NameExtractors.ModuleClassName +import NameKinds.ModuleClassName import ast.tpd._ import java.io.{ File, IOException } import java.lang.Integer.toHexString diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index 2fd078befaaf..6df96a9a0129 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala @@ -6,7 +6,7 @@ package tasty import collection.mutable import Names.{Name, chrs, SimpleTermName, DerivedTermName} import NameOps.NameDecorator -import NameExtractors._ +import NameKinds._ import Decorators._ import TastyBuffer._ import scala.io.Codec @@ -53,7 +53,7 @@ class NameBuffer extends TastyBuffer(10000) { def writeNameRef(name: Name): Unit = writeNameRef(nameRefs(name.toTermName)) def pickleNameContents(name: Name): Unit = { - val tag = name.toTermName.info.extractor.tag + val tag = name.toTermName.info.kind.tag writeByte(tag) name.toTermName match { case name: SimpleTermName => diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala index 756b7db5c8e7..a14691ed5561 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala @@ -6,7 +6,7 @@ import scala.collection.mutable import TastyFormat._ import TastyBuffer.NameRef import Names.{Name, TermName, termName, EmptyTermName} -import NameExtractors._ +import NameKinds._ import java.util.UUID object TastyUnpickler { @@ -60,7 +60,7 @@ class TastyUnpickler(reader: TastyReader) { val num = readNat() val originals = until(end)(readName()) val original = if (originals.isEmpty) EmptyTermName else originals.head - uniqueExtractorOfSeparator(separator)(original, num) + uniqueNameKindOfSeparator(separator)(original, num) case DEFAULTGETTER => DefaultGetterName(readName(), readNat()) case VARIANT => @@ -73,7 +73,7 @@ class TastyUnpickler(reader: TastyReader) { if (sig == Signature.NotAMethod) sig = Signature.NotAMethod SignedName(original, sig) case _ => - simpleExtractorOfTag(tag)(readName()) + simpleNameKindOfTag(tag)(readName()) } assert(currentAddr == end, s"bad name $result $start $currentAddr $end") result diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 355eef1cae3b..5d33738c2b59 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -9,7 +9,7 @@ import TastyFormat._ import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annotations._, StdNames.tpnme, NameOps._ import collection.mutable import typer.Inliner -import NameOps._, NameExtractors._ +import NameOps._, NameKinds._ import StdNames.nme import TastyBuffer._ import TypeApplications._ diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index b8e6bbdf0987..96bf29a7081e 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -5,7 +5,7 @@ package tasty import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._ import StdNames._, Denotations._, Flags._, Constants._, Annotations._ -import NameExtractors._ +import NameKinds._ import util.Positions._ import ast.{tpd, Trees, untpd} import Trees._ diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index d0451dd60388..3112be659ab1 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -12,7 +12,7 @@ import core._ import Flags._ import Contexts._ import Names._ -import NameExtractors.WildcardParamName +import NameKinds.WildcardParamName import ast.{Positioned, Trees, untpd} import ast.Trees._ import Decorators._ @@ -21,7 +21,6 @@ import util.Positions._ import Constants._ import ScriptParsers._ import Comments._ - import scala.annotation.{tailrec, switch} import util.DotClass import rewrite.Rewrites.patch diff --git a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala index fa79d995c4eb..a8d82045e647 100644 --- a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala +++ b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala @@ -14,7 +14,7 @@ import DenotTransformers._ import Annotations._ import StdNames._ import NameOps._ -import NameExtractors._ +import NameKinds._ import ast.Trees._ /** This phase augments Scala2 traits with implementation classes and with additional members diff --git a/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala b/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala index 368250cdfc5e..b9a9544f513f 100644 --- a/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala +++ b/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala @@ -12,7 +12,7 @@ import core.SymDenotations._ import core.StdNames.nme import core.Names._ import core.NameOps._ -import core.NameExtractors.TempResultName +import core.NameKinds.TempResultName import ast.Trees._ import SymUtils._ import collection.{ mutable, immutable } diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index e9fe42e78909..4cee0d0de721 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -11,7 +11,7 @@ import core.Types._ import core.Names._ import core.StdNames._ import core.NameOps._ -import core.NameExtractors.ShadowedName +import core.NameKinds.ShadowedName import core.Decorators._ import core.Constants._ import core.Definitions._ diff --git a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala index 803504944207..37f978f112fe 100644 --- a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -20,7 +20,7 @@ import scala.collection.mutable import DenotTransformers._ import typer.Checking import NameOps._ -import NameExtractors.AvoidClashName +import NameKinds.AvoidClashName import StdNames._ diff --git a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala index 357baa3df0e3..f64006d73c51 100644 --- a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala @@ -10,7 +10,7 @@ import Contexts._ import Symbols._ import Decorators._ import NameOps._ -import NameExtractors._ +import NameKinds._ import StdNames.nme import rewrite.Rewrites.patch import util.Positions.Position diff --git a/compiler/src/dotty/tools/dotc/transform/LiftTry.scala b/compiler/src/dotty/tools/dotc/transform/LiftTry.scala index 61554f5ce55f..278868131c20 100644 --- a/compiler/src/dotty/tools/dotc/transform/LiftTry.scala +++ b/compiler/src/dotty/tools/dotc/transform/LiftTry.scala @@ -8,7 +8,7 @@ import core.Contexts._ import core.Types._ import core.Flags._ import core.Decorators._ -import core.NameExtractors.LiftedTreeName +import core.NameKinds.LiftedTreeName import NonLocalReturns._ /** Lifts try's that might be executed on non-empty expression stacks diff --git a/compiler/src/dotty/tools/dotc/transform/Mixin.scala b/compiler/src/dotty/tools/dotc/transform/Mixin.scala index fc23d96ee06a..546077d279a2 100644 --- a/compiler/src/dotty/tools/dotc/transform/Mixin.scala +++ b/compiler/src/dotty/tools/dotc/transform/Mixin.scala @@ -13,7 +13,7 @@ import Decorators._ import DenotTransformers._ import StdNames._ import NameOps._ -import NameExtractors._ +import NameKinds._ import Phases._ import ast.untpd import ast.Trees._ diff --git a/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala b/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala index 945504743c3f..fdee076b452f 100644 --- a/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala +++ b/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala @@ -5,7 +5,7 @@ import core._ import Contexts._, Symbols._, Types._, Flags._, Decorators._, StdNames._, Constants._, Phases._ import TreeTransforms._ import ast.Trees._ -import NameExtractors.NonLocalReturnKeyName +import NameKinds.NonLocalReturnKeyName import collection.mutable object NonLocalReturns { diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index f93eac0a268a..d87412d93b71 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -11,7 +11,7 @@ import core.Symbols._ import core.Types._ import core.Constants._ import core.StdNames._ -import core.NameExtractors._ +import core.NameKinds._ import dotty.tools.dotc.ast.{untpd, TreeTypeMap, tpd} import dotty.tools.dotc.core import dotty.tools.dotc.core.DenotTransformers.DenotTransformer @@ -73,11 +73,11 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { trait CodegenCore { // assert(owner ne null); assert(owner ne NoSymbol) - def freshSym(pos: Position, tp: Type = NoType, unique: UniqueNameExtractor = PatMatStdBinderName, owner: Symbol = ctx.owner) = { + def freshSym(pos: Position, tp: Type = NoType, unique: UniqueNameKind = PatMatStdBinderName, owner: Symbol = ctx.owner) = { ctx.newSymbol(owner, unique.fresh(), Flags.Synthetic | Flags.Case, tp, coord = pos) } - def newSynthCaseLabel(unique: UniqueNameExtractor, tpe: Type, owner: Symbol = ctx.owner) = + def newSynthCaseLabel(unique: UniqueNameKind, tpe: Type, owner: Symbol = ctx.owner) = ctx.newSymbol(owner, unique.fresh(), Flags.Label | Flags.Synthetic | Flags.Method, tpe).asTerm //NoSymbol.newLabel(freshName(name), NoPosition) setFlag treeInfo.SYNTH_CASE_FLAGS diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala index 1df10cac2917..e7936e8d95b4 100644 --- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -13,7 +13,7 @@ import Decorators._ import DenotTransformers._ import StdNames._ import NameOps._ -import NameExtractors._ +import NameKinds._ import ast.Trees._ import util.Positions._ import Names._ diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index 1b3018d9b083..4c07ca4c8c7b 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -10,7 +10,7 @@ import Decorators._ import Names._ import StdNames._ import NameOps._ -import NameExtractors._ +import NameKinds._ import Flags._ import Annotations._ diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index 87e9c1013755..10c18e165dfb 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -10,7 +10,7 @@ import DenotTransformers.DenotTransformer import Denotations.SingleDenotation import Symbols._ import Types._ -import NameExtractors.TailLabelName +import NameKinds.TailLabelName import TreeTransforms.{MiniPhaseTransform, TransformerInfo} /** diff --git a/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala b/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala index a651c0c74aa5..44d26e7dd3a4 100644 --- a/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala +++ b/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala @@ -5,7 +5,7 @@ import core.Symbols._ import core.StdNames._ import ast.Trees._ import core.Types._ -import core.NameExtractors.ExceptionBinderName +import core.NameKinds.ExceptionBinderName import dotty.tools.dotc.core.Decorators._ import dotty.tools.dotc.core.Flags import dotty.tools.dotc.core.Contexts.Context diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index 3f3a0cce3f06..22acd112b61c 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -12,7 +12,7 @@ import Symbols._ import Decorators._ import Names._ import StdNames._ -import NameExtractors.UniqueName +import NameKinds.UniqueName import Trees._ import Inferencing._ import util.Positions._ diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index ad65af98cd42..eaabb068957e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -15,7 +15,7 @@ import StdNames.nme import Contexts.Context import Names.{Name, TermName} import NameOps._ -import NameExtractors.InlineAccessorName +import NameKinds.InlineAccessorName import SymDenotations.SymDenotation import Annotations._ import transform.ExplicitOuter diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 03357fee31f6..398a7a17e69e 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -5,7 +5,7 @@ package typer import core._ import ast._ import Contexts._, Types._, Flags._, Denotations._, Names._, StdNames._, NameOps._, Symbols._ -import NameExtractors.DepParamName +import NameKinds.DepParamName import Trees._ import Constants._ import Scopes._ diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 8674c8fbd8a5..e6236d122e5a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -18,7 +18,7 @@ import SymDenotations._ import Annotations._ import Names._ import NameOps._ -import NameExtractors._ +import NameKinds._ import Flags._ import Decorators._ import ErrorReporting._ diff --git a/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala b/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala index 529e30f05a02..5dbec3e5a586 100644 --- a/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala +++ b/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala @@ -4,11 +4,11 @@ package util import scala.collection.mutable import core.Names.TermName -import core.NameExtractors.UniqueNameExtractor +import core.NameKinds.UniqueNameKind import core.StdNames.str abstract class FreshNameCreator { - def newName(prefix: TermName, unique: UniqueNameExtractor): TermName + def newName(prefix: TermName, unique: UniqueNameKind): TermName } object FreshNameCreator { @@ -21,7 +21,7 @@ object FreshNameCreator { * that the returned name has never been returned by a previous * call to this function (provided the prefix does not end in a digit). */ - def newName(prefix: TermName, unique: UniqueNameExtractor): TermName = { + def newName(prefix: TermName, unique: UniqueNameKind): TermName = { val key = str.sanitize(prefix.toString + unique.separator) counters(key) += 1 val counter = counters(key) From d5c1e6dc677ef9ef49f02075747b2301ba45fd74 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 28 Mar 2017 23:30:36 +0200 Subject: [PATCH 36/68] Fix rebase breakage --- compiler/src/dotty/tools/dotc/ast/Desugar.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 288fadfd0863..e9df661866fa 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -636,6 +636,7 @@ object desugar { case (named, tpt) :: Nil => derivedValDef(original, named, tpt, matchExpr, mods) case _ => + val tmpName = UniqueName.fresh() val patMods = mods & Lazy | Synthetic | (if (ctx.owner.isClass) PrivateLocal else EmptyFlags) val firstDef = From a5d94d23341b2f30f677f1420f1ce088a0f1ed5b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 29 Mar 2017 16:58:41 +0200 Subject: [PATCH 37/68] Decentralize unmangling, add new nameKinds Start scheme where unmangling is done by NameKinds instead of in NameOps. Also add namekinds for protected accessors. --- .../src/dotty/tools/dotc/ast/Desugar.scala | 4 +- .../{NameExtractors.scala => NameKinds.scala} | 26 +++++++++ .../src/dotty/tools/dotc/core/NameOps.scala | 58 +++++-------------- .../src/dotty/tools/dotc/core/StdNames.scala | 2 - .../dotc/core/classfile/ClassfileParser.scala | 4 +- .../tools/dotc/core/tasty/TastyFormat.scala | 6 +- .../core/unpickleScala2/Scala2Unpickler.scala | 3 +- .../src/dotty/tools/dotc/sbt/ExtractAPI.scala | 4 +- .../tools/dotc/transform/SuperAccessors.scala | 10 ++-- .../dotty/tools/dotc/typer/Applications.scala | 3 +- 10 files changed, 62 insertions(+), 58 deletions(-) rename compiler/src/dotty/tools/dotc/core/{NameExtractors.scala => NameKinds.scala} (87%) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index e9df661866fa..9cf530f8fe3c 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -6,7 +6,7 @@ import core._ import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ import Decorators._ -import NameKinds.{UniqueName, EvidenceParamName} +import NameKinds.{UniqueName, EvidenceParamName, DefaultGetterName} import language.higherKinds import typer.FrontEnd import collection.mutable.ListBuffer @@ -187,7 +187,7 @@ object desugar { case (vparam :: vparams) :: vparamss1 => def defaultGetter: DefDef = DefDef( - name = meth.name.defaultGetterName(n), + name = DefaultGetterName(meth.name, n), tparams = meth.tparams.map(tparam => dropContextBound(toDefParam(tparam))), vparamss = takeUpTo(normalizedVparamss.nestedMap(toDefParam), n), tpt = TypeTree(), diff --git a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala similarity index 87% rename from compiler/src/dotty/tools/dotc/core/NameExtractors.scala rename to compiler/src/dotty/tools/dotc/core/NameKinds.scala index 7350087a5b5f..2c5e3ee3ec6b 100644 --- a/compiler/src/dotty/tools/dotc/core/NameExtractors.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -31,6 +31,7 @@ object NameKinds { override def toString = infoString } def definesNewName = false + def unmangle(name: SimpleTermName): TermName = name def mkString(underlying: TermName, info: ThisInfo): String def infoString: String } @@ -58,11 +59,17 @@ object NameKinds { extends ClassifiedNameKind(tag, if (optInfoString.isEmpty) s"Prefix $prefix" else optInfoString) { def mkString(underlying: TermName, info: ThisInfo) = underlying.mapLast(n => termName(prefix + n.toString)).toString + override def unmangle(name: SimpleTermName): TermName = + if (name.startsWith(prefix)) apply(name.drop(prefix.length).asSimpleName) + else name } class SuffixNameKind(tag: Int, suffix: String, optInfoString: String = "") extends ClassifiedNameKind(tag, if (optInfoString.isEmpty) s"Suffix $suffix" else optInfoString) { def mkString(underlying: TermName, info: ThisInfo) = underlying.toString ++ suffix + override def unmangle(name: SimpleTermName): TermName = + if (name.endsWith(suffix)) apply(name.take(name.length - suffix.length).asSimpleName) + else name } trait QualifiedInfo extends NameInfo { @@ -181,6 +188,20 @@ object NameKinds { val prefix = if (underlying.isConstructorName) nme.DEFAULT_GETTER_INIT else underlying prefix.toString + nme.DEFAULT_GETTER + (info.num + 1) } + + private val dgLen = nme.DEFAULT_GETTER.length + + override def unmangle(name: SimpleTermName): TermName = { + var i = name.length + while (i > 0 && name(i - 1).isDigit) i -= 1 + if (i > dgLen && i < name.length && name.slice(i - dgLen, i) == nme.DEFAULT_GETTER) { + val index = name.drop(i).toString.toInt - 1 + var original = name.take(i - dgLen).asTermName + if (original == nme.DEFAULT_GETTER_INIT) original = Names.CONSTRUCTOR + apply(original, index) + } + else name + } } object VariantName extends NumberedNameKind(VARIANT, "Variant") { @@ -194,6 +215,8 @@ object NameKinds { val SuperAccessorName = new PrefixNameKind(SUPERACCESSOR, "super$") val InitializerName = new PrefixNameKind(INITIALIZER, "initial$") val ShadowedName = new PrefixNameKind(SHADOWED, "(shadowed)") + val ProtectedAccessorName = new PrefixNameKind(PROTECTEDACCESSOR, "protected$") + val ProtectedSetterName = new PrefixNameKind(PROTECTEDSETTER, "protected$set") // dubious encoding, kept for Scala2 compatibility val AvoidClashName = new SuffixNameKind(AVOIDCLASH, "$_avoid_name_clash_$") val ModuleClassName = new SuffixNameKind(OBJECTCLASS, "$", optInfoString = "ModuleClass") @@ -216,6 +239,9 @@ object NameKinds { def infoString: String = "Signed" } + val Scala2MethodNameKinds: List[NameKind] = + List(DefaultGetterName, ProtectedAccessorName, ProtectedSetterName) + def simpleNameKindOfTag : collection.Map[Int, ClassifiedNameKind] = simpleNameKinds def qualifiedNameKindOfSeparator: collection.Map[String, QualifiedNameKind] = qualifiedNameKinds def uniqueNameKindOfSeparator : collection.Map[String, UniqueNameKind] = uniqueNameKinds diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 356b41efb902..f936e5a34ecc 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -60,13 +60,11 @@ object NameOps { def isImplClassName = name endsWith IMPL_CLASS_SUFFIX 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.toSimpleName containsSlice INTERPRETER_IMPORT_WRAPPER def isSetterName = name endsWith SETTER_SUFFIX def isSingletonName = name endsWith SINGLETON_SUFFIX def isImportName = name startsWith IMPORT def isFieldName = name endsWith LOCAL_SUFFIX - def isDefaultGetterName = name.isTermName && name.asTermName.defaultGetterIndex >= 0 def isScala2LocalSuffix = name.endsWith(" ") def isModuleVarName(name: Name): Boolean = name.stripAnonNumberSuffix endsWith MODULE_VAR_SUFFIX @@ -400,54 +398,21 @@ object NameOps { name.mapLast(n => n.take(n.length - LOCAL_SUFFIX.length).asSimpleName) } - /** Nominally, name$default$N, encoded for - * @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 = - DefaultGetterName(name, pos) - /** Nominally, name from name$default$N, CONSTRUCTOR for */ def defaultGetterToMethod: TermName = name rewrite { case DefaultGetterName(methName, _) => methName } - def defaultGetterToMethodOfMangled: 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 = name collect { case DefaultGetterName(_, num) => num } getOrElse -1 - def defaultGetterIndexOfMangled: 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)) - name.drop(i).toString.toInt - 1 - else - -1 - } - def stripScala2LocalSuffix: TermName = if (name.isScala2LocalSuffix) name.init.asTermName else name - /** The name of an accessor for protected symbols. */ - def protectedAccessorName: TermName = - PROTECTED_PREFIX ++ name.unexpandedName - - /** The name of a setter for protected symbols. Used for inherited Java fields. */ - def protectedSetterName: TermName = - PROTECTED_SET_PREFIX ++ name.unexpandedName - def moduleVarName: TermName = name ++ MODULE_VAR_SUFFIX @@ -509,18 +474,25 @@ object NameOps { case name => name } - def unmangleMethodName: TermName = - if (name.isSimple) { - val idx = name.defaultGetterIndexOfMangled - if (idx >= 0) name.defaultGetterToMethodOfMangled.defaultGetterName(idx) - else name - } - else name - def unmangleSuperName: TermName = if (name.isSimple && name.startsWith(str.SUPER_PREFIX)) SuperAccessorName(name.drop(str.SUPER_PREFIX.length).asTermName) else name + + def unmangle(kind: NameKind): TermName = name rewrite { + case unmangled: SimpleTermName => + kind.unmangle(unmangled) + case ExpandedName(prefix, last) => + kind.unmangle(last) rewrite { + case kernel: SimpleTermName => + ExpandedName(prefix, kernel) + } + } + + def unmangle(kinds: List[NameKind]): TermName = { + val unmangled = (name /: kinds)(_.unmangle(_)) + if (unmangled eq name) name else unmangled.unmangle(kinds) + } } private final val FalseSuper = "$$super".toTermName diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 598d556502f0..7dd569d04bb4 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -123,8 +123,6 @@ object StdNames { val OVERLOADED: N = "" val PACKAGE: N = "package" val PACKAGE_CLS: N = "package$" - val PROTECTED_PREFIX: N = "protected$" - val PROTECTED_SET_PREFIX: N = PROTECTED_PREFIX + "set" val ROOT: N = "" val SINGLETON_SUFFIX: N = ".type" val SPECIALIZED_SUFFIX: N = "$sp" diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 13315eb3e409..b09da70e1ee5 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -5,7 +5,7 @@ package classfile import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._, Decorators._ import SymDenotations._, unpickleScala2.Scala2Unpickler._, Constants._, Annotations._, util.Positions._ -import NameKinds.ModuleClassName +import NameKinds.{ModuleClassName, DefaultGetterName} import ast.tpd._ import java.io.{ File, IOException } import java.lang.Integer.toHexString @@ -598,7 +598,7 @@ class ClassfileParser( def addDefaultGetter(attr: Symbol, n: Int) = ctx.newSymbol( owner = moduleRoot.symbol, - name = nme.CONSTRUCTOR.defaultGetterName(n), + name = DefaultGetterName(nme.CONSTRUCTOR, n), flags = attr.flags & Flags.AccessFlags, info = defn.NothingType).entered diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 18d4a6344b71..f7e61c924529 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -229,8 +229,10 @@ object TastyFormat { final val DEFAULTGETTER = 11 final val VARIANT = 12 final val SUPERACCESSOR = 20 - final val INITIALIZER = 21 - final val SHADOWED = 22 + final val PROTECTEDACCESSOR = 21 + final val PROTECTEDSETTER = 22 + final val INITIALIZER = 23 + final val SHADOWED = 24 final val AVOIDCLASH = 27 final val OBJECTCLASS = 29 diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 976eb5df4ee8..e4b6faa4b2b5 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -9,6 +9,7 @@ import java.lang.Double.longBitsToDouble import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._ import StdNames._, Denotations._, NameOps._, Flags._, Constants._, Annotations._ +import NameKinds.Scala2MethodNameKinds import dotty.tools.dotc.typer.ProtoTypes.{FunProtoTyped, FunProto} import util.Positions._ import dotty.tools.dotc.ast.{tpd, Trees, untpd}, ast.tpd._ @@ -436,7 +437,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas if (flags is Method) { name = if (name == nme.TRAIT_CONSTRUCTOR) nme.CONSTRUCTOR - else name.asTermName.unmangleMethodName + else name.asTermName.unmangle(Scala2MethodNameKinds) } if (flags is Scala2ExpandedName) { name = name.unmangleExpandedName diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index 324aecdf0321..db19bf6b6850 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -5,6 +5,7 @@ import ast.{Trees, tpd} import core._, core.Decorators._ import Annotations._, Contexts._, Flags._, Phases._, Trees._, Types._, Symbols._ import Names._, NameOps._, StdNames._ +import NameKinds.DefaultGetterName import typer.Inliner import typer.ErrorReporting.cyclicErrorMsg import transform.SymUtils._ @@ -300,7 +301,8 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder sym.owner.companionModule // default getters for class constructors are found in the companion object else sym.owner - (0 until pnames.length).map(i => qual.info.member(sym.name.defaultGetterName(start + i)).exists) + (0 until pnames.length).map(i => + qual.info.member(DefaultGetterName(sym.name, start + i)).exists) } else (0 until pnames.length).map(Function.const(false)) val params = (pnames, ptypes, defaults).zipped.map((pname, ptype, isDefault) => diff --git a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index bae1b897e238..583834fb31a2 100644 --- a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -11,6 +11,7 @@ import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTrans import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._ import util.Positions._ import Decorators._ +import NameKinds.{ProtectedAccessorName, ProtectedSetterName} import Symbols._, TypeUtils._ /** This class performs the following functions: @@ -168,7 +169,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { assert(clazz.exists, sym) ctx.debuglog("Decided for host class: " + clazz) - val accName = sym.name.protectedAccessorName + val accName = ProtectedAccessorName(sym.name) // if the result type depends on the this type of an enclosing class, the accessor // has to take an object of exactly this type, otherwise it's more general @@ -206,7 +207,8 @@ class SuperAccessors(thisTransformer: DenotTransformer) { } def isProtectedAccessor(tree: Tree)(implicit ctx: Context): Boolean = tree match { - case Apply(TypeApply(Select(_, name), _), qual :: Nil) => name.isProtectedAccessorName + case Apply(TypeApply(Select(_, name), _), qual :: Nil) => + name.is(ProtectedAccessorName) || name.is(ProtectedSetterName) case _ => false } @@ -221,7 +223,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { assert(clazz.exists, sym) ctx.debuglog("Decided for host class: " + clazz) - val accName = sym.name.protectedAccessorName + val accName = ProtectedAccessorName(sym.name) // if the result type depends on the this type of an enclosing class, the accessor // has to take an object of exactly this type, otherwise it's more general @@ -265,7 +267,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { assert(clazz.exists, field) ctx.debuglog("Decided for host class: " + clazz) - val accName = field.name.protectedSetterName + val accName = ProtectedSetterName(field.name) val accType = MethodType(clazz.classInfo.selfType :: field.info :: Nil, defn.UnitType) val protectedAccessor = clazz.info.decl(accName).symbol orElse { val newAcc = ctx.newSymbol( diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 1fcebf4f02ff..db1e0bcfbe0c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -20,6 +20,7 @@ import Trees._ import config.Config import Names._ import StdNames._ +import NameKinds.DefaultGetterName import ProtoTypes._ import EtaExpansion._ import Inferencing._ @@ -345,7 +346,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => } val getterPrefix = if ((meth is Synthetic) && meth.name == nme.apply) nme.CONSTRUCTOR else meth.name - def getterName = getterPrefix.defaultGetterName(n) + def getterName = DefaultGetterName(getterPrefix, n) if (!meth.hasDefaultParams) EmptyTree else if (receiver.isEmpty) { From b595a98a5b51f3b328f1d69e6afc56f19129666d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 29 Mar 2017 18:56:29 +0200 Subject: [PATCH 38/68] New unmangling for ExpandedName --- .../src/dotty/tools/dotc/core/NameKinds.scala | 20 ++++++- .../src/dotty/tools/dotc/core/NameOps.scala | 57 ++++++------------- .../core/unpickleScala2/Scala2Unpickler.scala | 8 +-- 3 files changed, 40 insertions(+), 45 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index 2c5e3ee3ec6b..eea5aefe31b0 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -151,9 +151,27 @@ object NameKinds { val QualifiedName = new QualifiedNameKind(QUALIFIED, ".") val FlattenedName = new QualifiedNameKind(FLATTENED, "$") - val ExpandedName = new QualifiedNameKind(EXPANDED, str.EXPAND_SEPARATOR) val TraitSetterName = new QualifiedNameKind(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR) + val ExpandedName = new QualifiedNameKind(EXPANDED, str.EXPAND_SEPARATOR) { + private val FalseSuper = "$$super".toTermName + private val FalseSuperLength = FalseSuper.length + + override def unmangle(name: SimpleTermName): TermName = { + var i = name.lastIndexOfSlice(str.EXPAND_SEPARATOR) + if (i < 0) name + else { + // Hack to make super accessors from traits work. They would otherwise fail because of #765 + // The problem is that in `x$$super$$plus` the expansion prefix needs to be `x` + // instead of `x$$super`. + if (i > FalseSuperLength && name.slice(i - FalseSuperLength, i) == FalseSuper) + i -= FalseSuper.length + + apply(name.take(i).asTermName, name.drop(i + str.EXPAND_SEPARATOR.length).asSimpleName) + } + } + } + val UniqueName = new UniqueNameKind("$") { override def mkString(underlying: TermName, info: ThisInfo) = if (underlying.isEmpty) "$" + info.num + "$" else super.mkString(underlying, info) diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index f936e5a34ecc..8d5344d8af6e 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -151,17 +151,6 @@ object NameOps { name.rewrite { case ExpandedName(_, unexp) => unexp } } - def unexpandedNameOfMangled: N = likeTyped { - 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 - - if (idx < 0) name else (name drop (idx + nme.EXPAND_SEPARATOR.length)) - } - def expandedPrefix: N = likeTyped { name.exclude(ExpandedName) } def expandedPrefixOfMangled: N = { @@ -170,15 +159,6 @@ object NameOps { likeTyped(name.take(idx)) } - def unmangleExpandedName: N = - if (name.isSimple) { - val unmangled = unexpandedNameOfMangled - if (name eq unmangled) name - else likeTyped( - ExpandedName(expandedPrefixOfMangled.toTermName, unmangled.asSimpleName)) - } - else name - def implClassName: N = likeTyped(name ++ tpnme.IMPL_CLASS_SUFFIX) def errorName: N = likeTyped(name ++ nme.ERROR) @@ -354,6 +334,23 @@ object NameOps { /** If name length exceeds allowable limit, replace part of it by hash */ def compactified(implicit ctx: Context): TermName = termName(compactify(name.toString)) + + def unmangle(kind: NameKind): N = likeTyped { + name rewrite { + case unmangled: SimpleTermName => + kind.unmangle(unmangled) + case ExpandedName(prefix, last) => + kind.unmangle(last) rewrite { + case kernel: SimpleTermName => + ExpandedName(prefix, kernel) + } + } + } + + def unmangle(kinds: List[NameKind]): N = { + val unmangled = (name /: kinds)(_.unmangle(_)) + if (unmangled eq name) name else unmangled.unmangle(kinds) + } } // needed??? @@ -473,26 +470,6 @@ object NameOps { case NO_NAME => primitivePostfixMethodName case name => name } - - def unmangleSuperName: TermName = - if (name.isSimple && name.startsWith(str.SUPER_PREFIX)) - SuperAccessorName(name.drop(str.SUPER_PREFIX.length).asTermName) - else name - - def unmangle(kind: NameKind): TermName = name rewrite { - case unmangled: SimpleTermName => - kind.unmangle(unmangled) - case ExpandedName(prefix, last) => - kind.unmangle(last) rewrite { - case kernel: SimpleTermName => - ExpandedName(prefix, kernel) - } - } - - def unmangle(kinds: List[NameKind]): TermName = { - val unmangled = (name /: kinds)(_.unmangle(_)) - if (unmangled eq name) name else unmangled.unmangle(kinds) - } } private final val FalseSuper = "$$super".toTermName diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index e4b6faa4b2b5..608c77a8e0af 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -9,7 +9,7 @@ import java.lang.Double.longBitsToDouble import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._ import StdNames._, Denotations._, NameOps._, Flags._, Constants._, Annotations._ -import NameKinds.Scala2MethodNameKinds +import NameKinds.{Scala2MethodNameKinds, SuperAccessorName, ExpandedName} import dotty.tools.dotc.typer.ProtoTypes.{FunProtoTyped, FunProto} import util.Positions._ import dotty.tools.dotc.ast.{tpd, Trees, untpd}, ast.tpd._ @@ -439,12 +439,12 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas if (name == nme.TRAIT_CONSTRUCTOR) nme.CONSTRUCTOR else name.asTermName.unmangle(Scala2MethodNameKinds) } - if (flags is Scala2ExpandedName) { - name = name.unmangleExpandedName + if ((flags is Scala2ExpandedName) && name.isSimple) { + name = name.unmangle(ExpandedName) flags = flags &~ Scala2ExpandedName } if (flags is Scala2SuperAccessor) { - name = name.asTermName.unmangleSuperName + name = name.asTermName.unmangle(SuperAccessorName) flags = flags &~ Scala2SuperAccessor } From ae694957bfb9f5121eee3434243ecaabb6b24d1d Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 29 Mar 2017 22:00:49 +0200 Subject: [PATCH 39/68] Fix inner class name table emission with semantic names The backend contains: val outerName = innerClassSym.rawowner.javaBinaryName // Java compatibility. See the big comment in BTypes that summarizes the InnerClass spec. val outerNameModule = if (innerClassSym.rawowner.isTopLevelModuleClass) outerName.dropModule Where `dropModule` is defined in the backend interface as: def dropModule: Name = n.stripModuleClassSuffix This will only work as expected if `javaBinaryName` returns a name with proper semantic information, but before this commit we just used the output of `fullNameSeparated` which contains no semantic information. --- .../src/dotty/tools/backend/jvm/DottyBackendInterface.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 45bbca01755c..10288a4be7c0 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -557,7 +557,8 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def fullName: String = sym.showFullName def simpleName: Name = sym.name def javaSimpleName: Name = toDenot(sym).name // addModuleSuffix(simpleName.dropLocal) - def javaBinaryName: Name = toDenot(sym).fullNameSeparated("/") // addModuleSuffix(fullNameInternal('/')) + def javaBinaryName: Name = toDenot(sym).fullNameSeparated("/").unmangleClassName // addModuleSuffix(fullNameInternal('/')) + // We use `unmangleClassName` so that `stripModuleClassSuffix` works as expected. def javaClassName: String = toDenot(sym).fullName.toString// addModuleSuffix(fullNameInternal('.')).toString def name: Name = sym.name def rawname: Name = { From 21ded6ee9f727bd5a1c3975809c06868fe1b5536 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 30 Mar 2017 13:44:02 +0200 Subject: [PATCH 40/68] Revise qualified names 1. Fix problem in fullNameSeparated 2. Revise expandedName operations --- .../backend/jvm/DottyBackendInterface.scala | 3 +- .../src/dotty/tools/dotc/core/NameKinds.scala | 28 +++++++--- .../src/dotty/tools/dotc/core/NameOps.scala | 50 ++++++----------- .../src/dotty/tools/dotc/core/StdNames.scala | 1 - .../tools/dotc/core/SymDenotations.scala | 53 ++++++++----------- .../tools/dotc/core/tasty/TastyFormat.scala | 3 +- .../dotc/core/tasty/TastyUnpickler.scala | 8 +-- .../dotc/transform/AugmentScala2Traits.scala | 4 +- 8 files changed, 63 insertions(+), 87 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 10288a4be7c0..7ef6b7ef9fe6 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -557,8 +557,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def fullName: String = sym.showFullName def simpleName: Name = sym.name def javaSimpleName: Name = toDenot(sym).name // addModuleSuffix(simpleName.dropLocal) - def javaBinaryName: Name = toDenot(sym).fullNameSeparated("/").unmangleClassName // addModuleSuffix(fullNameInternal('/')) - // We use `unmangleClassName` so that `stripModuleClassSuffix` works as expected. + def javaBinaryName: Name = javaClassName.replace('.', '/').toTermName // TODO: can we make this a string? addModuleSuffix(fullNameInternal('/')) def javaClassName: String = toDenot(sym).fullName.toString// addModuleSuffix(fullNameInternal('.')).toString def name: Name = sym.name def rawname: Name = { diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index eea5aefe31b0..381bb3fc0ede 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -14,8 +14,8 @@ import collection.mutable object NameKinds { @sharable private val simpleNameKinds = new mutable.HashMap[Int, ClassifiedNameKind] + @sharable private val qualifiedNameKinds = new mutable.HashMap[Int, QualifiedNameKind] @sharable private val uniqueNameKinds = new mutable.HashMap[String, UniqueNameKind] - @sharable private val qualifiedNameKinds = new mutable.HashMap[String, QualifiedNameKind] abstract class NameInfo extends DotClass { def kind: NameKind @@ -83,8 +83,18 @@ object NameKinds { override def map(f: SimpleTermName => SimpleTermName): NameInfo = new QualInfo(f(name)) override def toString = s"$infoString $name" } - def apply(qual: TermName, name: SimpleTermName) = + def apply(qual: TermName, name: SimpleTermName): TermName = qual.derived(new QualInfo(name)) + + /** Overloaded version used only for ExpandedName and TraitSetterName. + * Needed because the suffix of an expanded name may itself be expanded. + * For example, look at javap of scala.App.initCode + */ + def apply(qual: TermName, name: TermName): TermName = name rewrite { + case name: SimpleTermName => apply(qual, name) + case AnyQualifiedName(_, _) => apply(qual, name.toSimpleName) + } + def unapply(name: DerivedTermName): Option[(TermName, SimpleTermName)] = name match { case DerivedTermName(qual, info: this.QualInfo) => Some((qual, info.name)) case _ => None @@ -96,7 +106,7 @@ object NameKinds { s"$underlying$separator${info.name}" def infoString = s"Qualified $separator" - qualifiedNameKinds(separator) = this + qualifiedNameKinds(tag) = this } object AnyQualifiedName { @@ -150,8 +160,8 @@ object NameKinds { } val QualifiedName = new QualifiedNameKind(QUALIFIED, ".") - val FlattenedName = new QualifiedNameKind(FLATTENED, "$") - val TraitSetterName = new QualifiedNameKind(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR) + val FlatName = new QualifiedNameKind(FLATTENED, "$") + val ExpandPrefixName = new QualifiedNameKind(EXPANDPREFIX, "$") val ExpandedName = new QualifiedNameKind(EXPANDED, str.EXPAND_SEPARATOR) { private val FalseSuper = "$$super".toTermName @@ -172,6 +182,8 @@ object NameKinds { } } + val TraitSetterName = new QualifiedNameKind(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR) + val UniqueName = new UniqueNameKind("$") { override def mkString(underlying: TermName, info: ThisInfo) = if (underlying.isEmpty) "$" + info.num + "$" else super.mkString(underlying, info) @@ -260,7 +272,7 @@ object NameKinds { val Scala2MethodNameKinds: List[NameKind] = List(DefaultGetterName, ProtectedAccessorName, ProtectedSetterName) - def simpleNameKindOfTag : collection.Map[Int, ClassifiedNameKind] = simpleNameKinds - def qualifiedNameKindOfSeparator: collection.Map[String, QualifiedNameKind] = qualifiedNameKinds - def uniqueNameKindOfSeparator : collection.Map[String, UniqueNameKind] = uniqueNameKinds + def simpleNameKindOfTag : collection.Map[Int, ClassifiedNameKind] = simpleNameKinds + def qualifiedNameKindOfTag : collection.Map[Int, QualifiedNameKind] = qualifiedNameKinds + def uniqueNameKindOfSeparator: collection.Map[String, UniqueNameKind] = uniqueNameKinds } \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 8d5344d8af6e..01ce4807c82b 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -59,10 +59,8 @@ object NameOps { def isStaticConstructorName = name == STATIC_CONSTRUCTOR def isImplClassName = name endsWith IMPL_CLASS_SUFFIX def isLocalDummyName = name startsWith LOCALDUMMY_PREFIX - def isLoopHeaderLabel = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX) def isReplWrapperName = name.toSimpleName containsSlice INTERPRETER_IMPORT_WRAPPER def isSetterName = name endsWith SETTER_SUFFIX - def isSingletonName = name endsWith SINGLETON_SUFFIX def isImportName = name startsWith IMPORT def isFieldName = name endsWith LOCAL_SUFFIX def isScala2LocalSuffix = name.endsWith(" ") @@ -110,8 +108,16 @@ object NameOps { /** Convert this module class name to corresponding source module name */ def sourceModuleName: TermName = name.toTermName.exclude(ModuleClassName) - /** If name ends in module class suffix, drop it */ - def stripModuleClassSuffix: Name = name.exclude(ModuleClassName) + /** If name ends in module class suffix, drop it. This + * method needs to work on mangled as well as unmangled names because + * it is also called from the backend. + */ + def stripModuleClassSuffix: Name = name match { + case name: SimpleTermName if name.endsWith("$") => + name.unmangleClassName.exclude(ModuleClassName) + case _ => + name.exclude(ModuleClassName) + } /** If flags is a ModuleClass but not a Package, add module class suffix */ def adjustIfModuleClass(flags: Flags.FlagSet): N = likeTyped { @@ -122,43 +128,17 @@ object NameOps { /** The superaccessor for method with given name */ def superName: TermName = SuperAccessorName(name.toTermName) - /** The expanded name of `name` relative to given class `base`. - */ - def expandedName(base: Symbol, separator: Name)(implicit ctx: Context): N = - expandedName(if (base.name.is(ExpandedName)) base.name else base.fullNameSeparated("$"), separator) - - def expandedName(base: Symbol)(implicit ctx: Context): N = expandedName(base, nme.EXPAND_SEPARATOR) - - /** The expanded name of `name` relative to `basename` with given `separator` - */ - def expandedName(prefix: Name, separator: Name = nme.EXPAND_SEPARATOR): N = - likeTyped { - def qualify(name: SimpleTermName) = - qualifiedNameKindOfSeparator(separator.toString)(prefix.toTermName, name) - name rewrite { - case name: SimpleTermName => - qualify(name) - case AnyQualifiedName(_, _) => - // Note: an expanded name may itself be expanded. For example, look at javap of scala.App.initCode - qualify(name.toSimpleName) - } - } - - def expandedName(prefix: Name): N = expandedName(prefix, nme.EXPAND_SEPARATOR) + def expandedName(base: Symbol, kind: QualifiedNameKind = ExpandedName)(implicit ctx: Context): N = { + val prefix = + if (base.name.is(ExpandedName)) base.name else base.fullNameSeparated(ExpandPrefixName) + likeTyped { kind(prefix.toTermName, name.toTermName) } + } /** Revert the expanded name. */ def unexpandedName: N = likeTyped { name.rewrite { case ExpandedName(_, unexp) => unexp } } - def expandedPrefix: N = likeTyped { name.exclude(ExpandedName) } - - def expandedPrefixOfMangled: N = { - val idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) - assert(idx >= 0) - likeTyped(name.take(idx)) - } - def implClassName: N = likeTyped(name ++ tpnme.IMPL_CLASS_SUFFIX) def errorName: N = likeTyped(name ++ nme.ERROR) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 7dd569d04bb4..51821c51b184 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -124,7 +124,6 @@ object StdNames { val PACKAGE: N = "package" val PACKAGE_CLS: N = "package$" val ROOT: N = "" - val SINGLETON_SUFFIX: N = ".type" val SPECIALIZED_SUFFIX: N = "$sp" val SUPER_PREFIX: N = "super$" val WHILE_PREFIX: N = "while$" diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 3d0b306c0d32..f4682bf7d883 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -383,20 +383,18 @@ object SymDenotations { /** The encoded full path name of this denotation, where outer names and inner names * are separated by `separator` strings. * Never translates expansions of operators back to operator symbol. - * Drops package objects. Represents terms in the owner chain by a simple `~`. + * Drops package objects. Represents each term in the owner chain by a simple `~`. * (Note: scalac uses nothing to represent terms, which can cause name clashes * between same-named definitions in different enclosing methods. Before this commit * we used `$' but this can cause ambiguities with the class separator '$'). * 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)(implicit ctx: Context): Name = { - val stopAtPackage = separator.isEmpty - val sep = if (stopAtPackage) "$" else separator + def fullNameSeparated(kind: QualifiedNameKind)(implicit ctx: Context): Name = if (symbol == NoSymbol || owner == NoSymbol || owner.isEffectiveRoot || - stopAtPackage && owner.is(PackageClass)) name + kind == FlatName && owner.is(PackageClass)) name else { var filler = "" var encl = owner @@ -404,34 +402,25 @@ object SymDenotations { encl = encl.owner filler += "~" } - var prefix = encl.fullNameSeparated(separator) - val fn = - if (qualifiedNameKindOfSeparator.contains(sep)) { - if (sep == "$") - // duplicate scalac's behavior: don't write a double '$$' for module class members. - prefix = prefix.exclude(ModuleClassName) - name rewrite { - case n: SimpleTermName => - val n1 = if (filler.isEmpty) n else termName(filler ++ n) - qualifiedNameKindOfSeparator(sep)(prefix.toTermName, n1) - } - } - else { - val sep1 = - if (owner.is(ModuleClass, butNot = Package) && sep == "$") "" - else sep - // duplicate scalac's behavior: don't write a double '$$' for module class members. - prefix ++ sep1 ++ name - } + var prefix = encl.fullNameSeparated(kind) + if (kind.separator == "$") + // duplicate scalac's behavior: don't write a double '$$' for module class members. + prefix = prefix.exclude(ModuleClassName) + def qualify(n: SimpleTermName) = + kind(prefix.toTermName, if (filler.isEmpty) n else termName(filler ++ n)) + val fn = name rewrite { + case name: SimpleTermName => qualify(name) + case name @ AnyQualifiedName(_, _) => qualify(name.toSimpleName) + } if (isType) fn.toTypeName else fn.toTermName } - } + /** The encoded flat name of this denotation, where joined names are separated by `separator` characters. */ - def flatName(implicit ctx: Context): Name = fullNameSeparated("") + def flatName(implicit ctx: Context): Name = fullNameSeparated(FlatName) /** `fullName` where `.' is the separator character */ - def fullName(implicit ctx: Context): Name = fullNameSeparated(".") + def fullName(implicit ctx: Context): Name = fullNameSeparated(QualifiedName) // ----- Tests ------------------------------------------------- @@ -1763,13 +1752,13 @@ object SymDenotations { } } - private[this] var fullNameCache: SimpleMap[String, Name] = SimpleMap.Empty - override final def fullNameSeparated(separator: String)(implicit ctx: Context): Name = { - val cached = fullNameCache(separator) + private[this] var fullNameCache: SimpleMap[QualifiedNameKind, Name] = SimpleMap.Empty + override final def fullNameSeparated(kind: QualifiedNameKind)(implicit ctx: Context): Name = { + val cached = fullNameCache(kind) if (cached != null) cached else { - val fn = super.fullNameSeparated(separator) - fullNameCache = fullNameCache.updated(separator, fn) + val fn = super.fullNameSeparated(kind) + fullNameCache = fullNameCache.updated(kind, fn) fn } } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index f7e61c924529..ec59e711ac7a 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -223,8 +223,9 @@ object TastyFormat { final val UTF8 = 1 final val QUALIFIED = 2 final val FLATTENED = 3 + final val EXPANDPREFIX = 5 final val EXPANDED = 4 - final val TRAITSETTER = 5 + final val TRAITSETTER = 6 final val UNIQUE = 10 final val DEFAULTGETTER = 11 final val VARIANT = 12 diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala index a14691ed5561..835222727e0b 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala @@ -49,12 +49,8 @@ class TastyUnpickler(reader: TastyReader) { case UTF8 => goto(end) termName(bytes, start.index, length) - case QUALIFIED => - QualifiedName(readName(), readName().asSimpleName) - case FLATTENED => - FlattenedName(readName(), readName().asSimpleName) - case EXPANDED => - ExpandedName(readName(), readName().asSimpleName) + case QUALIFIED | FLATTENED | EXPANDED | EXPANDPREFIX => + qualifiedNameKindOfTag(tag)(readName(), readName().asSimpleName) case UNIQUE => val separator = readName().toString val num = readNat() diff --git a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala index a8d82045e647..f2ffaff5da61 100644 --- a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala +++ b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala @@ -14,7 +14,7 @@ import DenotTransformers._ import Annotations._ import StdNames._ import NameOps._ -import NameKinds._ +import NameKinds.{ExpandedName, TraitSetterName} import ast.Trees._ /** This phase augments Scala2 traits with implementation classes and with additional members @@ -74,7 +74,7 @@ class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransform def traitSetter(getter: TermSymbol) = getter.copy( name = getter.ensureNotPrivate.name - .expandedName(getter.owner, nme.TRAIT_SETTER_SEPARATOR) + .expandedName(getter.owner, TraitSetterName) .asTermName.setterName, flags = Method | Accessor, info = MethodType(getter.info.resultType :: Nil, defn.UnitType)) From ab2d095943dc63414da8352ebf1e82bdb642450d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 30 Mar 2017 14:06:43 +0200 Subject: [PATCH 41/68] Make "direct names" semantic --- compiler/src/dotty/tools/dotc/core/NameKinds.scala | 1 + compiler/src/dotty/tools/dotc/core/StdNames.scala | 2 -- compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala | 2 ++ .../src/dotty/tools/dotc/transform/ShortcutImplicits.scala | 7 ++++--- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index 381bb3fc0ede..f5a758256e3a 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -248,6 +248,7 @@ object NameKinds { val ProtectedAccessorName = new PrefixNameKind(PROTECTEDACCESSOR, "protected$") val ProtectedSetterName = new PrefixNameKind(PROTECTEDSETTER, "protected$set") // dubious encoding, kept for Scala2 compatibility val AvoidClashName = new SuffixNameKind(AVOIDCLASH, "$_avoid_name_clash_$") + val DirectName = new SuffixNameKind(DIRECT, "$direct") val ModuleClassName = new SuffixNameKind(OBJECTCLASS, "$", optInfoString = "ModuleClass") object SignedName extends NameKind(63) { diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 51821c51b184..ece3d42dd68b 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -132,7 +132,6 @@ object StdNames { val COMPANION_MODULE_METHOD: N = "companion$module" val COMPANION_CLASS_METHOD: N = "companion$class" val TRAIT_SETTER_SEPARATOR: N = str.TRAIT_SETTER_SEPARATOR - val DIRECT_SUFFIX: N = "$direct" // value types (and AnyRef) are all used as terms as well // as (at least) arguments to the @specialize annotation. @@ -166,7 +165,6 @@ object StdNames { // fictions we use as both types and terms final val ERROR: N = "" - final val ERRORenc: N = encode("") final val NO_NAME: N = "" // formerly NOSYMBOL final val WILDCARD: N = "_" diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index ec59e711ac7a..4acadc943239 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -235,9 +235,11 @@ object TastyFormat { final val INITIALIZER = 23 final val SHADOWED = 24 final val AVOIDCLASH = 27 + final val DIRECT = 28 final val OBJECTCLASS = 29 final val SIGNED = 63 + final val firstInternalTag = 64 // AST tags diff --git a/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala b/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala index 1a530b95caab..2fea1984730f 100644 --- a/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala +++ b/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala @@ -11,6 +11,7 @@ import core.Decorators._ import core.StdNames.nme import core.Names._ import core.NameOps._ +import core.NameKinds.DirectName import ast.Trees._ import ast.tpd import collection.mutable @@ -91,7 +92,7 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr /** A new `m$direct` method to accompany the given method `m` */ private def newDirectMethod(sym: Symbol)(implicit ctx: Context): Symbol = { val direct = sym.copy( - name = sym.name.directName, + name = DirectName(sym.name.asTermName).asInstanceOf[sym.ThisName], flags = sym.flags | Synthetic, info = directInfo(sym.info)) if (direct.allOverriddenSymbols.isEmpty) direct.resetFlag(Override) @@ -103,7 +104,7 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr */ private def directMethod(sym: Symbol)(implicit ctx: Context): Symbol = if (sym.owner.isClass) { - val direct = sym.owner.info.member(sym.name.directName) + val direct = sym.owner.info.member(DirectName(sym.name.asTermName)) .suchThat(_.info matches directInfo(sym.info)).symbol if (direct.maybeOwner == sym.owner) direct else newDirectMethod(sym).enteredAfter(thisTransform) @@ -121,7 +122,7 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr case TypeApply(fn, args) => cpy.TypeApply(tree)(directQual(fn), args) case Block(stats, expr) => cpy.Block(tree)(stats, directQual(expr)) case tree: RefTree => - cpy.Ref(tree)(tree.name.directName) + cpy.Ref(tree)(DirectName(tree.name.asTermName)) .withType(directMethod(tree.symbol).termRef) } directQual(tree.qualifier) From 6786cea6969b9a64bc4583f9c8fbd26bc8fbf372 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 30 Mar 2017 15:18:27 +0200 Subject: [PATCH 42/68] Make field names semantic --- .../src/dotty/tools/dotc/core/NameKinds.scala | 1 + .../src/dotty/tools/dotc/core/NameOps.scala | 24 +++++-------------- .../src/dotty/tools/dotc/core/StdNames.scala | 1 - .../tools/dotc/core/tasty/TastyFormat.scala | 8 ++++--- 4 files changed, 12 insertions(+), 22 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index f5a758256e3a..706320938a39 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -249,6 +249,7 @@ object NameKinds { val ProtectedSetterName = new PrefixNameKind(PROTECTEDSETTER, "protected$set") // dubious encoding, kept for Scala2 compatibility val AvoidClashName = new SuffixNameKind(AVOIDCLASH, "$_avoid_name_clash_$") val DirectName = new SuffixNameKind(DIRECT, "$direct") + val FieldName = new SuffixNameKind(FIELD, "$$local") val ModuleClassName = new SuffixNameKind(OBJECTCLASS, "$", optInfoString = "ModuleClass") object SignedName extends NameKind(63) { diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 01ce4807c82b..ac6bfcca35ba 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -62,7 +62,6 @@ object NameOps { def isReplWrapperName = name.toSimpleName containsSlice INTERPRETER_IMPORT_WRAPPER def isSetterName = name endsWith SETTER_SUFFIX def isImportName = name startsWith IMPORT - def isFieldName = name endsWith LOCAL_SUFFIX def isScala2LocalSuffix = name.endsWith(" ") def isModuleVarName(name: Name): Boolean = name.stripAnonNumberSuffix endsWith MODULE_VAR_SUFFIX @@ -347,33 +346,22 @@ object NameOps { implicit class TermNameDecorator(val name: TermName) extends AnyVal { import nme._ - def setterName: TermName = - if (name.isFieldName) name.fieldToGetter.setterName - else name ++ SETTER_SUFFIX + def setterName: TermName = name.exclude(FieldName) ++ SETTER_SUFFIX def getterName: TermName = - if (name.isFieldName) fieldToGetter - else setterToGetter + name.exclude(FieldName).mapLast(n => + if (n.endsWith(SETTER_SUFFIX)) n.take(n.length - SETTER_SUFFIX.length).asSimpleName + else n) def fieldName: TermName = if (name.isSetterName) { if (name.is(TraitSetterName)) { - val TraitSetterName(_, original) = name + val TraitSetterName(_, original) = name original.fieldName } else getterName.fieldName } - 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.mapLast(n => n.take(n.length - SETTER_SUFFIX.length).asSimpleName) - } - - def fieldToGetter: TermName = { - assert(name.isFieldName) - name.mapLast(n => n.take(n.length - LOCAL_SUFFIX.length).asSimpleName) - } + else FieldName(name) /** Nominally, name from name$default$N, CONSTRUCTOR for */ def defaultGetterToMethod: TermName = diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index ece3d42dd68b..784a39fd8b83 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -240,7 +240,6 @@ object StdNames { val FAKE_LOCAL_THIS: N = "this$" val LAZY_FIELD_OFFSET: N = "OFFSET$" val LAZY_SLOW_SUFFIX: N = "$lzycompute" - val LOCAL_SUFFIX: N = "$$local" val UNIVERSE_BUILD_PREFIX: N = "$u.build." val UNIVERSE_BUILD: N = "$u.build" val UNIVERSE_PREFIX: N = "$u." diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 4acadc943239..602bdeb029fb 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -234,9 +234,11 @@ object TastyFormat { final val PROTECTEDSETTER = 22 final val INITIALIZER = 23 final val SHADOWED = 24 - final val AVOIDCLASH = 27 - final val DIRECT = 28 - final val OBJECTCLASS = 29 + final val AVOIDCLASH = 30 + final val DIRECT = 31 + final val FIELD = 32 + final val SETTER = 33 + final val OBJECTCLASS = 40 final val SIGNED = 63 final val firstInternalTag = 64 From 1c1355994a66d2af714de5cc033da0a27abe146e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 30 Mar 2017 17:15:10 +0200 Subject: [PATCH 43/68] Fix ParallelTesting NPE --- compiler/test/dotty/tools/dotc/ParallelTesting.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/test/dotty/tools/dotc/ParallelTesting.scala b/compiler/test/dotty/tools/dotc/ParallelTesting.scala index 45de03b4809b..80c56808b456 100644 --- a/compiler/test/dotty/tools/dotc/ParallelTesting.scala +++ b/compiler/test/dotty/tools/dotc/ParallelTesting.scala @@ -423,7 +423,8 @@ trait ParallelTesting { self => extends Test(testSources, times, threadLimit, suppressAllOutput) { private def runMain(dir: JFile, testSource: TestSource): Array[String] = { def renderStackTrace(ex: Throwable): String = - ex.getStackTrace + if (ex == null) "" + else ex.getStackTrace .takeWhile(_.getMethodName != "invoke0") .mkString(" ", "\n ", "") From 0ffa6d865b7a77b2d0a44306691c767d47ab4e08 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 31 Mar 2017 09:50:28 +0200 Subject: [PATCH 44/68] Fix dropModule logic --- .../src/dotty/tools/backend/jvm/DottyBackendInterface.scala | 2 +- compiler/src/dotty/tools/dotc/core/NameOps.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 7ef6b7ef9fe6..db4a0c6943c4 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -557,7 +557,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def fullName: String = sym.showFullName def simpleName: Name = sym.name def javaSimpleName: Name = toDenot(sym).name // addModuleSuffix(simpleName.dropLocal) - def javaBinaryName: Name = javaClassName.replace('.', '/').toTermName // TODO: can we make this a string? addModuleSuffix(fullNameInternal('/')) + def javaBinaryName: Name = javaClassName.replace('.', '/').toTypeName // TODO: can we make this a string? addModuleSuffix(fullNameInternal('/')) def javaClassName: String = toDenot(sym).fullName.toString// addModuleSuffix(fullNameInternal('.')).toString def name: Name = sym.name def rawname: Name = { diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index ac6bfcca35ba..39981543d24f 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -111,8 +111,8 @@ object NameOps { * method needs to work on mangled as well as unmangled names because * it is also called from the backend. */ - def stripModuleClassSuffix: Name = name match { - case name: SimpleTermName if name.endsWith("$") => + def stripModuleClassSuffix: Name = name.toTermName match { + case n: SimpleTermName if n.endsWith("$") => name.unmangleClassName.exclude(ModuleClassName) case _ => name.exclude(ModuleClassName) From e3e5e79e24503a2e6be7f708d81c27068664b893 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 31 Mar 2017 09:52:33 +0200 Subject: [PATCH 45/68] Avoid duplicate hashCode/equals --- compiler/src/dotty/tools/dotc/core/Names.scala | 4 +--- compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala | 2 +- compiler/src/dotty/tools/dotc/transform/TreeChecker.scala | 3 ++- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 37df9cd241b8..d1412c35c72b 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -105,6 +105,7 @@ object Names { def lastIndexOfSlice(str: String): Int = lastPart.toString.lastIndexOfSlice(str) def lastIndexOfSlice(name: Name): Int = lastIndexOfSlice(name.toString) + override def hashCode = System.identityHashCode(this) override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] } @@ -196,9 +197,6 @@ object Names { thisKind == kind || !thisKind.definesNewName && thisKind.tag > kind.tag && 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 { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 602bdeb029fb..d1997376da3e 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -223,8 +223,8 @@ object TastyFormat { final val UTF8 = 1 final val QUALIFIED = 2 final val FLATTENED = 3 - final val EXPANDPREFIX = 5 final val EXPANDED = 4 + final val EXPANDPREFIX = 5 final val TRAITSETTER = 6 final val UNIQUE = 10 final val DEFAULTGETTER = 11 diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 199fac82b08b..9bb00e68320f 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -403,7 +403,8 @@ class TreeChecker extends Phase with SymTransformer { override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = withDefinedSyms(ddef.tparams) { withDefinedSymss(ddef.vparamss) { - if (!sym.isClassConstructor && !(sym.name eq Names.STATIC_CONSTRUCTOR)) assert(isValidJVMMethodName(sym.name), s"${sym.fullName} name is invalid on jvm") + if (!sym.isClassConstructor && !(sym.name eq Names.STATIC_CONSTRUCTOR)) + assert(isValidJVMMethodName(sym.name), s"${sym.name.debugString} name is invalid on jvm") ddef.vparamss.foreach(_.foreach { vparam => assert(vparam.symbol.is(Param), From a3f6ca5a5cd96e17d2f9a9c5187f45ff02b5dd61 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 31 Mar 2017 14:17:16 +0200 Subject: [PATCH 46/68] Make module var names semantic --- .../src/dotty/tools/dotc/core/NameKinds.scala | 1 + .../src/dotty/tools/dotc/core/NameOps.scala | 24 ++----------------- .../src/dotty/tools/dotc/core/StdNames.scala | 1 - .../tools/dotc/core/tasty/TastyFormat.scala | 1 + .../tools/dotc/printing/PlainPrinter.scala | 3 +-- 5 files changed, 5 insertions(+), 25 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index 706320938a39..8279c21bbd04 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -250,6 +250,7 @@ object NameKinds { val AvoidClashName = new SuffixNameKind(AVOIDCLASH, "$_avoid_name_clash_$") val DirectName = new SuffixNameKind(DIRECT, "$direct") val FieldName = new SuffixNameKind(FIELD, "$$local") + val ModuleVarName = new SuffixNameKind(OBJECTVAR, "$module") val ModuleClassName = new SuffixNameKind(OBJECTCLASS, "$", optInfoString = "ModuleClass") object SignedName extends NameKind(63) { diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 39981543d24f..b262fb536f6a 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -57,15 +57,13 @@ object NameOps { def isConstructorName = name == CONSTRUCTOR || name == TRAIT_CONSTRUCTOR def isStaticConstructorName = name == STATIC_CONSTRUCTOR - def isImplClassName = name endsWith IMPL_CLASS_SUFFIX def isLocalDummyName = name startsWith LOCALDUMMY_PREFIX def isReplWrapperName = name.toSimpleName containsSlice INTERPRETER_IMPORT_WRAPPER def isSetterName = name endsWith SETTER_SUFFIX def isImportName = name startsWith IMPORT def isScala2LocalSuffix = name.endsWith(" ") - def isModuleVarName(name: Name): Boolean = - name.stripAnonNumberSuffix endsWith MODULE_VAR_SUFFIX - def isSelectorName = name.startsWith(" ") && name.tail.forall(_.isDigit) + def isModuleVarName(name: Name): Boolean = name.exclude(UniqueName).is(ModuleVarName) + def isSelectorName = name.startsWith("_") && name.tail.forall(_.isDigit) def isOuterSelect = name.endsWith(nme.OUTER_SELECT) /** Is name a variable name? */ @@ -86,21 +84,6 @@ object NameOps { false } - /** If the name ends with $nn where nn are - * all digits, strip the $ and the digits. - * Otherwise return the argument. - */ - def stripAnonNumberSuffix: Name = { - var pos = name.length - while (pos > 0 && name(pos - 1).isDigit) - pos -= 1 - - if (pos > 0 && pos < name.length && name(pos - 1) == '$') - name take (pos - 1) - else - name - } - /** Convert this module name to corresponding module class name */ def moduleClassName: TypeName = name.derived(ModuleClassName).toTypeName @@ -378,9 +361,6 @@ object NameOps { def stripScala2LocalSuffix: TermName = if (name.isScala2LocalSuffix) name.init.asTermName else name - def moduleVarName: TermName = - name ++ MODULE_VAR_SUFFIX - /** The name unary_x for a prefix operator x */ def toUnaryName: TermName = name match { case raw.MINUS => UNARY_- diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 784a39fd8b83..b89775e9ea39 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -117,7 +117,6 @@ object StdNames { val INTERPRETER_WRAPPER_SUFFIX: N = "$object" val LOCALDUMMY_PREFIX: N = " + tp.symbol.is(Module) || tp.symbol.name == nme.IMPORT => toTextRef(tp) ~ ".type" case tp: TermRef if tp.denot.isOverloaded => "" From 24f40bc76493410f2688c8a74028ecb1db7306bf Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 31 Mar 2017 14:40:06 +0200 Subject: [PATCH 47/68] Make outer select names semantic --- compiler/src/dotty/tools/dotc/core/NameKinds.scala | 10 ++++++++++ compiler/src/dotty/tools/dotc/core/NameOps.scala | 8 -------- compiler/src/dotty/tools/dotc/core/StdNames.scala | 1 - .../src/dotty/tools/dotc/core/tasty/TastyFormat.scala | 2 ++ .../src/dotty/tools/dotc/transform/ExplicitOuter.scala | 10 ++++++---- .../dotty/tools/dotc/transform/FirstTransform.scala | 4 ++-- .../dotty/tools/dotc/transform/SuperAccessors.scala | 4 ++-- .../src/dotty/tools/dotc/transform/TreeChecker.scala | 3 ++- compiler/src/dotty/tools/dotc/typer/Inliner.scala | 9 +++------ 9 files changed, 27 insertions(+), 24 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index 8279c21bbd04..cabb831717b5 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -242,6 +242,16 @@ object NameKinds { } } + /** Names of the form N_. Emitted by inliner, replaced by outer path + * in ExplicitOuter. + */ + object OuterSelectName extends NumberedNameKind(OUTERSELECT, "OuterSelect") { + def mkString(underlying: TermName, info: ThisInfo) = { + assert(underlying.isEmpty) + info.num + "_" + } + } + val SuperAccessorName = new PrefixNameKind(SUPERACCESSOR, "super$") val InitializerName = new PrefixNameKind(INITIALIZER, "initial$") val ShadowedName = new PrefixNameKind(SHADOWED, "(shadowed)") diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index b262fb536f6a..44c5c1e09e58 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -60,11 +60,9 @@ object NameOps { def isLocalDummyName = name startsWith LOCALDUMMY_PREFIX def isReplWrapperName = name.toSimpleName containsSlice INTERPRETER_IMPORT_WRAPPER def isSetterName = name endsWith SETTER_SUFFIX - def isImportName = name startsWith IMPORT def isScala2LocalSuffix = name.endsWith(" ") def isModuleVarName(name: Name): Boolean = name.exclude(UniqueName).is(ModuleVarName) def isSelectorName = name.startsWith("_") && name.tail.forall(_.isDigit) - def isOuterSelect = name.endsWith(nme.OUTER_SELECT) /** Is name a variable name? */ def isVariableName: Boolean = name.length > 0 && { @@ -247,12 +245,6 @@ object NameOps { else -1 } - /** The number of hops specified in an outer-select name */ - def outerSelectHops: Int = { - require(isOuterSelect) - name.dropRight(nme.OUTER_SELECT.length).toString.toInt - } - /** The name of the generic runtime operation corresponding to an array operation */ def genericArrayOp: TermName = name match { case nme.apply => nme.array_apply diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index b89775e9ea39..b5d8e356ec60 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -253,7 +253,6 @@ object StdNames { val MODULE_INSTANCE_FIELD: N = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$" val OUTER: N = "$outer" val OUTER_LOCAL: N = "$outer " - val OUTER_SELECT: N = "_" // emitted by inliner, replaced by outer path in explicitouter val REFINE_CLASS: N = "" val ROOTPKG: N = "_root_" val SELECTOR_DUMMY: N = "" diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 04550f18824f..68c5bf10e0d7 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -229,6 +229,8 @@ object TastyFormat { final val UNIQUE = 10 final val DEFAULTGETTER = 11 final val VARIANT = 12 + final val OUTERSELECT = 13 + final val SUPERACCESSOR = 20 final val PROTECTEDACCESSOR = 21 final val PROTECTEDSETTER = 22 diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index a6e6439928a6..c302aa61b543 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -11,6 +11,7 @@ import core.Decorators._ import core.StdNames.nme import core.Names._ import core.NameOps._ +import core.NameKinds.OuterSelectName import ast.Trees._ import SymUtils._ import dotty.tools.dotc.ast.tpd @@ -61,10 +62,11 @@ class ExplicitOuter extends MiniPhaseTransform with InfoTransformer { thisTransf /** Convert a selection of the form `qual.C_` to an outer path from `qual` to `C` */ override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) = - if (tree.name.isOuterSelect) - outer.path(start = tree.qualifier, count = tree.name.outerSelectHops) - .ensureConforms(tree.tpe) - else tree + tree.name match { + case OuterSelectName(_, nhops) => + outer.path(start = tree.qualifier, count = nhops).ensureConforms(tree.tpe) + case _ => tree + } /** First, add outer accessors if a class does not have them yet and it references an outer this. * If the class has outer accessors, implement them. diff --git a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala index 37f978f112fe..a3cf71ef2203 100644 --- a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -20,7 +20,7 @@ import scala.collection.mutable import DenotTransformers._ import typer.Checking import NameOps._ -import NameKinds.AvoidClashName +import NameKinds.{AvoidClashName, OuterSelectName} import StdNames._ @@ -77,7 +77,7 @@ class FirstTransform extends MiniPhaseTransform with InfoTransformer with Annota override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = { tree match { - case Select(qual, name) if !name.isOuterSelect && tree.symbol.exists => + case Select(qual, name) if !name.is(OuterSelectName) && tree.symbol.exists => assert(qual.tpe derivesFrom tree.symbol.owner, i"non member selection of ${tree.symbol.showLocated} from ${qual.tpe} in $tree") case _: TypeTree => case _: Import | _: NamedArg | _: TypTree => diff --git a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index 583834fb31a2..80d9091fbd71 100644 --- a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -11,7 +11,7 @@ import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTrans import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._ import util.Positions._ import Decorators._ -import NameKinds.{ProtectedAccessorName, ProtectedSetterName} +import NameKinds.{ProtectedAccessorName, ProtectedSetterName, OuterSelectName} import Symbols._, TypeUtils._ /** This class performs the following functions: @@ -152,7 +152,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { */ private def ensureProtectedAccessOK(sel: Select, targs: List[Tree])(implicit ctx: Context) = { val sym = sel.symbol - if (sym.isTerm && !sel.name.isOuterSelect && needsProtectedAccessor(sym, sel.pos)) { + if (sym.isTerm && !sel.name.is(OuterSelectName) && needsProtectedAccessor(sym, sel.pos)) { ctx.debuglog("Adding protected accessor for " + sel) protectedAccessorCall(sel, targs) } else sel diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 9bb00e68320f..44c26ecd9c9f 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -13,6 +13,7 @@ import core.Flags._ import core.Constants._ import core.StdNames._ import core.NameOps._ +import core.NameKinds.OuterSelectName import core.Decorators._ import core.TypeErasure.isErasedType import core.Phases.Phase @@ -339,7 +340,7 @@ class TreeChecker extends Phase with SymTransformer { val sym = tree.symbol if (!tpe.isInstanceOf[WithFixedSym] && sym.exists && !sym.is(Private) && - !tree.name.isOuterSelect // outer selects have effectively fixed symbols + !tree.name.is(OuterSelectName) // outer selects have effectively fixed symbols ) { val qualTpe = tree.qualifier.typeOpt val member = diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index eaabb068957e..38a139be1502 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -13,9 +13,9 @@ import Decorators._ import Constants._ import StdNames.nme import Contexts.Context -import Names.{Name, TermName} +import Names.{Name, TermName, EmptyTermName} import NameOps._ -import NameKinds.InlineAccessorName +import NameKinds.{InlineAccessorName, OuterSelectName} import SymDenotations.SymDenotation import Annotations._ import transform.ExplicitOuter @@ -399,9 +399,6 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { // The class that the this-proxy `selfSym` represents def classOf(selfSym: Symbol) = selfSym.info.widen.classSymbol - // The name of the outer selector that computes the rhs of `selfSym` - def outerSelector(n: Int): TermName = n.toString.toTermName ++ nme.OUTER_SELECT - // The total nesting depth of the class represented by `selfSym`. def outerLevel(selfSym: Symbol): Int = classOf(selfSym).ownersIterator.length @@ -419,7 +416,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { if (!lastSelf.exists) prefix else - untpd.Select(ref(lastSelf), outerSelector(lastLevel - level)).withType(selfSym.info) + untpd.Select(ref(lastSelf), OuterSelectName(EmptyTermName, lastLevel - level)).withType(selfSym.info) bindingsBuf += ValDef(selfSym.asTerm, rhs) lastSelf = selfSym lastLevel = level From 130069ad787ca20e960d57e11e6f4911e3bed5a0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 31 Mar 2017 15:01:06 +0200 Subject: [PATCH 48/68] Cleanups of NameOps Remove unused functionality --- .../backend/jvm/DottyBackendInterface.scala | 4 +- .../src/dotty/tools/dotc/core/NameOps.scala | 79 ------------------- .../src/dotty/tools/dotc/core/StdNames.scala | 1 - .../tools/dotc/transform/SuperAccessors.scala | 4 +- .../src/dotty/tools/dotc/typer/Namer.scala | 12 +-- .../dotty/tools/dotc/typer/RefChecks.scala | 15 ++-- 6 files changed, 15 insertions(+), 100 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index db4a0c6943c4..a300857ecd79 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -30,9 +30,9 @@ import Decorators._ import tpd._ import scala.tools.asm -import NameOps._ import StdNames.nme import NameOps._ +import NameKinds.DefaultGetterName import dotty.tools.dotc.core import dotty.tools.dotc.core.Names.TypeName @@ -255,7 +255,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma val evalue = t.symbol.name.toString // value the actual enumeration value. av.visitEnum(name, edesc, evalue) } else { - assert(toDenot(t.symbol).name.toTermName.defaultGetterIndex >= 0) // this should be default getter. do not emmit. + assert(toDenot(t.symbol).name.is(DefaultGetterName)) // this should be default getter. do not emmit. } case t: SeqLiteral => val arrAnnotV: AnnotationVisitor = av.visitArray(name) diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 44c5c1e09e58..2caaaf1abdbf 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -61,7 +61,6 @@ object NameOps { def isReplWrapperName = name.toSimpleName containsSlice INTERPRETER_IMPORT_WRAPPER def isSetterName = name endsWith SETTER_SUFFIX def isScala2LocalSuffix = name.endsWith(" ") - def isModuleVarName(name: Name): Boolean = name.exclude(UniqueName).is(ModuleVarName) def isSelectorName = name.startsWith("_") && name.tail.forall(_.isDigit) /** Is name a variable name? */ @@ -105,9 +104,6 @@ object NameOps { else name.toTermName.exclude(AvoidClashName) } - /** The superaccessor for method with given name */ - def superName: TermName = SuperAccessorName(name.toTermName) - def expandedName(base: Symbol, kind: QualifiedNameKind = ExpandedName)(implicit ctx: Context): N = { val prefix = if (base.name.is(ExpandedName)) base.name else base.fullNameSeparated(ExpandPrefixName) @@ -307,17 +303,6 @@ object NameOps { } } - // needed??? - private val Boxed = Map[TypeName, TypeName]( - tpnme.Boolean -> jtpnme.BoxedBoolean, - tpnme.Byte -> jtpnme.BoxedByte, - tpnme.Char -> jtpnme.BoxedCharacter, - tpnme.Short -> jtpnme.BoxedShort, - tpnme.Int -> jtpnme.BoxedInteger, - tpnme.Long -> jtpnme.BoxedLong, - tpnme.Float -> jtpnme.BoxedFloat, - tpnme.Double -> jtpnme.BoxedDouble) - implicit class TermNameDecorator(val name: TermName) extends AnyVal { import nme._ @@ -338,18 +323,6 @@ object NameOps { } else FieldName(name) - /** Nominally, name from name$default$N, CONSTRUCTOR for */ - def defaultGetterToMethod: TermName = - name rewrite { - case DefaultGetterName(methName, _) => methName - } - - /** If this is a default getter, its index (starting from 0), else -1 */ - def defaultGetterIndex: Int = - name collect { - case DefaultGetterName(_, num) => num - } getOrElse -1 - def stripScala2LocalSuffix: TermName = if (name.isScala2LocalSuffix) name.init.asTermName else name @@ -361,57 +334,5 @@ object NameOps { case raw.BANG => UNARY_! case _ => name } - - /** The name of a method which stands in for a primitive operation - * during structural type dispatch. - */ - def primitiveInfixMethodName: TermName = name match { - case OR => takeOr - case XOR => takeXor - case AND => takeAnd - case EQ => testEqual - case NE => testNotEqual - case ADD => add - case SUB => subtract - case MUL => multiply - case DIV => divide - case MOD => takeModulo - case LSL => shiftSignedLeft - case LSR => shiftLogicalRight - case ASR => shiftSignedRight - case LT => testLessThan - case LE => testLessOrEqualThan - case GE => testGreaterOrEqualThan - case GT => testGreaterThan - case ZOR => takeConditionalOr - case ZAND => takeConditionalAnd - case _ => NO_NAME - } - - /** Postfix/prefix, really. - */ - def primitivePostfixMethodName: TermName = name match { - case UNARY_! => takeNot - case UNARY_+ => positive - case UNARY_- => negate - case UNARY_~ => complement - case `toByte` => toByte - case `toShort` => toShort - case `toChar` => toCharacter - case `toInt` => toInteger - case `toLong` => toLong - case `toFloat` => toFloat - case `toDouble` => toDouble - case _ => NO_NAME - } - - def primitiveMethodName: TermName = - primitiveInfixMethodName match { - case NO_NAME => primitivePostfixMethodName - case name => name - } } - - private final val FalseSuper = "$$super".toTermName - private val FalseSuperLength = FalseSuper.length } diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index b5d8e356ec60..8eea6adedc50 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -252,7 +252,6 @@ object StdNames { val REIFY_SYMDEF_PREFIX: N = "symdef$" val MODULE_INSTANCE_FIELD: N = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$" val OUTER: N = "$outer" - val OUTER_LOCAL: N = "$outer " val REFINE_CLASS: N = "" val ROOTPKG: N = "_root_" val SELECTOR_DUMMY: N = "" diff --git a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index 80d9091fbd71..84a32f93bf08 100644 --- a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -11,7 +11,7 @@ import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTrans import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._ import util.Positions._ import Decorators._ -import NameKinds.{ProtectedAccessorName, ProtectedSetterName, OuterSelectName} +import NameKinds.{ProtectedAccessorName, ProtectedSetterName, OuterSelectName, SuperAccessorName} import Symbols._, TypeUtils._ /** This class performs the following functions: @@ -72,7 +72,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { val Select(qual, name) = sel val sym = sel.symbol val clazz = qual.symbol.asClass - var superName = name.superName + var superName = SuperAccessorName(name.asTermName) if (clazz is Trait) superName = superName.expandedName(clazz) val superInfo = sel.tpe.widenSingleton.ensureMethodic diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 78a1cd9c30e0..19b6dfa712a5 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -6,6 +6,7 @@ import core._ import ast._ import Trees._, Constants._, StdNames._, Scopes._, Denotations._, Comments._ import Contexts._, Symbols._, Types._, SymDenotations._, Names._, NameOps._, Flags._, Decorators._ +import NameKinds.DefaultGetterName import ast.desugar, ast.desugar._ import ProtoTypes._ import util.Positions._ @@ -1012,12 +1013,8 @@ class Namer { typer: Typer => * the corresponding parameter where bound parameters are replaced by * Wildcards. */ - def rhsProto = { - val name = sym.asTerm.name - val idx = name.defaultGetterIndex - if (idx < 0) WildcardType - else { - val original = name.defaultGetterToMethod + def rhsProto = sym.asTerm.name collect { + case DefaultGetterName(original, idx) => val meth: Denotation = if (original.isConstructorName && (sym.owner is ModuleClass)) sym.owner.companionClass.info.decl(nme.CONSTRUCTOR) @@ -1035,8 +1032,7 @@ class Namer { typer: Typer => paramProto(defaultAlts.head.info.widen.paramInfoss, idx) else WildcardType - } - } + } getOrElse WildcardType // println(s"final inherited for $sym: ${inherited.toString}") !!! // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}") diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 49bc24c80342..4715873e5483 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -6,6 +6,7 @@ import core._ import config._ import Symbols._, SymDenotations._, Types._, Contexts._, Decorators._, Flags._, Names._, NameOps._ import StdNames._, Denotations._, Scopes._, Constants.Constant, SymUtils._ +import NameKinds.DefaultGetterName import Annotations._ import util.Positions._ import scala.collection.{ mutable, immutable } @@ -24,12 +25,8 @@ object RefChecks { import reporting.diagnostic.Message import reporting.diagnostic.messages._ - - private def isDefaultGetter(name: Name): Boolean = - name.isTermName && name.asTermName.defaultGetterIndex >= 0 - private val defaultMethodFilter = new NameFilter { - def apply(pre: Type, name: Name)(implicit ctx: Context): Boolean = isDefaultGetter(name) + def apply(pre: Type, name: Name)(implicit ctx: Context): Boolean = name.is(DefaultGetterName) } /** Only one overloaded alternative is allowed to define default arguments */ @@ -45,7 +42,9 @@ object RefChecks { if defaultGetterClass.isClass ) { val defaultGetterNames = defaultGetterClass.asClass.memberNames(defaultMethodFilter) - val defaultMethodNames = defaultGetterNames map (_.asTermName.defaultGetterToMethod) + val defaultMethodNames = defaultGetterNames map { _ rewrite { + case DefaultGetterName(methName, _) => methName + }} for (name <- defaultMethodNames) { val methods = clazz.info.member(name).alternatives.map(_.symbol) @@ -238,7 +237,7 @@ object RefChecks { } } else - isDefaultGetter(member.name) || // default getters are not checked for compatibility + member.name.is(DefaultGetterName) || // default getters are not checked for compatibility memberTp.overrides(otherTp) //Console.println(infoString(member) + " overrides " + infoString(other) + " in " + clazz);//DEBUG @@ -298,7 +297,7 @@ object RefChecks { } else if (other.isEffectivelyFinal) { // (1.2) overrideError(i"cannot override final member ${other.showLocated}") } else if (!other.is(Deferred) && - !isDefaultGetter(other.name) && + !other.name.is(DefaultGetterName) && !member.isAnyOverride) { // (*) Exclusion for default getters, fixes SI-5178. We cannot assign the Override flag to // the default getter: one default getter might sometimes override, sometimes not. Example in comment on ticket. From 7a927ce233a8ea4b8ddc285b8a36c61ca3fdd405 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 31 Mar 2017 16:07:57 +0200 Subject: [PATCH 49/68] Run compileStdLib only as junit test It fails without any test output in partest --- compiler/test/dotc/tests.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/test/dotc/tests.scala b/compiler/test/dotc/tests.scala index 1c80767ee255..af2c88e1ac50 100644 --- a/compiler/test/dotc/tests.scala +++ b/compiler/test/dotc/tests.scala @@ -203,7 +203,9 @@ class tests extends CompilerTest { private val stdlibFiles: List[String] = StdLibSources.whitelisted - @Test def compileStdLib = compileList("compileStdLib", stdlibFiles, "-migration" :: "-Yno-inline" :: scala2mode) + @Test def compileStdLib = + if (!generatePartestFiles) + compileList("compileStdLib", stdlibFiles, "-migration" :: "-Yno-inline" :: scala2mode) @Test def compileMixed = compileLine( """../tests/pos/B.scala |../scala-scala/src/library/scala/collection/immutable/Seq.scala From b4f21c6da6b6bc1797908f1400631573b6445e31 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 31 Mar 2017 18:32:02 +0200 Subject: [PATCH 50/68] 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. --- compiler/src/dotty/tools/dotc/FromTasty.scala | 3 +- .../src/dotty/tools/dotc/ast/Desugar.scala | 2 +- .../src/dotty/tools/dotc/ast/TreeInfo.scala | 2 +- .../dotty/tools/dotc/core/Definitions.scala | 19 ++-- .../src/dotty/tools/dotc/core/NameKinds.scala | 6 +- .../src/dotty/tools/dotc/core/NameOps.scala | 101 +++++++----------- .../src/dotty/tools/dotc/core/Names.scala | 57 +++++----- .../src/dotty/tools/dotc/core/StdNames.scala | 37 ++++--- .../tools/dotc/core/SymDenotations.scala | 2 +- .../dotc/core/classfile/ClassfileParser.scala | 10 +- .../tools/dotc/core/tasty/NameBuffer.scala | 4 +- .../dotty/tools/dotc/parsing/Scanners.scala | 6 +- .../dotty/tools/dotc/parsing/package.scala | 2 +- .../tools/dotc/printing/RefinedPrinter.scala | 5 +- .../dotty/tools/dotc/typer/Applications.scala | 5 +- .../dotty/tools/dotc/typer/EtaExpansion.scala | 2 +- 16 files changed, 124 insertions(+), 139 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/FromTasty.scala b/compiler/src/dotty/tools/dotc/FromTasty.scala index b060a2054090..da0190fa19fd 100644 --- a/compiler/src/dotty/tools/dotc/FromTasty.scala +++ b/compiler/src/dotty/tools/dotc/FromTasty.scala @@ -17,6 +17,7 @@ import Decorators._ import dotty.tools.dotc.transform.Pickler import tasty.DottyUnpickler import ast.tpd._ +import NameKinds.QualifiedName /** Compiler for TASTY files. * Usage: @@ -74,7 +75,7 @@ object FromTasty extends Driver { case unit: TASTYCompilationUnit => val className = unit.className.toTypeName val clsd = - if (className.contains('.')) ctx.base.staticRef(className) + if (className.is(QualifiedName)) ctx.base.staticRef(className) else defn.EmptyPackageClass.info.decl(className) def cannotUnpickle(reason: String) = { ctx.error(s"class $className cannot be unpickled because $reason") diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 9cf530f8fe3c..111382b1803c 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -403,7 +403,7 @@ object desugar { def anyRef = ref(defn.AnyRefAlias.typeRef) def productConstr(n: Int) = { - val tycon = scalaDot((tpnme.Product.toString + n).toTypeName) + val tycon = scalaDot((str.Product + n).toTypeName) val targs = constrVparamss.head map (_.tpt) if (targs.isEmpty) tycon else AppliedTypeTree(tycon, targs) } diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index 037ab73aff17..f3bce4000079 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -157,7 +157,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => } /** Is name a left-associative operator? */ - def isLeftAssoc(operator: Name) = operator.nonEmpty && (operator.last != ':') + def isLeftAssoc(operator: Name) = !operator.isEmpty && (operator.toSimpleName.last != ':') /** can this type be a type pattern? */ def mayBeTypePat(tree: untpd.Tree): Boolean = unsplice(tree) match { diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 670b919acbe4..a1858e93485a 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -119,7 +119,7 @@ class Definitions { enterTypeParam(cls, name ++ "$T" ++ i.toString, Contravariant, decls) val resParam = enterTypeParam(cls, name ++ "$R", Covariant, decls) val (methodType, parentTraits) = - if (name.startsWith(tpnme.ImplicitFunction)) { + if (name.startsWith(str.ImplicitFunction)) { val superTrait = FunctionType(arity).appliedTo(argParams.map(_.typeRef) ::: resParam.typeRef :: Nil) (ImplicitMethodType, ctx.normalizeToClassRefs(superTrait :: Nil, cls, decls)) @@ -723,12 +723,11 @@ class Definitions { /** If type `ref` refers to a class in the scala package, its name, otherwise EmptyTypeName */ def scalaClassName(ref: Type)(implicit ctx: Context): TypeName = scalaClassName(ref.classSymbol) - private def isVarArityClass(cls: Symbol, prefix: Name) = { - val name = scalaClassName(cls) - name.startsWith(prefix) && - name.length > prefix.length && - name.drop(prefix.length).forall(_.isDigit) - } + private def isVarArityClass(cls: Symbol, prefix: String) = + scalaClassName(cls).testSimple(name => + name.startsWith(prefix) && + name.length > prefix.length && + name.drop(prefix.length).forall(_.isDigit)) def isBottomClass(cls: Symbol) = cls == NothingClass || cls == NullClass @@ -758,9 +757,9 @@ class Definitions { */ def isSyntheticFunctionClass(cls: Symbol) = scalaClassName(cls).isSyntheticFunction - def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.AbstractFunction) - def isTupleClass(cls: Symbol) = isVarArityClass(cls, tpnme.Tuple) - def isProductClass(cls: Symbol) = isVarArityClass(cls, tpnme.Product) + def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, str.AbstractFunction) + def isTupleClass(cls: Symbol) = isVarArityClass(cls, str.Tuple) + def isProductClass(cls: Symbol) = isVarArityClass(cls, str.Product) /** Returns the erased class of the function class `cls` * - FunctionN for N > 22 becomes FunctionXXL diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index cabb831717b5..8ea19bed2a39 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -164,7 +164,7 @@ object NameKinds { val ExpandPrefixName = new QualifiedNameKind(EXPANDPREFIX, "$") val ExpandedName = new QualifiedNameKind(EXPANDED, str.EXPAND_SEPARATOR) { - private val FalseSuper = "$$super".toTermName + private val FalseSuper = termName("$$super") private val FalseSuperLength = FalseSuper.length override def unmangle(name: SimpleTermName): TermName = { @@ -216,10 +216,10 @@ object NameKinds { object DefaultGetterName extends NumberedNameKind(DEFAULTGETTER, "DefaultGetter") { def mkString(underlying: TermName, info: ThisInfo) = { val prefix = if (underlying.isConstructorName) nme.DEFAULT_GETTER_INIT else underlying - prefix.toString + nme.DEFAULT_GETTER + (info.num + 1) + prefix.toString + str.DEFAULT_GETTER + (info.num + 1) } - private val dgLen = nme.DEFAULT_GETTER.length + private val dgLen = str.DEFAULT_GETTER.length override def unmangle(name: SimpleTermName): TermName = { var i = name.length diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 2caaaf1abdbf..e74bf8ca7d6f 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -52,24 +52,32 @@ object NameOps { implicit class NameDecorator[N <: Name](val name: N) extends AnyVal { import nme._ + def testSimple(f: SimpleTermName => Boolean): Boolean = name match { + case name: SimpleTermName => f(name) + case name: TypeName => name.toTermName.testSimple(f) + case _ => false + } + def likeTyped(n: PreName): N = (if (name.isTermName) n.toTermName else n.toTypeName).asInstanceOf[N] def isConstructorName = name == CONSTRUCTOR || name == TRAIT_CONSTRUCTOR def isStaticConstructorName = name == STATIC_CONSTRUCTOR def isLocalDummyName = name startsWith LOCALDUMMY_PREFIX - def isReplWrapperName = name.toSimpleName containsSlice INTERPRETER_IMPORT_WRAPPER + def isReplWrapperName = name.toString contains str.INTERPRETER_IMPORT_WRAPPER def isSetterName = name endsWith SETTER_SUFFIX - def isScala2LocalSuffix = name.endsWith(" ") - def isSelectorName = name.startsWith("_") && name.tail.forall(_.isDigit) + def isScala2LocalSuffix = testSimple(_.endsWith(" ")) + def isSelectorName = testSimple(n => n.startsWith("_") && n.drop(1).forall(_.isDigit)) /** Is name a variable name? */ - def isVariableName: Boolean = name.length > 0 && { - val first = name.head - (((first.isLower && first.isLetter) || first == '_') - && (name != false_) - && (name != true_) - && (name != null_)) + def isVariableName: Boolean = testSimple { n => + n.length > 0 && { + val first = n.head + (((first.isLower && first.isLetter) || first == '_') + && (n != false_) + && (n != true_) + && (n != null_)) + } } def isOpAssignmentName: Boolean = name match { @@ -91,11 +99,10 @@ object NameOps { * method needs to work on mangled as well as unmangled names because * it is also called from the backend. */ - def stripModuleClassSuffix: Name = name.toTermName match { - case n: SimpleTermName if n.endsWith("$") => - name.unmangleClassName.exclude(ModuleClassName) - case _ => - name.exclude(ModuleClassName) + def stripModuleClassSuffix: N = likeTyped { + val name1 = + if (name.isSimple && name.endsWith("$")) name.unmangleClassName else name + name.exclude(ModuleClassName) } /** If flags is a ModuleClass but not a Package, add module class suffix */ @@ -159,56 +166,13 @@ object NameOps { } } - def unmangleClassName: N = - if (name.isSimple && name.isTypeName) - if (name.endsWith(MODULE_SUFFIX) && !tpnme.falseModuleClassNames.contains(name.asTypeName)) - likeTyped(name.dropRight(MODULE_SUFFIX.length).moduleClassName) - else name - else name - - /** Translate a name into a list of simple TypeNames and TermNames. - * In all segments before the last, type/term is determined by whether - * the following separator char is '.' or '#'. The last segment - * is of the same type as the original name. - * - * Examples: - * - * package foo { - * object Lorax { object Wog ; class Wog } - * class Lorax { object Zax ; class Zax } - * } - * - * f("foo.Lorax".toTermName) == List("foo": Term, "Lorax": Term) // object Lorax - * f("foo.Lorax".toTypeName) == List("foo": Term, "Lorax": Type) // class Lorax - * f("Lorax.Wog".toTermName) == List("Lorax": Term, "Wog": Term) // object Wog - * f("Lorax.Wog".toTypeName) == List("Lorax": Term, "Wog": Type) // class Wog - * f("Lorax#Zax".toTermName) == List("Lorax": Type, "Zax": Term) // object Zax - * f("Lorax#Zax".toTypeName) == List("Lorax": Type, "Zax": Type) // class Zax - * - * Note that in actual scala syntax you cannot refer to object Zax without an - * instance of Lorax, so Lorax#Zax could only mean the type. One might think - * that Lorax#Zax.type would work, but this is not accepted by the parser. - * For the purposes of referencing that object, the syntax is allowed. - */ - def segments: List[Name] = { - def mkName(name: Name, follow: Char): Name = - if (follow == '.') name.toTermName else name.toTypeName - - name.indexWhere(ch => ch == '.' || ch == '#') match { - case -1 => - if (name.isEmpty) scala.Nil else name :: scala.Nil - case idx => - mkName(name take idx, name(idx)) :: (name drop (idx + 1)).segments - } - } - /** Is a synthetic function name * - N for FunctionN * - N for ImplicitFunctionN * - (-1) otherwise */ def functionArity: Int = - functionArityFor(tpnme.Function) max functionArityFor(tpnme.ImplicitFunction) + functionArityFor(str.Function) max functionArityFor(str.ImplicitFunction) /** Is a function name * - FunctionN for N >= 0 @@ -221,7 +185,7 @@ object NameOps { * - ImplicitFunctionN for N >= 0 * - false otherwise */ - def isImplicitFunction: Boolean = functionArityFor(tpnme.ImplicitFunction) >= 0 + def isImplicitFunction: Boolean = functionArityFor(str.ImplicitFunction) >= 0 /** Is a synthetic function name * - FunctionN for N > 22 @@ -229,12 +193,12 @@ object NameOps { * - false otherwise */ def isSyntheticFunction: Boolean = { - functionArityFor(tpnme.Function) > MaxImplementedFunctionArity || - functionArityFor(tpnme.ImplicitFunction) >= 0 + functionArityFor(str.Function) > MaxImplementedFunctionArity || + functionArityFor(str.ImplicitFunction) >= 0 } /** Parsed function arity for function with some specific prefix */ - private def functionArityFor(prefix: Name): Int = { + private def functionArityFor(prefix: String): Int = { if (name.startsWith(prefix)) try name.toString.substring(prefix.length).toInt catch { case _: NumberFormatException => -1 } @@ -285,6 +249,13 @@ object NameOps { /** If name length exceeds allowable limit, replace part of it by hash */ def compactified(implicit ctx: Context): TermName = termName(compactify(name.toString)) + def unmangleClassName: N = name.toTermName match { + case name: SimpleTermName + if name.endsWith(str.MODULE_SUFFIX) && !nme.falseModuleClassNames.contains(name) => + likeTyped(name.dropRight(str.MODULE_SUFFIX.length).moduleClassName) + case _ => name + } + def unmangle(kind: NameKind): N = likeTyped { name rewrite { case unmangled: SimpleTermName => @@ -306,11 +277,11 @@ object NameOps { implicit class TermNameDecorator(val name: TermName) extends AnyVal { import nme._ - def setterName: TermName = name.exclude(FieldName) ++ SETTER_SUFFIX + def setterName: TermName = name.exclude(FieldName) ++ str.SETTER_SUFFIX def getterName: TermName = name.exclude(FieldName).mapLast(n => - if (n.endsWith(SETTER_SUFFIX)) n.take(n.length - SETTER_SUFFIX.length).asSimpleName + if (n.endsWith(SETTER_SUFFIX)) n.take(n.length - str.SETTER_SUFFIX.length).asSimpleName else n) def fieldName: TermName = @@ -324,7 +295,7 @@ object NameOps { else FieldName(name) def stripScala2LocalSuffix: TermName = - if (name.isScala2LocalSuffix) name.init.asTermName else name + if (name.isScala2LocalSuffix) name.asSimpleName.dropRight(1) else name /** The name unary_x for a prefix operator x */ def toUnaryName: TermName = name match { diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index d1412c35c72b..5b6315e663f5 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -88,8 +88,8 @@ object Names { /** Replace operator symbols by corresponding \$op_name's. */ def encode: Name - def firstPart: TermName - def lastPart: TermName + def firstPart: SimpleTermName + def lastPart: SimpleTermName /** A more efficient version of concatenation */ def ++ (other: Name): ThisName = ++ (other.toString) @@ -204,7 +204,15 @@ object Names { def apply(n: Int) = chrs(start + n) - private def contains(ch: Char): Boolean = { + def exists(p: Char => Boolean): Boolean = { + var i = 0 + while (i < length && !p(chrs(start + i))) i += 1 + i < length + } + + def forall(p: Char => Boolean) = !exists(!p(_)) + + def contains(ch: Char): Boolean = { var i = 0 while (i < length && chrs(start + i) != ch) i += 1 i < length @@ -224,6 +232,12 @@ object Names { i > str.length } + def lastIndexOf(ch: Char, start: Int = length - 1): Int = { + var i = start + while (i >= 0 && apply(i) != ch) i -= 1 + i + } + override def replace(from: Char, to: Char): SimpleTermName = { val cs = new Array[Char](length) Array.copy(chrs, start, cs, 0, length) @@ -233,6 +247,19 @@ object Names { termName(cs, 0, length) } + def slice(from: Int, until: Int): SimpleTermName = { + assert(0 <= from && from <= until && until <= length) + termName(chrs, start + from, until - from) + } + + def drop(n: Int) = slice(n, length) + def take(n: Int) = slice(0, n) + def dropRight(n: Int) = slice(0, length - n) + def takeRight(n: Int) = slice(length - n, length) + + def head = apply(0) + def last = apply(length - 1) + def isSimple = true def asSimpleName = this def toSimpleName = this @@ -242,12 +269,6 @@ object Names { 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) @@ -490,24 +511,6 @@ object Names { val dontEncode = Set(CONSTRUCTOR, EMPTY_PACKAGE, REFINEMENT) - def termNameBuilder: Builder[Char, TermName] = - StringBuilder.newBuilder.mapResult(termName) - - def typeNameBuilder: Builder[Char, TypeName] = - StringBuilder.newBuilder.mapResult(termName(_).toTypeName) - - implicit class nameToSeq(val name: Name) extends IndexedSeqOptimized[Char, Name] { - 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 - - def seq: WrappedString = new WrappedString(name.toString) - override protected[this] def thisCollection: WrappedString = seq - def indexOfSlice(name: Name): Int = indexOfSlice(name.toString) - def containsSlice(name: Name): Boolean = containsSlice(name.toString) - } - implicit val NameOrdering: Ordering[Name] = new Ordering[Name] { private def compareInfos(x: NameInfo, y: NameInfo): Int = if (x.kind.tag != y.kind.tag) x.kind.tag - y.kind.tag diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 8eea6adedc50..c942a058a815 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -16,12 +16,26 @@ object StdNames { /** Base strings from which synthetic names are derived. */ object str { - val EXPAND_SEPARATOR = "$$" - val TRAIT_SETTER_SEPARATOR = "$_setter_$" - val SUPER_PREFIX = "super$" - val INITIALIZER_PREFIX = "initial$" - val SHADOWED_PREFIX = "(shadowed)" - val AVOID_CLASH_SUFFIX = "$_avoid_name_clash_$" + final val SETTER_SUFFIX = "_$eq" + final val EXPAND_SEPARATOR = "$$" + final val TRAIT_SETTER_SEPARATOR = "$_setter_$" + final val SUPER_PREFIX = "super$" + final val INITIALIZER_PREFIX = "initial$" + final val SHADOWED_PREFIX = "(shadowed)" + final val AVOID_CLASH_SUFFIX = "$_avoid_name_clash_$" + final val MODULE_SUFFIX = NameTransformer.MODULE_SUFFIX_STRING + final val DEFAULT_GETTER = "$default$" + + final val INTERPRETER_IMPORT_WRAPPER = "$iw" + final val INTERPRETER_LINE_PREFIX = "line" + final val INTERPRETER_VAR_PREFIX = "res" + final val INTERPRETER_WRAPPER_SUFFIX = "$object" + + final val Function = "Function" + final val ImplicitFunction = "ImplicitFunction" + final val AbstractFunction = "AbstractFunction" + final val Tuple = "Tuple" + final val Product = "Product" def sanitize(str: String) = str.replaceAll("""[<>]""", """\$""") } @@ -102,7 +116,7 @@ object StdNames { val BITMAP_TRANSIENT: N = BITMAP_PREFIX + "trans$" // initialization bitmap for transient lazy vals val BITMAP_CHECKINIT: N = BITMAP_PREFIX + "init$" // initialization bitmap for checkinit values val BITMAP_CHECKINIT_TRANSIENT: N = BITMAP_PREFIX + "inittrans$" // initialization bitmap for transient checkinit values - val DEFAULT_GETTER: N = "$default$" + val DEFAULT_GETTER: N = str.DEFAULT_GETTER val DEFAULT_GETTER_INIT: N = "$lessinit$greater" val DO_WHILE_PREFIX: N = "doWhile$" val EMPTY: N = "" @@ -111,10 +125,6 @@ object StdNames { val EXPAND_SEPARATOR: N = str.EXPAND_SEPARATOR val IMPL_CLASS_SUFFIX: N = "$class" val IMPORT: N = "" - val INTERPRETER_IMPORT_WRAPPER: N = "$iw" - val INTERPRETER_LINE_PREFIX: N = "line" - val INTERPRETER_VAR_PREFIX: N = "res" - val INTERPRETER_WRAPPER_SUFFIX: N = "$object" val LOCALDUMMY_PREFIX: N = " qualify(name) case name @ AnyQualifiedName(_, _) => qualify(name.toSimpleName) diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index b09da70e1ee5..98ac5253355a 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -247,7 +247,8 @@ class ClassfileParser( final def objToAny(tp: Type)(implicit ctx: Context) = if (tp.isDirectRef(defn.ObjectClass) && !ctx.phase.erasedTypes) defn.AnyType else tp - private def sigToType(sig: TermName, owner: Symbol = null)(implicit ctx: Context): Type = { + private def sigToType(signature: TermName, owner: Symbol = null)(implicit ctx: Context): Type = { + val sig = signature.toSimpleName var index = 0 val end = sig.length def accept(ch: Char): Unit = { @@ -655,7 +656,10 @@ class ClassfileParser( * and implicitly current class' superclasses. */ private def enterOwnInnerClasses()(implicit ctx: Context): Unit = { - def className(name: Name): Name = name.drop(name.lastIndexOf('.') + 1) + def className(name: Name): Name = { + val name1 = name.toSimpleName + name1.drop(name1.lastIndexOf('.') + 1) + } def enterClassAndModule(entry: InnerClassEntry, file: AbstractFile, jflags: Int) = { ctx.base.loaders.enterClassAndModule( @@ -1003,7 +1007,7 @@ class ClassfileParser( val start = starts(index) if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start) val name = getExternalName(in.getChar(start + 1)) - if (name(0) == ARRAY_TAG) { + if (name.firstPart(0) == ARRAY_TAG) { c = sigToType(name) values(index) = c } else { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index 6df96a9a0129..7ee6427f3724 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala @@ -30,7 +30,7 @@ class NameBuffer extends TastyBuffer(10000) { nameIndex(prefix); nameIndex(name) case AnyUniqueName(original, separator, num) => nameIndex(separator.toTermName) - if (original.nonEmpty) nameIndex(original) + if (!original.isEmpty) nameIndex(original) case DerivedTermName(original, _) => nameIndex(original) case _ => @@ -68,7 +68,7 @@ class NameBuffer extends TastyBuffer(10000) { withLength { writeNameRef(separator.toTermName) writeNat(num) - if (original.nonEmpty) writeNameRef(original) + if (!original.isEmpty) writeNameRef(original) } case DefaultGetterName(method, paramNumber) => withLength { writeNameRef(method); writeNat(paramNumber) } diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 3084c30a8957..b0fa8d760ec3 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -37,7 +37,7 @@ object Scanners { var lastOffset: Offset = 0 /** the name of an identifier */ - var name: TermName = null + var name: SimpleTermName = null /** the string value of a literal */ var strVal: String = null @@ -98,10 +98,10 @@ object Scanners { /** Clear buffer and set name and token */ def finishNamed(idtoken: Token = IDENTIFIER, target: TokenData = this): Unit = { - target.name = flushBuf(litBuf).toTermName + target.name = termName(flushBuf(litBuf)) target.token = idtoken if (idtoken == IDENTIFIER) { - val idx = target.name.asSimpleName.start + val idx = target.name.start target.token = toToken(idx) } } diff --git a/compiler/src/dotty/tools/dotc/parsing/package.scala b/compiler/src/dotty/tools/dotc/parsing/package.scala index 8b113ed96c30..cdb30d0be7ed 100644 --- a/compiler/src/dotty/tools/dotc/parsing/package.scala +++ b/compiler/src/dotty/tools/dotc/parsing/package.scala @@ -10,7 +10,7 @@ package object parsing { def precedence(operator: Name): Int = if (operator eq nme.ERROR) -1 else { - val firstCh = operator(0) + val firstCh = operator.firstPart.head if (isScalaLetter(firstCh)) 1 else if (operator.isOpAssignmentName) 0 else firstCh match { diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index f6399d3b788f..c3f36cc463f7 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -156,8 +156,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { // one version of the annotation tree that has the correct positions). withoutPos(super.toText(tp)) case tp: SelectionProto => - return "?{ " ~ toText(tp.name) ~ (" " provided !tp.name.decode.last.isLetterOrDigit) ~ - ": " ~ toText(tp.memberProto) ~ " }" + return "?{ " ~ toText(tp.name) ~ + (" " provided !tp.name.toSimpleName.decode.last.isLetterOrDigit) ~ + ": " ~ toText(tp.memberProto) ~ " }" case tp: ViewProto => return toText(tp.argType) ~ " ?=>? " ~ toText(tp.resultType) case tp @ FunProto(args, resultType, _) => diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index db1e0bcfbe0c..2f2af9868b34 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -403,7 +403,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def missingArg(n: Int): Unit = { val pname = methodType.paramNames(n) fail( - if (pname contains '$') s"not enough arguments for $methString" + if (pname.firstPart contains '$') s"not enough arguments for $methString" else s"missing argument for parameter $pname of $methString") } @@ -719,7 +719,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic => val lhs1 = typedExpr(lhs) val liftedDefs = new mutable.ListBuffer[Tree] val lhs2 = untpd.TypedSplice(liftAssigned(liftedDefs, lhs1)) - val assign = untpd.Assign(lhs2, untpd.Apply(untpd.Select(lhs2, name.init), rhss)) + val assign = untpd.Assign(lhs2, + untpd.Apply(untpd.Select(lhs2, name.asSimpleName.dropRight(1)), rhss)) wrapDefs(liftedDefs, typed(assign)) } diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index 22acd112b61c..e5480c98d911 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -63,7 +63,7 @@ object EtaExpansion { case mt: MethodType => (args, mt.paramNames, mt.paramInfos).zipped map { (arg, name, tp) => if (tp.isInstanceOf[ExprType]) arg - else liftArg(defs, arg, if (name contains '$') EmptyTermName else name) + else liftArg(defs, arg, if (name.firstPart contains '$') EmptyTermName else name) } case _ => args map (liftArg(defs, _)) From 4a54b2c24d6f6feb5864461697f5872df220ba52 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 31 Mar 2017 18:36:57 +0200 Subject: [PATCH 51/68] Merge likeTyped and likeKinded into likeSpaced --- .../src/dotty/tools/dotc/core/NameOps.scala | 28 ++++++++----------- .../src/dotty/tools/dotc/core/Names.scala | 14 ++++++---- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index e74bf8ca7d6f..5a71c2bd234e 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -58,7 +58,7 @@ object NameOps { case _ => false } - def likeTyped(n: PreName): N = + def likeSpaced(n: PreName): N = (if (name.isTermName) n.toTermName else n.toTypeName).asInstanceOf[N] def isConstructorName = name == CONSTRUCTOR || name == TRAIT_CONSTRUCTOR @@ -99,14 +99,14 @@ object NameOps { * method needs to work on mangled as well as unmangled names because * it is also called from the backend. */ - def stripModuleClassSuffix: N = likeTyped { + def stripModuleClassSuffix: N = likeSpaced { val name1 = if (name.isSimple && name.endsWith("$")) name.unmangleClassName else name name.exclude(ModuleClassName) } /** If flags is a ModuleClass but not a Package, add module class suffix */ - def adjustIfModuleClass(flags: Flags.FlagSet): N = likeTyped { + def adjustIfModuleClass(flags: Flags.FlagSet): N = likeSpaced { if (flags is (ModuleClass, butNot = Package)) name.asTypeName.moduleClassName else name.toTermName.exclude(AvoidClashName) } @@ -114,24 +114,18 @@ object NameOps { def expandedName(base: Symbol, kind: QualifiedNameKind = ExpandedName)(implicit ctx: Context): N = { val prefix = if (base.name.is(ExpandedName)) base.name else base.fullNameSeparated(ExpandPrefixName) - likeTyped { kind(prefix.toTermName, name.toTermName) } + likeSpaced { kind(prefix.toTermName, name.toTermName) } } /** Revert the expanded name. */ - def unexpandedName: N = likeTyped { + def unexpandedName: N = likeSpaced { name.rewrite { case ExpandedName(_, unexp) => unexp } } - def implClassName: N = likeTyped(name ++ tpnme.IMPL_CLASS_SUFFIX) + def implClassName: N = likeSpaced(name ++ tpnme.IMPL_CLASS_SUFFIX) - def errorName: N = likeTyped(name ++ nme.ERROR) + def errorName: N = likeSpaced(name ++ nme.ERROR) - def directName: N = likeTyped(name ++ DIRECT_SUFFIX) - - def freshened(implicit ctx: Context): N = - likeTyped( - if (name.is(ModuleClassName)) name.stripModuleClassSuffix.freshened.moduleClassName - else likeTyped(ctx.freshName(name ++ NameTransformer.NAME_JOIN_STRING))) /* /** Name with variance prefix: `+` for covariant, `-` for contravariant */ def withVariance(v: Int): N = @@ -159,7 +153,7 @@ object NameOps { } */ - def freshened(implicit ctx: Context): N = likeTyped { + def freshened(implicit ctx: Context): N = likeSpaced { name.toTermName match { case ModuleClassName(original) => ModuleClassName(original.freshened) case name => UniqueName.fresh(name) @@ -241,7 +235,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.likeKinded(name ++ nme.specializedTypeNames.prefix ++ + name.likeSpaced(name ++ nme.specializedTypeNames.prefix ++ methodTags.fold(nme.EMPTY)(_ ++ _) ++ nme.specializedTypeNames.separator ++ classTags.fold(nme.EMPTY)(_ ++ _) ++ nme.specializedTypeNames.suffix) } @@ -252,11 +246,11 @@ object NameOps { def unmangleClassName: N = name.toTermName match { case name: SimpleTermName if name.endsWith(str.MODULE_SUFFIX) && !nme.falseModuleClassNames.contains(name) => - likeTyped(name.dropRight(str.MODULE_SUFFIX.length).moduleClassName) + likeSpaced(name.dropRight(str.MODULE_SUFFIX.length).moduleClassName) case _ => name } - def unmangle(kind: NameKind): N = likeTyped { + def unmangle(kind: NameKind): N = likeSpaced { name rewrite { case unmangled: SimpleTermName => kind.unmangle(unmangled) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 5b6315e663f5..56bdb162375c 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -71,8 +71,10 @@ object Names { 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 + /** A name in the same (term or type) namespace as this name and + * with same characters as given `name`. + */ + def likeSpaced(name: Name): ThisName def derived(info: NameInfo): ThisName def derived(kind: ClassifiedNameKind): ThisName = derived(kind.info) @@ -129,7 +131,7 @@ object Names { _typeName } - def likeKinded(name: Name): TermName = name.toTermName + def likeSpaced(name: Name): TermName = name.toTermName def info: NameInfo = SimpleTermNameKind.info def underlying: TermName = unsupported("underlying") @@ -264,7 +266,7 @@ object Names { def asSimpleName = this def toSimpleName = this def rewrite(f: PartialFunction[Name, Name]): ThisName = - if (f.isDefinedAt(this)) likeKinded(f(this)) else this + if (f.isDefinedAt(this)) likeSpaced(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) @@ -311,7 +313,7 @@ object Names { 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 + def likeSpaced(name: Name): TypeName = name.toTypeName def derived(info: NameInfo): TypeName = toTermName.derived(info).toTypeName def exclude(kind: NameKind): TypeName = toTermName.exclude(kind).toTypeName @@ -342,7 +344,7 @@ object Names { def toSimpleName = termName(toString) def rewrite(f: PartialFunction[Name, Name]): ThisName = - if (f.isDefinedAt(this)) likeKinded(f(this)) + if (f.isDefinedAt(this)) likeSpaced(f(this)) else info match { case qual: QualifiedInfo => this case _ => underlying.rewrite(f).derived(info) From a574ba6b70fc8a8dadf4ec493fcb5dc19d1fa478 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 31 Mar 2017 19:01:10 +0200 Subject: [PATCH 52/68] Further simplification for Name --- .../dotty/tools/dotc/core/Definitions.scala | 2 +- .../src/dotty/tools/dotc/core/NameOps.scala | 6 ++--- .../src/dotty/tools/dotc/core/Names.scala | 6 ++--- .../src/dotty/tools/dotc/core/StdNames.scala | 27 +++++-------------- .../tools/dotc/core/SymDenotations.scala | 6 ++--- .../core/unpickleScala2/Scala2Unpickler.scala | 2 +- .../test/dotty/tools/DottyTypeStealer.scala | 2 +- 7 files changed, 17 insertions(+), 34 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index a1858e93485a..d4d652d6ba4a 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -119,7 +119,7 @@ class Definitions { enterTypeParam(cls, name ++ "$T" ++ i.toString, Contravariant, decls) val resParam = enterTypeParam(cls, name ++ "$R", Covariant, decls) val (methodType, parentTraits) = - if (name.startsWith(str.ImplicitFunction)) { + if (name.firstPart.startsWith(str.ImplicitFunction)) { val superTrait = FunctionType(arity).appliedTo(argParams.map(_.typeRef) ::: resParam.typeRef :: Nil) (ImplicitMethodType, ctx.normalizeToClassRefs(superTrait :: Nil, cls, decls)) diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 5a71c2bd234e..ac4b296bb9c0 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -63,9 +63,9 @@ object NameOps { def isConstructorName = name == CONSTRUCTOR || name == TRAIT_CONSTRUCTOR def isStaticConstructorName = name == STATIC_CONSTRUCTOR - def isLocalDummyName = name startsWith LOCALDUMMY_PREFIX + def isLocalDummyName = name startsWith str.LOCALDUMMY_PREFIX def isReplWrapperName = name.toString contains str.INTERPRETER_IMPORT_WRAPPER - def isSetterName = name endsWith SETTER_SUFFIX + def isSetterName = name endsWith str.SETTER_SUFFIX def isScala2LocalSuffix = testSimple(_.endsWith(" ")) def isSelectorName = testSimple(n => n.startsWith("_") && n.drop(1).forall(_.isDigit)) @@ -275,7 +275,7 @@ object NameOps { def getterName: TermName = name.exclude(FieldName).mapLast(n => - if (n.endsWith(SETTER_SUFFIX)) n.take(n.length - str.SETTER_SUFFIX.length).asSimpleName + if (n.endsWith(str.SETTER_SUFFIX)) n.take(n.length - str.SETTER_SUFFIX.length).asSimpleName else n) def fieldName: TermName = diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 56bdb162375c..95cc2fef7173 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -101,11 +101,7 @@ object Names { def isEmpty: Boolean def startsWith(str: String): Boolean = firstPart.startsWith(str) - 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 hashCode = System.identityHashCode(this) override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] @@ -240,6 +236,8 @@ object Names { i } + def lastIndexOfSlice(str: String): Int = toString.lastIndexOfSlice(str) + override def replace(from: Char, to: Char): SimpleTermName = { val cs = new Array[Char](length) Array.copy(chrs, start, cs, 0, length) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index c942a058a815..815940eb0527 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -25,6 +25,9 @@ object StdNames { final val AVOID_CLASH_SUFFIX = "$_avoid_name_clash_$" final val MODULE_SUFFIX = NameTransformer.MODULE_SUFFIX_STRING final val DEFAULT_GETTER = "$default$" + final val LOCALDUMMY_PREFIX = "" + termName(str.LOCALDUMMY_PREFIX + clazz.name + ">") def newBitmapName(bitmapPrefix: TermName, n: Int): TermName = bitmapPrefix ++ n.toString diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 547fd2d913c2..1c72065333af 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -461,13 +461,13 @@ object SymDenotations { /** Is this symbol an anonymous class? */ final def isAnonymousClass(implicit ctx: Context): Boolean = - isClass && (initial.name startsWith tpnme.ANON_CLASS) + isClass && (initial.name startsWith str.ANON_CLASS) final def isAnonymousFunction(implicit ctx: Context) = - this.symbol.is(Method) && (initial.name startsWith nme.ANON_FUN) + this.symbol.is(Method) && (initial.name startsWith str.ANON_FUN) final def isAnonymousModuleVal(implicit ctx: Context) = - this.symbol.is(ModuleVal) && (initial.name startsWith nme.ANON_CLASS) + this.symbol.is(ModuleVal) && (initial.name startsWith str.ANON_CLASS) /** Is this a companion class method or companion object method? * These methods are generated by Symbols#synthesizeCompanionMethod diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 608c77a8e0af..5871ec46c259 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -1036,7 +1036,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas val rhs = readTreeRef() val params = until(end, readIdentRef) val ldef = DefDef(symbol.asTerm, rhs) - def isCaseLabel(sym: Symbol) = sym.name.startsWith(nme.CASEkw) + def isCaseLabel(sym: Symbol) = sym.name.startsWith(nme.CASEkw.toString) if (isCaseLabel(symbol)) ldef else Block(ldef :: Nil, Apply(Ident(symbol.termRef), Nil)) diff --git a/compiler/test/dotty/tools/DottyTypeStealer.scala b/compiler/test/dotty/tools/DottyTypeStealer.scala index ff6e67e41614..727cd9e7da19 100644 --- a/compiler/test/dotty/tools/DottyTypeStealer.scala +++ b/compiler/test/dotty/tools/DottyTypeStealer.scala @@ -19,7 +19,7 @@ object DottyTypeStealer extends DottyTest { implicit val ctx = context val findValDef: (List[ValDef], tpd.Tree) => List[ValDef] = (acc , tree) => { tree match { - case t: ValDef if t.name.startsWith(dummyName.toTermName) => t :: acc + case t: ValDef if t.name.startsWith(dummyName) => t :: acc case _ => acc } } From c646883fbe6c2fffaa8f64d64e46bc85b58def25 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 1 Apr 2017 10:04:17 +0200 Subject: [PATCH 53/68] Bugfix in stripModuleClassSuffix --- compiler/src/dotty/tools/dotc/core/NameOps.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index ac4b296bb9c0..27bd3a05e954 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -100,9 +100,9 @@ object NameOps { * it is also called from the backend. */ def stripModuleClassSuffix: N = likeSpaced { - val name1 = + val semName = if (name.isSimple && name.endsWith("$")) name.unmangleClassName else name - name.exclude(ModuleClassName) + semName.exclude(ModuleClassName) } /** If flags is a ModuleClass but not a Package, add module class suffix */ From 9f7012e886aa13f22e6ffc417050f9f6fc5b8003 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 1 Apr 2017 11:32:03 +0200 Subject: [PATCH 54/68] Memoize toSimpleName toSimpleName is called a lot from the backend, so it makes sense to memoize it. It would be even better to communicate with the backend using strings, because then we would not have to enter all these simple names in the name table. --- compiler/src/dotty/tools/dotc/core/Names.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 95cc2fef7173..352fa6b6b5f1 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -339,7 +339,12 @@ object Names { def isSimple = false def asSimpleName = throw new UnsupportedOperationException(s"$debugString is not a simple name") - def toSimpleName = termName(toString) + + private var simpleName: SimpleTermName = null + def toSimpleName = { + if (simpleName == null) simpleName = termName(toString) + simpleName + } def rewrite(f: PartialFunction[Name, Name]): ThisName = if (f.isDefinedAt(this)) likeSpaced(f(this)) From b2bd0bf7d3df3b4c418e411290c2a2b18321aabf Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 1 Apr 2017 11:58:25 +0200 Subject: [PATCH 55/68] Don't unmangle names in ClassfileParser Classfile parsing is about JVM-level names, not Scala level ones. So it is more consistent to use mangled names throughout. --- .../dotc/core/classfile/ClassfileParser.scala | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 98ac5253355a..13934f237535 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -247,22 +247,21 @@ class ClassfileParser( final def objToAny(tp: Type)(implicit ctx: Context) = if (tp.isDirectRef(defn.ObjectClass) && !ctx.phase.erasedTypes) defn.AnyType else tp - private def sigToType(signature: TermName, owner: Symbol = null)(implicit ctx: Context): Type = { - val sig = signature.toSimpleName + private def sigToType(sig: SimpleTermName, owner: Symbol = null)(implicit ctx: Context): Type = { var index = 0 val end = sig.length def accept(ch: Char): Unit = { assert(sig(index) == ch, (sig(index), ch)) index += 1 } - def subName(isDelimiter: Char => Boolean): TermName = { + def subName(isDelimiter: Char => Boolean): SimpleTermName = { val start = index while (!isDelimiter(sig(index))) { index += 1 } - sig.slice(start, index).asTermName + sig.slice(start, index) } // Warning: sigToType contains nested completers which might be forced in a later run! // So local methods need their own ctx parameters. - def sig2type(tparams: immutable.Map[Name,Symbol], skiptvs: Boolean)(implicit ctx: Context): Type = { + def sig2type(tparams: immutable.Map[Name, Symbol], skiptvs: Boolean)(implicit ctx: Context): Type = { val tag = sig(index); index += 1 (tag: @switch) match { case BYTE_TAG => defn.ByteType @@ -895,7 +894,7 @@ class ClassfileParser( private val len = in.nextChar private val starts = new Array[Int](len) private val values = new Array[AnyRef](len) - private val internalized = new Array[TermName](len) + private val internalized = new Array[SimpleTermName](len) { var i = 1 while (i < starts.length) { @@ -922,12 +921,12 @@ class ClassfileParser( } /** Return the name found at given index. */ - def getName(index: Int): TermName = { + def getName(index: Int): SimpleTermName = { if (index <= 0 || len <= index) errorBadIndex(index) values(index) match { - case name: TermName => name + case name: SimpleTermName => name case null => val start = starts(index) if (in.buf(start).toInt != CONSTANT_UTF8) errorBadTag(start) @@ -938,12 +937,12 @@ class ClassfileParser( } /** Return the name found at given index in the constant pool, with '/' replaced by '.'. */ - def getExternalName(index: Int): TermName = { + def getExternalName(index: Int): SimpleTermName = { if (index <= 0 || len <= index) errorBadIndex(index) if (internalized(index) == null) - internalized(index) = getName(index).replace('/', '.').unmangleClassName + internalized(index) = getName(index).replace('/', '.') internalized(index) } @@ -955,9 +954,9 @@ class ClassfileParser( val start = starts(index) if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start) val name = getExternalName(in.getChar(start + 1)) - if (name.is(ModuleClassName) && (name ne nme.nothingRuntimeClass) && (name ne nme.nullRuntimeClass)) + if (name.endsWith("$") && (name ne nme.nothingRuntimeClass) && (name ne nme.nullRuntimeClass)) // Null$ and Nothing$ ARE classes - c = ctx.requiredModule(name.sourceModuleName) + c = ctx.requiredModule(name.dropRight(1)) else c = classNameToSymbol(name) values(index) = c } @@ -967,7 +966,7 @@ class ClassfileParser( /** Return the external name of the class info structure found at 'index'. * Use 'getClassSymbol' if the class is sure to be a top-level class. */ - def getClassName(index: Int): TermName = { + def getClassName(index: Int): SimpleTermName = { val start = starts(index) if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start) getExternalName(in.getChar(start + 1)) From e2fb134fd3a49848ea49a6db42a298276c08b110 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 1 Apr 2017 13:31:07 +0200 Subject: [PATCH 56/68] Simplify classfile parser "own name" checking Simplifies the test that the class represented by a classfile is the class logically referenced by the file. The simplification is needed if we want to populate package scopes with unmangled classnames. --- .../dotc/core/classfile/ClassfileParser.scala | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 13934f237535..27afa4d09399 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -39,7 +39,7 @@ class ClassfileParser( protected val staticScope: MutableScope = newScope // the scope of all static definitions protected var pool: ConstantPool = _ // the classfile's constant pool - protected var currentClassName: Name = _ // JVM name of the current class + protected var currentClassName: SimpleTermName = _ // JVM name of the current class protected var classTParams = Map[Name,Symbol]() classRoot.info = (new NoCompleter).withDecls(instanceScope) @@ -47,8 +47,8 @@ class ClassfileParser( private def currentIsTopLevel(implicit ctx: Context) = classRoot.owner is Flags.PackageClass - private def mismatchError(c: Symbol) = - throw new IOException(s"class file '${in.file}' has location not matching its contents: contains $c") + private def mismatchError(className: SimpleTermName) = + throw new IOException(s"class file '${in.file}' has location not matching its contents: contains class $className") def run()(implicit ctx: Context): Option[Embedded] = try { ctx.debuglog("[class] >> " + classRoot.fullName) @@ -92,15 +92,8 @@ class ClassfileParser( val nameIdx = in.nextChar currentClassName = pool.getClassName(nameIdx) - if (currentIsTopLevel) { - val c = pool.getClassSymbol(nameIdx) - if (c != classRoot.symbol) { - println(currentClassName.debugString) // TODO: remove - println(c.name.debugString) - println(classRoot.symbol.name.debugString) - mismatchError(c) - } - } + if (currentIsTopLevel && currentClassName != classRoot.fullName.toSimpleName) + mismatchError(currentClassName) addEnclosingTParams() From e4780e574f9613346e6908f7947f40a58327e376 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 1 Apr 2017 17:21:39 +0200 Subject: [PATCH 57/68] Keep package member names mangled Once we start using unencoded operators internally, we will face the problem that one cannot decode realiably a class file filename. We therefore turn things around, keeping members of package scopes in mangled and encoded form. This is compensated by (1) mangling names for lookup of such members and (2) when unpickling from Scala 2 info or Tasty, comparing mangled names when matching a read class or module object against a root. --- .../src/dotty/tools/dotc/core/Denotations.scala | 2 +- compiler/src/dotty/tools/dotc/core/Scopes.scala | 10 +++++++++- .../src/dotty/tools/dotc/core/SymDenotations.scala | 13 ++++++++++--- .../src/dotty/tools/dotc/core/SymbolLoaders.scala | 4 ++-- .../dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 4 +++- .../dotc/core/unpickleScala2/Scala2Unpickler.scala | 9 ++++++--- 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index fca77fc066d7..fd42bde3660f 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -1207,7 +1207,7 @@ object Denotations { } recurSimple(path.length, wrap) } - recur(path.unmangleClassName) + recur(path) } /** If we are looking for a non-existing term name in a package, diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala index 6090079e54ba..032442421735 100644 --- a/compiler/src/dotty/tools/dotc/core/Scopes.scala +++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala @@ -394,6 +394,14 @@ object Scopes { } } + class PackageScope extends MutableScope { + override final def newScopeEntry(name: Name, sym: Symbol)(implicit ctx: Context): ScopeEntry = + super.newScopeEntry(name.toSimpleName, sym) + + override final def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = + super.lookupEntry(name.toSimpleName) + } + /** Create a new scope */ def newScope: MutableScope = new MutableScope() @@ -408,7 +416,7 @@ object Scopes { } /** Create new scope for the members of package `pkg` */ - def newPackageScope(pkgClass: Symbol): MutableScope = newScope + def newPackageScope(pkgClass: Symbol): MutableScope = new PackageScope() /** Transform scope of members of `owner` using operation `op` * This is overridden by the reflective compiler to avoid creating new scopes for packages diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 1c72065333af..b8cd7bb1800f 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -107,7 +107,7 @@ object SymDenotations { class SymDenotation private[SymDenotations] ( symbol: Symbol, ownerIfExists: Symbol, - final val name: Name, + initName: Name, initFlags: FlagSet, initInfo: Type, initPrivateWithin: Symbol = NoSymbol) extends SingleDenotation(symbol) { @@ -125,11 +125,18 @@ object SymDenotations { // ------ Getting and setting fields ----------------------------- + private[this] var myName = initName private[this] var myFlags: FlagSet = adaptFlags(initFlags) private[this] var myInfo: Type = initInfo private[this] var myPrivateWithin: Symbol = initPrivateWithin private[this] var myAnnotations: List[Annotation] = Nil + /** The name of the symbol */ + def name = myName + + /** Update the name; only called when unpickling top-level classes */ + def name_=(n: Name) = myName = n + /** The owner of the symbol; overridden in NoDenotation */ def owner: Symbol = ownerIfExists @@ -1208,12 +1215,12 @@ object SymDenotations { class ClassDenotation private[SymDenotations] ( symbol: Symbol, ownerIfExists: Symbol, - name: Name, + initName: Name, initFlags: FlagSet, initInfo: Type, initPrivateWithin: Symbol, initRunId: RunId) - extends SymDenotation(symbol, ownerIfExists, name, initFlags, initInfo, initPrivateWithin) { + extends SymDenotation(symbol, ownerIfExists, initName, initFlags, initInfo, initPrivateWithin) { import util.LRUCache diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 0ea643e0d9a5..75deb8bb5ad0 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -39,7 +39,7 @@ class SymbolLoaders { def enterClass( owner: Symbol, name: PreName, completer: SymbolLoader, flags: FlagSet = EmptyFlags, scope: Scope = EmptyScope)(implicit ctx: Context): Symbol = { - val cls = ctx.newClassSymbol(owner, name.toTypeName.unmangleClassName, flags, completer, assocFile = completer.sourceFileOrNull) + val cls = ctx.newClassSymbol(owner, name.toTypeName, flags, completer, assocFile = completer.sourceFileOrNull) enterNew(owner, cls, completer, scope) } @@ -163,7 +163,7 @@ class SymbolLoaders { initializeFromClassPath(root.symbol, classRep) for (classRep <- classpath.classes) if (maybeModuleClass(classRep) && - !root.unforcedDecls.lookup(classRep.name.toTypeName.unmangleClassName).exists) + !root.unforcedDecls.lookup(classRep.name.toTypeName).exists) initializeFromClassPath(root.symbol, classRep) } if (!root.isEmptyPackage) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 96bf29a7081e..81519727cea8 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -416,6 +416,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val tag = readByte() val end = readEnd() var name: Name = readName() + val sname = name.toSimpleName if (tag == TYPEDEF || tag == TYPEPARAM) name = name.toTypeName skipParams() val ttag = nextUnsharedTag @@ -432,9 +433,10 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi def adjustIfModule(completer: LazyType) = if (flags is Module) ctx.adjustModuleCompleter(completer, name) else completer val sym = - roots.find(root => (root.owner eq ctx.owner) && root.name == name) match { + roots.find(root => (root.owner eq ctx.owner) && root.name.toSimpleName == sname && root.isType == name.isTypeName) match { case Some(rootd) => pickling.println(i"overwriting ${rootd.symbol} # ${rootd.hashCode}") + rootd.name = name rootd.info = adjustIfModule( new Completer(ctx.owner, subReader(start, end)) with SymbolLoaders.SecondCompleter) rootd.flags = flags &~ Touched // allow one more completion diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 5871ec46c259..1e8fbe54b41f 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -448,15 +448,18 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas flags = flags &~ Scala2SuperAccessor } - def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass) - def isModuleClassRoot = (name == moduleClassRoot.name) && (owner == moduleClassRoot.owner) && (flags is Module) - def isModuleRoot = (name == moduleClassRoot.name.sourceModuleName) && (owner == moduleClassRoot.owner) && (flags is Module) + val sname = name.toSimpleName + def nameMatches(rootName: Name) = sname == rootName.toSimpleName + def isClassRoot = nameMatches(classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass) + def isModuleClassRoot = nameMatches(moduleClassRoot.name) && (owner == moduleClassRoot.owner) && (flags is Module) + def isModuleRoot = nameMatches(moduleClassRoot.name.sourceModuleName) && (owner == moduleClassRoot.owner) && (flags is Module) //if (isClassRoot) println(s"classRoot of $classRoot found at $readIndex, flags = $flags") // !!! DEBUG //if (isModuleRoot) println(s"moduleRoot of $moduleRoot found at $readIndex, flags = $flags") // !!! DEBUG //if (isModuleClassRoot) println(s"moduleClassRoot of $moduleClassRoot found at $readIndex, flags = $flags") // !!! DEBUG def completeRoot(denot: ClassDenotation, completer: LazyType): Symbol = { + denot.name = name denot.setFlag(flags) denot.resetFlag(Touched) // allow one more completion denot.info = completer From 2bfb2ca70c4588de00c12feba79ef7c0d68361a5 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 1 Apr 2017 18:51:11 +0200 Subject: [PATCH 58/68] Introduce mangled method Mangled is like toSimpleName, except that it keeps the term/type distinction. --- compiler/src/dotty/tools/dotc/core/Names.scala | 7 +++++++ compiler/src/dotty/tools/dotc/core/Scopes.scala | 4 ++-- .../src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 4 ++-- .../tools/dotc/core/unpickleScala2/Scala2Unpickler.scala | 4 ++-- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 352fa6b6b5f1..6caba33ecbb9 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -66,6 +66,8 @@ object Names { def isSimple: Boolean def asSimpleName: SimpleTermName def toSimpleName: SimpleTermName + def mangled: Name + def rewrite(f: PartialFunction[Name, Name]): ThisName def collect[T](f: PartialFunction[Name, T]): Option[T] def mapLast(f: SimpleTermName => SimpleTermName): ThisName @@ -263,6 +265,8 @@ object Names { def isSimple = true def asSimpleName = this def toSimpleName = this + def mangled = this + def rewrite(f: PartialFunction[Name, Name]): ThisName = if (f.isDefinedAt(this)) likeSpaced(f(this)) else this def collect[T](f: PartialFunction[Name, T]): Option[T] = f.lift(this) @@ -306,6 +310,8 @@ object Names { def isSimple = toTermName.isSimple def asSimpleName = toTermName.asSimpleName def toSimpleName = toTermName.toSimpleName + def mangled = toTermName.toSimpleName.toTypeName + 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 @@ -345,6 +351,7 @@ object Names { if (simpleName == null) simpleName = termName(toString) simpleName } + def mangled = toSimpleName def rewrite(f: PartialFunction[Name, Name]): ThisName = if (f.isDefinedAt(this)) likeSpaced(f(this)) diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala index 032442421735..023fe35c58fa 100644 --- a/compiler/src/dotty/tools/dotc/core/Scopes.scala +++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala @@ -396,10 +396,10 @@ object Scopes { class PackageScope extends MutableScope { override final def newScopeEntry(name: Name, sym: Symbol)(implicit ctx: Context): ScopeEntry = - super.newScopeEntry(name.toSimpleName, sym) + super.newScopeEntry(name.mangled, sym) override final def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = - super.lookupEntry(name.toSimpleName) + super.lookupEntry(name.mangled) } /** Create a new scope */ diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 81519727cea8..7d08c958c24b 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -416,7 +416,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val tag = readByte() val end = readEnd() var name: Name = readName() - val sname = name.toSimpleName + val mname = name.mangled if (tag == TYPEDEF || tag == TYPEPARAM) name = name.toTypeName skipParams() val ttag = nextUnsharedTag @@ -433,7 +433,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi def adjustIfModule(completer: LazyType) = if (flags is Module) ctx.adjustModuleCompleter(completer, name) else completer val sym = - roots.find(root => (root.owner eq ctx.owner) && root.name.toSimpleName == sname && root.isType == name.isTypeName) match { + roots.find(root => (root.owner eq ctx.owner) && root.name.mangled == mname) match { case Some(rootd) => pickling.println(i"overwriting ${rootd.symbol} # ${rootd.hashCode}") rootd.name = name diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 1e8fbe54b41f..f3bb99b27dcc 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -448,8 +448,8 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas flags = flags &~ Scala2SuperAccessor } - val sname = name.toSimpleName - def nameMatches(rootName: Name) = sname == rootName.toSimpleName + val mname = name.mangled + def nameMatches(rootName: Name) = mname == rootName.mangled def isClassRoot = nameMatches(classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass) def isModuleClassRoot = nameMatches(moduleClassRoot.name) && (owner == moduleClassRoot.owner) && (flags is Module) def isModuleRoot = nameMatches(moduleClassRoot.name.sourceModuleName) && (owner == moduleClassRoot.owner) && (flags is Module) From bd992dd3158f192fd391605a6b51e1c23e09171d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 1 Apr 2017 19:28:42 +0200 Subject: [PATCH 59/68] Fix and activate package scopes Prevviously they were actually unused. --- .../dotty/tools/dotc/core/Definitions.scala | 2 +- .../src/dotty/tools/dotc/core/Scopes.scala | 42 ++++++++++++++----- .../src/dotty/tools/dotc/core/StdNames.scala | 1 - .../dotty/tools/dotc/core/SymbolLoaders.scala | 2 +- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index d4d652d6ba4a..8925724fd1cf 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -938,7 +938,7 @@ class Definitions { private def makeScalaSpecial()(implicit ctx: Context) = { val oldInfo = ScalaPackageClass.classInfo val oldDecls = oldInfo.decls - val newDecls = new MutableScope(oldDecls) { + val newDecls = new PackageScope(oldDecls) { override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { val res = super.lookupEntry(name) if (res == null && name.isTypeName && name.isSyntheticFunction) diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala index 023fe35c58fa..9e6be7651f09 100644 --- a/compiler/src/dotty/tools/dotc/core/Scopes.scala +++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala @@ -144,6 +144,11 @@ object Scopes { final def toText(printer: Printer): Text = printer.toText(this) def checkConsistent()(implicit ctx: Context) = () + + /** Hook for transforming a name before it is used in a lookup or creation. + * Used to mangle names in package scopes. + */ + protected def normalize(name: Name): Name = name } /** A subclass of Scope that defines methods for entering and @@ -155,6 +160,7 @@ object Scopes { class MutableScope protected[Scopes](initElems: ScopeEntry, initSize: Int, val nestingLevel: Int = 0) extends Scope { + /** Scope shares elements with `base` */ protected[Scopes] def this(base: Scope)(implicit ctx: Context) = { this(base.lastEntry, base.size, base.nestingLevel + 1) ensureCapacity(MinHash)(ctx) // WTH? it seems the implicit is not in scope for a secondary constructor call. @@ -178,6 +184,8 @@ object Scopes { */ private var elemsCache: List[Symbol] = null + protected def newScopeLikeThis() = new MutableScope() + /** Clone scope, taking care not to force the denotations of any symbols in the scope. */ def cloneScope(implicit ctx: Context): MutableScope = { @@ -187,7 +195,7 @@ object Scopes { entries += e e = e.prev } - val scope = newScope + val scope = newScopeLikeThis() for (i <- entries.length - 1 to 0 by -1) { val e = entries(i) scope.newScopeEntry(e.name, e.sym) @@ -198,7 +206,7 @@ object Scopes { /** create and enter a scope entry with given name and symbol */ protected def newScopeEntry(name: Name, sym: Symbol)(implicit ctx: Context): ScopeEntry = { ensureCapacity(if (hashTable ne null) hashTable.length else MinHash) - val e = new ScopeEntry(name, sym, this) + val e = new ScopeEntry(normalize(name), sym, this) e.prev = lastEntry lastEntry = e if (hashTable ne null) enterInHash(e) @@ -234,7 +242,7 @@ object Scopes { enter(sym) } - private def ensureCapacity(tableSize: Int)(implicit ctx: Context): Unit = + protected def ensureCapacity(tableSize: Int)(implicit ctx: Context): Unit = if (size >= tableSize * FillFactor) createHash(tableSize * 2) private def createHash(tableSize: Int)(implicit ctx: Context): Unit = @@ -310,15 +318,16 @@ object Scopes { /** Lookup a symbol entry matching given name. */ override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { + val normalized = normalize(name) var e: ScopeEntry = null if (hashTable ne null) { - e = hashTable(name.hashCode & (hashTable.length - 1)) - while ((e ne null) && e.name != name) { + e = hashTable(normalized.hashCode & (hashTable.length - 1)) + while ((e ne null) && e.name != normalized) { e = e.tail } } else { e = lastEntry - while ((e ne null) && e.name != name) { + while ((e ne null) && e.name != normalized) { e = e.prev } } @@ -394,12 +403,23 @@ object Scopes { } } - class PackageScope extends MutableScope { - override final def newScopeEntry(name: Name, sym: Symbol)(implicit ctx: Context): ScopeEntry = - super.newScopeEntry(name.mangled, sym) + /** The scope of a package. This is different from a normal scope + * in that names of scope entries are kept in mangled form. + */ + class PackageScope protected[Scopes](initElems: ScopeEntry, initSize: Int, nestingLevel: Int) + extends MutableScope(initElems, initSize, nestingLevel) { + + /** Scope shares elements with `base` */ + def this(base: Scope)(implicit ctx: Context) = { + this(base.lastEntry, base.size, base.nestingLevel + 1) + ensureCapacity(MinHash)(ctx) // WTH? it seems the implicit is not in scope for a secondary constructor call. + } + + def this() = this(null, 0, 0) + + override def newScopeLikeThis() = new PackageScope() - override final def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = - super.lookupEntry(name.mangled) + override protected def normalize(name: Name) = name.mangled } /** Create a new scope */ diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 815940eb0527..9272c32ed70d 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -454,7 +454,6 @@ object StdNames { val ne: N = "ne" val newFreeTerm: N = "newFreeTerm" val newFreeType: N = "newFreeType" - val newNestedSymbol: N = "newNestedSymbol" val newScopeWith: N = "newScopeWith" val next: N = "next" val nmeNewTermName: N = "newTermName" diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 75deb8bb5ad0..ad0d02fa8796 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -148,7 +148,7 @@ class SymbolLoaders { override def sourceModule(implicit ctx: Context) = _sourceModule def description = "package loader " + classpath.name - private[core] val currentDecls: MutableScope = newScope + private[core] val currentDecls: MutableScope = new PackageScope() def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = { assert(root is PackageClass, root) From a7ee8dc999f415dbbed9c4e60bf4ade1cf8a94eb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 1 Apr 2017 20:14:19 +0200 Subject: [PATCH 60/68] Avoid setter in Name and fix a bug in TreeUnpickler --- compiler/src/dotty/tools/dotc/core/Names.scala | 2 +- compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 6caba33ecbb9..cef55a4828dc 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -346,7 +346,7 @@ object Names { def isSimple = false def asSimpleName = throw new UnsupportedOperationException(s"$debugString is not a simple name") - private var simpleName: SimpleTermName = null + private[this] var simpleName: SimpleTermName = null def toSimpleName = { if (simpleName == null) simpleName = termName(toString) simpleName diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 7d08c958c24b..2908c541e5e9 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -416,8 +416,8 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val tag = readByte() val end = readEnd() var name: Name = readName() - val mname = name.mangled if (tag == TYPEDEF || tag == TYPEPARAM) name = name.toTypeName + val mname = name.mangled skipParams() val ttag = nextUnsharedTag val isAbsType = isAbstractType(ttag) From 264211f6b7129923c01c2e3c402b157685d64b1f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 2 Apr 2017 11:43:03 +0200 Subject: [PATCH 61/68] Scope refactoring Since we now have separate package-scopes, it's easier to have them take into account the special role played by the scala package. So we can drop the funky logic of `makeScalaSpecial`. --- .../dotty/tools/dotc/core/Definitions.scala | 21 +-------- .../src/dotty/tools/dotc/core/Scopes.scala | 44 ++++--------------- .../dotty/tools/dotc/core/SymbolLoaders.scala | 22 ++++++++++ 3 files changed, 31 insertions(+), 56 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 8925724fd1cf..c7b1538c78c6 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -108,7 +108,7 @@ class Definitions { * def apply(implicit $x0: T0, ..., $x{N_1}: T{N-1}): R * } */ - private def newFunctionNTrait(name: TypeName) = { + def newFunctionNTrait(name: TypeName) = { val completer = new LazyType { def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { val cls = denot.asClass.classSymbol @@ -932,23 +932,6 @@ class Definitions { // ----- Initialization --------------------------------------------------- - /** Give the scala package a scope where a FunctionN trait is automatically - * added when someone looks for it. - */ - private def makeScalaSpecial()(implicit ctx: Context) = { - val oldInfo = ScalaPackageClass.classInfo - val oldDecls = oldInfo.decls - val newDecls = new PackageScope(oldDecls) { - override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { - val res = super.lookupEntry(name) - if (res == null && name.isTypeName && name.isSyntheticFunction) - newScopeEntry(newFunctionNTrait(name.asTypeName)) - else res - } - } - ScalaPackageClass.info = oldInfo.derivedClassInfo(decls = newDecls) - } - /** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */ lazy val syntheticScalaClasses = List( AnyClass, @@ -976,8 +959,6 @@ class Definitions { def init()(implicit ctx: Context) = { this.ctx = ctx if (!_isInitialized) { - makeScalaSpecial() - // force initialization of every symbol that is synthesized or hijacked by the compiler val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses() diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala index 9e6be7651f09..c256e7071db4 100644 --- a/compiler/src/dotty/tools/dotc/core/Scopes.scala +++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala @@ -32,7 +32,7 @@ object Scopes { * This value must be a power of two, so that the index of an element can * be computed as element.hashCode & (hashTable.length - 1) */ - private final val MinHash = 8 + final val MinHashedScopeSize = 8 /** The maximal permissible number of recursions when creating * a hashtable @@ -144,11 +144,6 @@ object Scopes { final def toText(printer: Printer): Text = printer.toText(this) def checkConsistent()(implicit ctx: Context) = () - - /** Hook for transforming a name before it is used in a lookup or creation. - * Used to mangle names in package scopes. - */ - protected def normalize(name: Name): Name = name } /** A subclass of Scope that defines methods for entering and @@ -163,7 +158,7 @@ object Scopes { /** Scope shares elements with `base` */ protected[Scopes] def this(base: Scope)(implicit ctx: Context) = { this(base.lastEntry, base.size, base.nestingLevel + 1) - ensureCapacity(MinHash)(ctx) // WTH? it seems the implicit is not in scope for a secondary constructor call. + ensureCapacity(MinHashedScopeSize)(ctx) // WTH? it seems the implicit is not in scope for a secondary constructor call. } def this() = this(null, 0, 0) @@ -205,8 +200,8 @@ object Scopes { /** create and enter a scope entry with given name and symbol */ protected def newScopeEntry(name: Name, sym: Symbol)(implicit ctx: Context): ScopeEntry = { - ensureCapacity(if (hashTable ne null) hashTable.length else MinHash) - val e = new ScopeEntry(normalize(name), sym, this) + ensureCapacity(if (hashTable ne null) hashTable.length else MinHashedScopeSize) + val e = new ScopeEntry(name, sym, this) e.prev = lastEntry lastEntry = e if (hashTable ne null) enterInHash(e) @@ -242,7 +237,7 @@ object Scopes { enter(sym) } - protected def ensureCapacity(tableSize: Int)(implicit ctx: Context): Unit = + private def ensureCapacity(tableSize: Int)(implicit ctx: Context): Unit = if (size >= tableSize * FillFactor) createHash(tableSize * 2) private def createHash(tableSize: Int)(implicit ctx: Context): Unit = @@ -318,16 +313,15 @@ object Scopes { /** Lookup a symbol entry matching given name. */ override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { - val normalized = normalize(name) var e: ScopeEntry = null if (hashTable ne null) { - e = hashTable(normalized.hashCode & (hashTable.length - 1)) - while ((e ne null) && e.name != normalized) { + e = hashTable(name.hashCode & (hashTable.length - 1)) + while ((e ne null) && e.name != name) { e = e.tail } } else { e = lastEntry - while ((e ne null) && e.name != normalized) { + while ((e ne null) && e.name != name) { e = e.prev } } @@ -403,25 +397,6 @@ object Scopes { } } - /** The scope of a package. This is different from a normal scope - * in that names of scope entries are kept in mangled form. - */ - class PackageScope protected[Scopes](initElems: ScopeEntry, initSize: Int, nestingLevel: Int) - extends MutableScope(initElems, initSize, nestingLevel) { - - /** Scope shares elements with `base` */ - def this(base: Scope)(implicit ctx: Context) = { - this(base.lastEntry, base.size, base.nestingLevel + 1) - ensureCapacity(MinHash)(ctx) // WTH? it seems the implicit is not in scope for a secondary constructor call. - } - - def this() = this(null, 0, 0) - - override def newScopeLikeThis() = new PackageScope() - - override protected def normalize(name: Name) = name.mangled - } - /** Create a new scope */ def newScope: MutableScope = new MutableScope() @@ -435,9 +410,6 @@ object Scopes { scope } - /** Create new scope for the members of package `pkg` */ - def newPackageScope(pkgClass: Symbol): MutableScope = new PackageScope() - /** Transform scope of members of `owner` using operation `op` * This is overridden by the reflective compiler to avoid creating new scopes for packages */ diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index ad0d02fa8796..168908cedd63 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -148,6 +148,28 @@ class SymbolLoaders { override def sourceModule(implicit ctx: Context) = _sourceModule def description = "package loader " + classpath.name + /** The scope of a package. This is different from a normal scope + * in three aspects: + * + * 1. Names of scope entries are kept in mangled form. + * 2. Some function types in the `scala` package are synthesized. + */ + final class PackageScope extends MutableScope { + override def newScopeEntry(name: Name, sym: Symbol)(implicit ctx: Context): ScopeEntry = + super.newScopeEntry(name.mangled, sym) + + override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { + val e = super.lookupEntry(name.mangled) + if (e == null && + _sourceModule.name == nme.scala_ && _sourceModule == defn.ScalaPackageVal && + name.isTypeName && name.isSyntheticFunction) + newScopeEntry(defn.newFunctionNTrait(name.asTypeName)) + else e + } + + override def newScopeLikeThis() = new PackageScope + } + private[core] val currentDecls: MutableScope = new PackageScope() def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = { From d0efabf2817468c248db8a2a6d5a6c0b58747867 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 2 Apr 2017 19:11:34 +0200 Subject: [PATCH 62/68] Lazy entering of names with internal $'s in package scopes Names with internal $'s are entered in package scopes only if - we look for a name with internal $'s. - we want to know all the members of a package scope This optimization seems to be fairly effective. The typical range of package scopes that need $-names is between 0 and 20%. The optimization seems to improve execution time of all unit tests by about 3%. Also. drop the inheritance from Iterable to Scope. The reason is that we now need a context parameter for toList and other Iterable operations which makes them impossible to fit into the Iterable framework. --- .../backend/jvm/DottyBackendInterface.scala | 2 +- .../src/dotty/tools/dotc/core/Contexts.scala | 2 +- .../src/dotty/tools/dotc/core/Scopes.scala | 59 ++++++++++------ .../tools/dotc/core/SymDenotations.scala | 21 +++--- .../dotty/tools/dotc/core/SymbolLoaders.scala | 68 ++++++++++++++----- .../core/unpickleScala2/Scala2Unpickler.scala | 2 +- .../dotc/reporting/diagnostic/messages.scala | 2 +- .../src/dotty/tools/dotc/sbt/ExtractAPI.scala | 4 +- .../tools/dotc/transform/ExplicitOuter.scala | 2 +- .../dotc/transform/PrimitiveForwarders.scala | 2 +- .../tools/dotc/transform/TreeChecker.scala | 4 +- .../tools/dotc/transform/ValueClasses.scala | 7 +- .../dotty/tools/dotc/typer/TypeAssigner.scala | 4 +- 13 files changed, 113 insertions(+), 66 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index a300857ecd79..8e054c9c2dd5 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -794,7 +794,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def memberInfo(s: Symbol): Type = tp.memberInfo(s) - def decls: List[Symbol] = tp.decls.map(_.symbol).toList + def decls: List[Symbol] = tp.decls.toList def members: List[Symbol] = tp.memberDenots(takeAllFilter, (name, buf) => buf ++= tp.member(name).alternatives).map(_.symbol).toList diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index c80ad876a6ab..b299de4340c3 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -294,7 +294,7 @@ object Contexts { /** Is this a context that introduces a non-empty scope? */ def isNonEmptyScopeContext: Boolean = - (this.scope ne outer.scope) && this.scope.nonEmpty + (this.scope ne outer.scope) && !this.scope.isEmpty /** Leave message in diagnostics buffer if it exists */ def diagnose(str: => String) = diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala index c256e7071db4..205798474c80 100644 --- a/compiler/src/dotty/tools/dotc/core/Scopes.scala +++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala @@ -60,7 +60,7 @@ object Scopes { * or to delete them. These methods are provided by subclass * MutableScope. */ - abstract class Scope extends DotClass with printing.Showable with Iterable[Symbol] { + abstract class Scope extends DotClass with printing.Showable { /** The last scope-entry from which all others are reachable via `prev` */ private[dotc] def lastEntry: ScopeEntry @@ -76,18 +76,37 @@ object Scopes { /** The symbols in this scope in the order they were entered; * inherited from outer ones first. */ - def toList: List[Symbol] + def toList(implicit ctx: Context): List[Symbol] /** Return all symbols as an iterator in the order they were entered in this scope. */ - def iterator: Iterator[Symbol] = toList.iterator + def iterator(implicit ctx: Context): Iterator[Symbol] = toList.iterator + + /** Is the scope empty? */ + def isEmpty: Boolean = lastEntry eq null + + def foreach[U](p: Symbol => U)(implicit ctx: Context): Unit = toList foreach p + + def filter(p: Symbol => Boolean)(implicit ctx: Context): List[Symbol] = { + ensureComplete() + var syms: List[Symbol] = Nil + var e = lastEntry + while ((e ne null) && e.owner == this) { + val sym = e.sym + if (p(sym)) syms = sym :: syms + e = e.prev + } + syms + } + + def find(p: Symbol => Boolean)(implicit ctx: Context): Symbol = filter(p) match { + case sym :: _ => sym + case _ => NoSymbol + } /** Returns a new mutable scope with the same content as this one. */ def cloneScope(implicit ctx: Context): MutableScope - /** Is the scope empty? */ - override def isEmpty: Boolean = lastEntry eq null - /** Lookup a symbol entry matching given name. */ def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry @@ -144,6 +163,12 @@ object Scopes { final def toText(printer: Printer): Text = printer.toText(this) def checkConsistent()(implicit ctx: Context) = () + + /** Ensure that all elements of this scope have been entered. + * Overridden by SymbolLoaders.PackageLoader#PackageScope, where it + * makes sure that all names with `$`'s have been added. + */ + protected def ensureComplete()(implicit ctx: Context): Unit = () } /** A subclass of Scope that defines methods for entering and @@ -341,8 +366,9 @@ object Scopes { /** Returns all symbols as a list in the order they were entered in this scope. * Does _not_ include the elements of inherited scopes. */ - override final def toList: List[Symbol] = { + override final def toList(implicit ctx: Context): List[Symbol] = { if (elemsCache eq null) { + ensureComplete() elemsCache = Nil var e = lastEntry while ((e ne null) && e.owner == this) { @@ -354,6 +380,7 @@ object Scopes { } override def implicitDecls(implicit ctx: Context): List[TermRef] = { + ensureComplete() var irefs = new mutable.ListBuffer[TermRef] var e = lastEntry while (e ne null) { @@ -368,25 +395,13 @@ object Scopes { /** Vanilla scope - symbols are stored in declaration order. */ - final def sorted: List[Symbol] = toList - - override def foreach[U](p: Symbol => U): Unit = toList foreach p - - override def filter(p: Symbol => Boolean): List[Symbol] = { - var syms: List[Symbol] = Nil - var e = lastEntry - while ((e ne null) && e.owner == this) { - val sym = e.sym - if (p(sym)) syms = sym :: syms - e = e.prev - } - syms - } + final def sorted(implicit ctx: Context): List[Symbol] = toList override def openForMutations: MutableScope = this /** Check that all symbols in this scope are in their correct hashtable buckets. */ override def checkConsistent()(implicit ctx: Context) = { + ensureComplete() var e = lastEntry while (e != null) { var e1 = lookupEntry(e.name) @@ -425,7 +440,7 @@ object Scopes { override private[dotc] def lastEntry = null override def size = 0 override def nestingLevel = 0 - override def toList = Nil + override def toList(implicit ctx: Context) = Nil override def cloneScope(implicit ctx: Context): MutableScope = unsupported("cloneScope") override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = null override def lookupNextEntry(entry: ScopeEntry)(implicit ctx: Context): ScopeEntry = null diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index b8cd7bb1800f..5a277cacbd94 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -930,14 +930,15 @@ object SymDenotations { * and which is also defined in the same scope and compilation unit. * NoSymbol if this class does not exist. */ - final def companionClass(implicit ctx: Context): Symbol = { - val companionMethod = info.decls.denotsNamed(nme.COMPANION_CLASS_METHOD, selectPrivate).first - - if (companionMethod.exists) - companionMethod.info.resultType.classSymbol - else - NoSymbol - } + final def companionClass(implicit ctx: Context): Symbol = + if (is(Package)) NoSymbol + else { + val companionMethod = info.decls.denotsNamed(nme.COMPANION_CLASS_METHOD, selectPrivate).first + if (companionMethod.exists) + companionMethod.info.resultType.classSymbol + else + NoSymbol + } final def scalacLinkedClass(implicit ctx: Context): Symbol = if (this is ModuleClass) companionNamed(effectiveName.toTypeName) @@ -1777,8 +1778,8 @@ object SymDenotations { def constrNamed(cname: TermName) = info.decls.denotsNamed(cname).last.symbol // denotsNamed returns Symbols in reverse order of occurrence if (this.is(ImplClass)) constrNamed(nme.TRAIT_CONSTRUCTOR) // ignore normal constructor - else - constrNamed(nme.CONSTRUCTOR).orElse(constrNamed(nme.TRAIT_CONSTRUCTOR)) + else if (this.is(Package)) NoSymbol + else constrNamed(nme.CONSTRUCTOR).orElse(constrNamed(nme.TRAIT_CONSTRUCTOR)) } /** The parameter accessors of this class. Term and type accessors, diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 168908cedd63..e4d2d446fd5d 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -14,6 +14,7 @@ import Contexts._, Symbols._, Flags._, SymDenotations._, Types._, Scopes._, util import StdNames._, NameOps._ import Decorators.{PreNamedString, StringInterpolators} import classfile.ClassfileParser +import util.Stats import scala.util.control.NonFatal object SymbolLoaders { @@ -148,46 +149,79 @@ class SymbolLoaders { override def sourceModule(implicit ctx: Context) = _sourceModule def description = "package loader " + classpath.name + private var enterFlatClasses: Option[Context => Unit] = None + + Stats.record("package scopes") + /** The scope of a package. This is different from a normal scope - * in three aspects: - * - * 1. Names of scope entries are kept in mangled form. - * 2. Some function types in the `scala` package are synthesized. + * in three aspects: + * + * 1. Names of scope entries are kept in mangled form. + * 2. Some function types in the `scala` package are synthesized. */ final class PackageScope extends MutableScope { override def newScopeEntry(name: Name, sym: Symbol)(implicit ctx: Context): ScopeEntry = super.newScopeEntry(name.mangled, sym) override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { - val e = super.lookupEntry(name.mangled) - if (e == null && - _sourceModule.name == nme.scala_ && _sourceModule == defn.ScalaPackageVal && - name.isTypeName && name.isSyntheticFunction) + val mangled = name.mangled + val e = super.lookupEntry(mangled) + if (e != null) e + else if (_sourceModule.initialDenot.name == nme.scala_ && _sourceModule == defn.ScalaPackageVal && + name.isTypeName && name.isSyntheticFunction) newScopeEntry(defn.newFunctionNTrait(name.asTypeName)) + else if (isFlatName(mangled.toSimpleName) && enterFlatClasses.isDefined) { + Stats.record("package scopes with flatnames entered") + enterFlatClasses.get(ctx) + lookupEntry(name) + } else e } + override def ensureComplete()(implicit ctx: Context) = + for (enter <- enterFlatClasses) enter(ctx) + override def newScopeLikeThis() = new PackageScope } private[core] val currentDecls: MutableScope = new PackageScope() + def isFlatName(name: SimpleTermName) = name.lastIndexOf('$', name.length - 2) >= 0 + + def isFlatName(classRep: ClassPath#ClassRep) = { + val idx = classRep.name.indexOf('$') + idx >= 0 && idx < classRep.name.length - 1 + } + + def maybeModuleClass(classRep: ClassPath#ClassRep) = classRep.name.last == '$' + + private def enterClasses(root: SymDenotation, flat: Boolean)(implicit ctx: Context) = { + def isAbsent(classRep: ClassPath#ClassRep) = + !root.unforcedDecls.lookup(classRep.name.toTypeName).exists + + if (!root.isRoot) { + for (classRep <- classpath.classes) + if (!maybeModuleClass(classRep) && isFlatName(classRep) == flat && + (!flat || isAbsent(classRep))) // on 2nd enter of flat names, check that the name has not been entered before + initializeFromClassPath(root.symbol, classRep) + for (classRep <- classpath.classes) + if (maybeModuleClass(classRep) && isFlatName(classRep) == flat && + isAbsent(classRep)) + initializeFromClassPath(root.symbol, classRep) + } + } + def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = { assert(root is PackageClass, root) - def maybeModuleClass(classRep: ClassPath#ClassRep) = classRep.name.last == '$' val pre = root.owner.thisType root.info = ClassInfo(pre, root.symbol.asClass, Nil, currentDecls, pre select sourceModule) if (!sourceModule.isCompleted) sourceModule.completer.complete(sourceModule) - if (!root.isRoot) { - for (classRep <- classpath.classes) - if (!maybeModuleClass(classRep)) - initializeFromClassPath(root.symbol, classRep) - for (classRep <- classpath.classes) - if (maybeModuleClass(classRep) && - !root.unforcedDecls.lookup(classRep.name.toTypeName).exists) - initializeFromClassPath(root.symbol, classRep) + enterFlatClasses = Some { ctx => + enterFlatClasses = None + enterClasses(root, flat = true)(ctx) } + enterClasses(root, flat = false) if (!root.isEmptyPackage) for (pkg <- classpath.packages) enterPackage(root.symbol, pkg) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index f3bb99b27dcc..1db3ebcb066c 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -363,7 +363,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas } def slowSearch(name: Name): Symbol = - owner.info.decls.find(_.name == name).getOrElse(NoSymbol) + owner.info.decls.find(_.name == name) def nestedObjectSymbol: Symbol = { // If the owner is overloaded (i.e. a method), it's not possible to select the diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 87837fd82c0b..20cd0842669c 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -237,7 +237,7 @@ object messages { val msg = { import core.Flags._ val maxDist = 3 - val decls = site.decls.flatMap { sym => + val decls = site.decls.toList.flatMap { sym => if (sym.flagsUNSAFE.is(Synthetic | PrivateOrLocal) || sym.isConstructor) Nil else List((sym.name.show, sym)) } diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index db19bf6b6850..5488d1979649 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -214,7 +214,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder // and can therefore be ignored. def alwaysPresent(s: Symbol) = s.isCompanionMethod || (csym.is(ModuleClass) && s.isConstructor) - val decls = cinfo.decls.filterNot(alwaysPresent).toList + val decls = cinfo.decls.filter(!alwaysPresent(_)).toList val apiDecls = apiDefinitions(decls) val declSet = decls.toSet @@ -224,7 +224,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder // We cannot filter out `LegacyApp` because it contains the main method, // see the comment about main class discovery in `computeType`. .filter(bc => !bc.is(Scala2x) || bc.eq(LegacyAppClass)) - .flatMap(_.classInfo.decls.filterNot(s => s.is(Private) || declSet.contains(s))) + .flatMap(_.classInfo.decls.filter(s => !(s.is(Private) || declSet.contains(s)))) // Inherited members need to be computed lazily because a class might contain // itself as an inherited member, like in `class A { class B extends A }`, // this works because of `classLikeCache` diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index c302aa61b543..7ad7fb348447 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -217,7 +217,7 @@ object ExplicitOuter { def outerAccessor(cls: ClassSymbol)(implicit ctx: Context): Symbol = if (cls.isStatic) NoSymbol // fast return to avoid scanning package decls else cls.info.member(outerAccName(cls)).suchThat(_ is OuterAccessor).symbol orElse - cls.info.decls.find(_ is OuterAccessor).getOrElse(NoSymbol) + cls.info.decls.find(_ is OuterAccessor) /** Class has an outer accessor. Can be called only after phase ExplicitOuter. */ private def hasOuter(cls: ClassSymbol)(implicit ctx: Context): Boolean = diff --git a/compiler/src/dotty/tools/dotc/transform/PrimitiveForwarders.scala b/compiler/src/dotty/tools/dotc/transform/PrimitiveForwarders.scala index d752ce8e7107..7c51ba59388f 100644 --- a/compiler/src/dotty/tools/dotc/transform/PrimitiveForwarders.scala +++ b/compiler/src/dotty/tools/dotc/transform/PrimitiveForwarders.scala @@ -43,7 +43,7 @@ class PrimitiveForwarders extends MiniPhaseTransform with IdentityDenotTransform import ops._ def methodPrimitiveForwarders: List[Tree] = - for (meth <- mixins.flatMap(_.info.decls.flatMap(needsPrimitiveForwarderTo)).distinct) + for (meth <- mixins.flatMap(_.info.decls.toList.flatMap(needsPrimitiveForwarderTo)).distinct) yield polyDefDef(implementation(meth.asTerm), forwarder(meth)) cpy.Template(impl)(body = methodPrimitiveForwarders ::: impl.body) diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 44c26ecd9c9f..eb7773ef3869 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -391,11 +391,11 @@ class TreeChecker extends Phase with SymTransformer { !x.isCompanionMethod && !x.isValueClassConvertMethod - val symbolsNotDefined = cls.classInfo.decls.toSet.filter(isNonMagicalMethod) -- impl.body.map(_.symbol) - constr.symbol + val symbolsNotDefined = cls.classInfo.decls.toList.toSet.filter(isNonMagicalMethod) -- impl.body.map(_.symbol) - constr.symbol assert(symbolsNotDefined.isEmpty, i" $cls tree does not define methods: ${symbolsNotDefined.toList}%, %\n" + - i"expected: ${cls.classInfo.decls.toSet.filter(isNonMagicalMethod).toList}%, %\n" + + i"expected: ${cls.classInfo.decls.toList.toSet.filter(isNonMagicalMethod)}%, %\n" + i"defined: ${impl.body.map(_.symbol)}%, %") super.typedClassDef(cdef, cls) diff --git a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala index b398c2767218..00d491486a6c 100644 --- a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala +++ b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala @@ -28,13 +28,10 @@ object ValueClasses { !d.isSuperAccessor && !d.is(Macro) - /** The member that of a derived value class that unboxes it. */ + /** The member of a derived value class that unboxes it. */ def valueClassUnbox(d: ClassDenotation)(implicit ctx: Context): Symbol = // (info.decl(nme.unbox)).orElse(...) uncomment once we accept unbox methods - d.classInfo.decls - .find(d => d.isTerm && d.symbol.is(ParamAccessor)) - .map(_.symbol) - .getOrElse(NoSymbol) + d.classInfo.decls.find(_.is(TermParamAccessor)) /** For a value class `d`, this returns the synthetic cast from the underlying type to * ErasedValueType defined in the companion module. This method is added to the module diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index ead4ad5cbd42..ec6fb1770000 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -91,8 +91,8 @@ trait TypeAssigner { else parent } - val refinableDecls = info.decls.filterNot( - sym => sym.is(TypeParamAccessor | Private) || sym.isConstructor) + val refinableDecls = info.decls.filter( + sym => !(sym.is(TypeParamAccessor | Private) || sym.isConstructor)) val fullType = (parentType /: refinableDecls)(addRefinement) mapOver(fullType) case TypeBounds(lo, hi) if variance > 0 => From 868a6a1025781eeac3eb884040639119542b3f49 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 3 Apr 2017 17:35:21 +0200 Subject: [PATCH 63/68] Make extension method names semantic --- .../src/dotty/tools/dotc/core/NameKinds.scala | 33 ++++++++++++++----- .../tools/dotc/core/tasty/TastyFormat.scala | 1 + .../dotc/transform/ExtensionMethods.scala | 5 +-- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index 8ea19bed2a39..cda6e0c83ad7 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -132,6 +132,13 @@ object NameKinds { case DerivedTermName(underlying, info: this.NumberedInfo) => Some((underlying, info.num)) case _ => None } + protected def skipSeparatorAndNum(name: SimpleTermName, separator: String): Int = { + var i = name.length + while (i > 0 && name(i - 1).isDigit) i -= 1 + if (i > separator.length && i < name.length && + name.slice(i - separator.length, i).toString == separator) i + else -1 + } } case class UniqueNameKind(val separator: String) @@ -205,6 +212,18 @@ object NameKinds { val SkolemName = new UniqueNameKind("?") val LiftedTreeName = new UniqueNameKind("liftedTree") + val UniqueExtMethName = new UniqueNameKind("$extension") { + override def unmangle(name: SimpleTermName): TermName = { + val i = skipSeparatorAndNum(name, separator) + if (i > 0) { + val index = name.drop(i).toString.toInt + var original = name.take(i - separator.length).asTermName + apply(original, index) + } + else name + } + } + val PatMatStdBinderName = new UniqueNameKind("x") val PatMatPiName = new UniqueNameKind("pi") // FIXME: explain what this is val PatMatPName = new UniqueNameKind("p") // FIXME: explain what this is @@ -218,15 +237,12 @@ object NameKinds { val prefix = if (underlying.isConstructorName) nme.DEFAULT_GETTER_INIT else underlying prefix.toString + str.DEFAULT_GETTER + (info.num + 1) } - - private val dgLen = str.DEFAULT_GETTER.length - + // TODO: Reduce code duplication with UniqueExtMethName override def unmangle(name: SimpleTermName): TermName = { - var i = name.length - while (i > 0 && name(i - 1).isDigit) i -= 1 - if (i > dgLen && i < name.length && name.slice(i - dgLen, i) == nme.DEFAULT_GETTER) { + val i = skipSeparatorAndNum(name, str.DEFAULT_GETTER) + if (i > 0) { val index = name.drop(i).toString.toInt - 1 - var original = name.take(i - dgLen).asTermName + var original = name.take(i - str.DEFAULT_GETTER.length).asTermName if (original == nme.DEFAULT_GETTER_INIT) original = Names.CONSTRUCTOR apply(original, index) } @@ -260,6 +276,7 @@ object NameKinds { val AvoidClashName = new SuffixNameKind(AVOIDCLASH, "$_avoid_name_clash_$") val DirectName = new SuffixNameKind(DIRECT, "$direct") val FieldName = new SuffixNameKind(FIELD, "$$local") + val ExtMethName = new SuffixNameKind(EXTMETH, "$extension") val ModuleVarName = new SuffixNameKind(OBJECTVAR, "$module") val ModuleClassName = new SuffixNameKind(OBJECTCLASS, "$", optInfoString = "ModuleClass") @@ -283,7 +300,7 @@ object NameKinds { } val Scala2MethodNameKinds: List[NameKind] = - List(DefaultGetterName, ProtectedAccessorName, ProtectedSetterName) + List(DefaultGetterName, ExtMethName, UniqueExtMethName, ProtectedAccessorName, ProtectedSetterName) def simpleNameKindOfTag : collection.Map[Int, ClassifiedNameKind] = simpleNameKinds def qualifiedNameKindOfTag : collection.Map[Int, QualifiedNameKind] = qualifiedNameKinds diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 68c5bf10e0d7..f03e279c65a8 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -240,6 +240,7 @@ object TastyFormat { final val DIRECT = 31 final val FIELD = 32 final val SETTER = 33 + final val EXTMETH = 34 final val OBJECTVAR = 39 final val OBJECTCLASS = 40 diff --git a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala index 64474cecdf00..61f32edaefff 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala @@ -16,6 +16,7 @@ import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTrans import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._ import TypeErasure.{ valueErasure, ErasedValueType } import TypeUtils._ +import NameKinds.{ExtMethName, UniqueExtMethName} import util.Positions._ import Decorators._ import SymUtils._ @@ -206,11 +207,11 @@ object ExtensionMethods { val alts = decl.alternatives val index = alts indexOf imeth.denot assert(index >= 0, alts + " does not contain " + imeth) - def altName(index: Int) = (imeth.name + "$extension" + index).toTermName + def altName(index: Int) = UniqueExtMethName(imeth.name.asTermName, index) altName(index) #:: ((0 until alts.length).toStream filter (index != _) map altName) case decl => assert(decl.exists, imeth.name + " not found in " + imeth.owner + "'s decls: " + imeth.owner.info.decls) - Stream((imeth.name + "$extension").toTermName) + Stream(ExtMethName(imeth.name.asTermName)) } } From b17af4b7abfa1de2a0099329a7e7148cabafbab0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 6 Apr 2017 14:58:20 +0200 Subject: [PATCH 64/68] Fix rebase breakage --- .../src/dotty/tools/dotc/core/Flags.scala | 2 +- .../src/dotty/tools/dotc/core/NameKinds.scala | 1 - .../src/dotty/tools/dotc/core/NameOps.scala | 23 +++---------------- .../src/dotty/tools/dotc/core/StdNames.scala | 2 ++ 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index ef326171991f..84072cd50b85 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -452,7 +452,7 @@ object Flags { final val FromStartFlags = Module | Package | Deferred | MethodOrHKCommon | Param | ParamAccessor | Scala2ExistentialCommon | Mutable.toCommonFlags | InSuperCall | Touched | JavaStatic | - CovariantOrOuter | ContravariantOrLabel | ExpandedName | CaseAccessorOrBaseTypeArg | + CovariantOrOuter | ContravariantOrLabel | CaseAccessorOrBaseTypeArg | Fresh | Frozen | Erroneous | ImplicitCommon | Permanent | Synthetic | SuperAccessorOrScala2x | Inline diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index cda6e0c83ad7..c34a100a8e80 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -252,7 +252,6 @@ object NameKinds { object VariantName extends NumberedNameKind(VARIANT, "Variant") { val varianceToPrefix = Map(-1 -> '-', 0 -> '=', 1 -> '+') - val prefixToVariance = Map('-' -> -1, '=' -> 0, '+' -> 1) def mkString(underlying: TermName, info: ThisInfo) = { varianceToPrefix(info.num).toString + underlying } diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 27bd3a05e954..915bd52abb20 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -126,33 +126,16 @@ object NameOps { def errorName: N = likeSpaced(name ++ nme.ERROR) -/* + /** Name with variance prefix: `+` for covariant, `-` for contravariant */ def withVariance(v: Int): N = - if (hasVariance) dropVariance.withVariance(v) - else v match { - case -1 => likeTyped('-' +: name) - case 1 => likeTyped('+' +: name) - case 0 => name - } - - /** Does name have a `+`/`-` variance prefix? */ - def hasVariance: Boolean = - name.nonEmpty && name.head == '+' || name.head == '-' - - /** Drop variance prefix if name has one */ - def dropVariance: N = if (hasVariance) likeTyped(name.tail) else name + likeSpaced { VariantName(name.exclude(VariantName).toTermName, v) } /** The variance as implied by the variance prefix, or 0 if there is * no variance prefix. */ - def variance = name.head match { - case '-' => -1 - case '+' => 1 - case _ => 0 - } + def variance = name.collect { case VariantName(_, n) => n }.getOrElse(0) -*/ def freshened(implicit ctx: Context): N = likeSpaced { name.toTermName match { case ModuleClassName(original) => ModuleClassName(original.freshened) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 9272c32ed70d..306a84589bd5 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -122,6 +122,8 @@ object StdNames { val DEFAULT_GETTER: N = str.DEFAULT_GETTER val DEFAULT_GETTER_INIT: N = "$lessinit$greater" val DO_WHILE_PREFIX: N = "doWhile$" + val DOLLAR_VALUES: N = "$values" + val DOLLAR_NEW: N = "$new" val EMPTY: N = "" val EMPTY_PACKAGE: N = Names.EMPTY_PACKAGE.toString val EXCEPTION_RESULT_PREFIX: N = "exceptionResult" From 800b1ad042044d8902c76fe353f7adf0491b5f20 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 6 Apr 2017 15:34:09 +0200 Subject: [PATCH 65/68] Fix pickling/unpickling of names Running the test suite with the pickling printer on showed up two more problems which are fixed in this commit. --- compiler/src/dotty/tools/dotc/core/NameKinds.scala | 7 +++++++ compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala | 6 +++--- .../src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala | 2 ++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index c34a100a8e80..bee39adaa1b5 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -141,6 +141,13 @@ object NameKinds { } } + object AnyNumberedName { + def unapply(name: DerivedTermName): Option[(TermName, Int)] = name match { + case DerivedTermName(qual, info: NumberedInfo) => Some((qual, info.num)) + case _ => None + } + } + case class UniqueNameKind(val separator: String) extends NumberedNameKind(UNIQUE, s"Unique $separator") { override def definesNewName = true diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index 7ee6427f3724..270d6be56d8f 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala @@ -45,7 +45,7 @@ class NameBuffer extends TastyBuffer(10000) { val lengthAddr = currentAddr for (i <- 0 until lengthWidth) writeByte(0) op - val length = currentAddr.index - lengthAddr.index - 1 + val length = currentAddr.index - lengthAddr.index - lengthWidth putNat(lengthAddr, length, lengthWidth) } @@ -70,10 +70,10 @@ class NameBuffer extends TastyBuffer(10000) { writeNat(num) if (!original.isEmpty) writeNameRef(original) } - case DefaultGetterName(method, paramNumber) => - withLength { writeNameRef(method); writeNat(paramNumber) } case VariantName(original, sign) => withLength { writeNameRef(original); writeNat(sign + 1) } + case AnyNumberedName(original, num) => + withLength { writeNameRef(original); writeNat(num) } case SignedName(original, Signature(params, result)) => withLength( { writeNameRef(original); writeNameRef(result); params.foreach(writeNameRef) }, diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala index 835222727e0b..37a3c2e762ad 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala @@ -61,6 +61,8 @@ class TastyUnpickler(reader: TastyReader) { DefaultGetterName(readName(), readNat()) case VARIANT => VariantName(readName(), readNat() - 1) + case OUTERSELECT => + OuterSelectName(readName(), readNat()) case SIGNED => val original = readName() val result = readName().toTypeName From a5b6bd6ac30b3ef618314ee8eff7b1d71b0fe131 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 10 Apr 2017 22:30:04 +0200 Subject: [PATCH 66/68] Adapt isPackageObject to semantic naming Used a hardcoded string before, which caused test failures. --- compiler/src/dotty/tools/dotc/core/StdNames.scala | 1 - compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 306a84589bd5..92befdacbd9f 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -135,7 +135,6 @@ object StdNames { val OPS_PACKAGE: N = "" val OVERLOADED: N = "" val PACKAGE: N = "package" - val PACKAGE_CLS: N = "package$" val ROOT: N = "" val SPECIALIZED_SUFFIX: N = "$sp" val SUPER_PREFIX: N = "super$" diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 5a277cacbd94..1e0beb5f30bd 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -513,8 +513,10 @@ object SymDenotations { /** Is this symbol a package object or its module class? */ def isPackageObject(implicit ctx: Context): Boolean = { - val poName = if (isType) nme.PACKAGE_CLS else nme.PACKAGE - (name.toTermName == poName) && (owner is Package) && (this is Module) + val nameMatches = + if (isType) name == tpnme.PACKAGE.moduleClassName + else name == nme.PACKAGE + nameMatches && (owner is Package) && (this is Module) } /** Is this symbol an abstract type? */ From bec4f9d2cbf7fe000efb849abd5d86a34a0a084a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 11 Apr 2017 08:55:17 +0200 Subject: [PATCH 67/68] Better documentation of sharable structures in Names, NameKinds --- compiler/src/dotty/tools/dotc/core/NameKinds.scala | 3 +++ compiler/src/dotty/tools/dotc/core/Names.scala | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index bee39adaa1b5..0f08e470103e 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -13,6 +13,9 @@ import collection.mutable object NameKinds { + // These are sharable since all NameKinds are created eagerly at the start of the program + // before any concurrent threads are forked. for this to work, NameKinds should never + // be created lazily or in modules that start running after compilers are forked. @sharable private val simpleNameKinds = new mutable.HashMap[Int, ClassifiedNameKind] @sharable private val qualifiedNameKinds = new mutable.HashMap[Int, QualifiedNameKind] @sharable private val uniqueNameKinds = new mutable.HashMap[String, UniqueNameKind] diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index cef55a4828dc..a72a028449af 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -134,7 +134,8 @@ object Names { def info: NameInfo = SimpleTermNameKind.info def underlying: TermName = unsupported("underlying") - @sharable private var derivedNames: AnyRef /* SimpleMap | j.u.HashMap */ = + @sharable // because of synchronized block in `and` + private var derivedNames: AnyRef /* SimpleMap | j.u.HashMap */ = SimpleMap.Empty[NameInfo] private def getDerived(info: NameInfo): DerivedTermName /* | Null */= derivedNames match { From 87608bded1fb23519a829fa7f6ee14d4b6a515dc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 11 Apr 2017 09:52:19 +0200 Subject: [PATCH 68/68] Fix type error --- compiler/src/dotty/tools/dotc/printing/Formatting.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala index aa25880c28d1..b35a07027da6 100644 --- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala +++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala @@ -139,7 +139,7 @@ object Formatting { seen.record(super.ParamRefNameString(param), param) override def toTextRef(tp: SingletonType): Text = tp match { - case tp: SkolemType => seen.record(tp.repr, tp) + case tp: SkolemType => seen.record(tp.repr.toString, tp) case _ => super.toTextRef(tp) } }