From f827882850754ba7862a1ff1615d78b350cf56cb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 21 Mar 2017 14:47:59 +0100 Subject: Add derived name machinery Add machinery to define and hash cons derived names. --- compiler/src/dotty/tools/dotc/core/NameInfos.scala | 39 ++++++++++ compiler/src/dotty/tools/dotc/core/NameOps.scala | 1 - compiler/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 (limited to 'compiler/src/dotty') 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 000000000..4bbc5bbcf --- /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 240ad359b..a6e5fefc7 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 6f970aae1..74e1fd2d2 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 -- cgit v1.2.3