diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 2040b39c3071..923f0a95a632 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -634,7 +634,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma toDenot(sym)(shiftedContext).isStatic(shiftedContext) } - def isStaticConstructor: Boolean = (isStaticMember && isClassConstructor) || (sym.name eq core.Names.STATIC_CONSTRUCTOR) + def isStaticConstructor: Boolean = (isStaticMember && isClassConstructor) || (sym.name eq nme.STATIC_CONSTRUCTOR) // navigation diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 07d6702f4965..0920ca946598 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -137,7 +137,7 @@ class Definitions { } private def newMethod(cls: ClassSymbol, name: TermName, info: Type, flags: FlagSet = EmptyFlags): TermSymbol = - newSymbol(cls, name.encode, flags | Method, info).asTerm + newSymbol(cls, name, flags | Method, info).asTerm private def enterMethod(cls: ClassSymbol, name: TermName, info: Type, flags: FlagSet = EmptyFlags): TermSymbol = newMethod(cls, name, info, flags).entered @@ -301,7 +301,7 @@ class Definitions { lazy val ScalaPredefModuleRef = ctx.requiredModuleRef("scala.Predef") def ScalaPredefModule(implicit ctx: Context) = ScalaPredefModuleRef.symbol - lazy val Predef_ConformsR = ScalaPredefModule.requiredClass("$less$colon$less").typeRef + lazy val Predef_ConformsR = ScalaPredefModule.requiredClass("<:<").typeRef def Predef_Conforms(implicit ctx: Context) = Predef_ConformsR.symbol lazy val Predef_conformsR = ScalaPredefModule.requiredMethodRef("$conforms") def Predef_conforms(implicit ctx: Context) = Predef_conformsR.symbol diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index ffc58f2e8d2f..aea68c34929c 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -1194,7 +1194,7 @@ object Denotations { select(recur(prefix), wrap(selector)) case qn @ AnyQualifiedName(prefix, _) => recur(prefix, n => wrap(qn.info.mkString(n).toTermName)) - case path: SimpleTermName => + case path: SimpleName => def recurSimple(len: Int, wrap: TermName => Name): Denotation = { val point = path.lastIndexOf('.', len - 1) val selector = wrap(path.slice(point + 1, len).asTermName) diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index 17a7c1412001..09a13e130f54 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -11,6 +11,7 @@ import Decorators._ import Contexts.Context import collection.mutable +/** Defines possible kinds of NameInfo of a derived name */ object NameKinds { // These are sharable since all NameKinds are created eagerly at the start of the program @@ -18,75 +19,113 @@ object NameKinds { // 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 numberedNameKinds = new mutable.HashMap[Int, NumberedNameKind] @sharable private val uniqueNameKinds = new mutable.HashMap[String, UniqueNameKind] + /** A class for the info stored in a derived name */ abstract class NameInfo extends DotClass { def kind: NameKind def mkString(underlying: TermName): String - def map(f: SimpleTermName => SimpleTermName): NameInfo = this + def map(f: SimpleName => SimpleName): NameInfo = this } + /** An abstract base class of classes that define the kind of a derived name info */ abstract class NameKind(val tag: Int) extends DotClass { self => + + /** The info class defined by this kind */ type ThisInfo <: Info + + /** A simple info type; some subclasses of Kind define more refined versions */ class Info extends NameInfo { this: ThisInfo => def kind = self def mkString(underlying: TermName) = self.mkString(underlying, this) override def toString = infoString } + + /** Does this kind define logically a new name? Tested by the `rewrite` and `collect` + * combinators of names. + */ def definesNewName = false - def unmangle(name: SimpleTermName): TermName = name + + /** Unmangle simple name `name` into a name of this kind, or return + * original name if this is not possible. + */ + def unmangle(name: SimpleName): TermName = name + + /** Turn a name of this kind consisting of an `underlying` prefix + * and the given `info` into a string. + */ def mkString(underlying: TermName, info: ThisInfo): String + + /** A string used for displaying the structure of a name */ def infoString: String } - object SimpleTermNameKind extends NameKind(UTF8) { self => + /** The kind of SimpleNames */ + object SimpleNameKind extends NameKind(UTF8) { self => type ThisInfo = Info val info = new Info def mkString(underlying: TermName, info: ThisInfo) = unsupported("mkString") def infoString = unsupported("infoString") } + /** The kind of names that add a simple classification to an underlying name. + */ abstract class ClassifiedNameKind(tag: Int, val infoString: String) extends NameKind(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) + + /** Build a new name of this kind from an underlying name */ + def apply(underlying: TermName) = underlying.derived(info) + + /** Extractor operation for names of this kind */ + def unapply(name: DerivedName): Option[TermName] = name match { + case DerivedName(underlying, `info`) => Some(underlying) case _ => None } + simpleNameKinds(tag) = this } + /** The kind of names that get formed by adding a prefix to an underlying name */ 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 - override def unmangle(name: SimpleTermName): TermName = + underlying.qualToString(_.toString, n => prefix + n.toString) + override def unmangle(name: SimpleName): TermName = if (name.startsWith(prefix)) apply(name.drop(prefix.length).asSimpleName) else name } + /** The kind of names that get formed by appending a suffix to an underlying 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 = + def mkString(underlying: TermName, info: ThisInfo) = + underlying.qualToString(_.toString, n => n.toString + suffix) + override def unmangle(name: SimpleName): TermName = if (name.endsWith(suffix)) apply(name.take(name.length - suffix.length).asSimpleName) else name } + /** A base trait for infos that define an additional selector name */ trait QualifiedInfo extends NameInfo { - val name: SimpleTermName + val name: SimpleName } + /** The kind of qualified names, consisting of an underlying name as a prefix, + * followed by a separator, followed by a simple selector name. + * + * A qualified names always constitutes a new name, different from its underlying name. + */ 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)) + case class QualInfo(val name: SimpleName) extends Info with QualifiedInfo { + override def map(f: SimpleName => SimpleName): NameInfo = new QualInfo(f(name)) override def toString = s"$infoString $name" } - def apply(qual: TermName, name: SimpleTermName): TermName = + + def apply(qual: TermName, name: SimpleName): TermName = qual.derived(new QualInfo(name)) /** Overloaded version used only for ExpandedName and TraitSetterName. @@ -94,12 +133,12 @@ object NameKinds { * 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 name: SimpleName => 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)) + def unapply(name: DerivedName): Option[(TermName, SimpleName)] = name match { + case DerivedName(qual, info: this.QualInfo) => Some((qual, info.name)) case _ => None } @@ -107,23 +146,27 @@ object NameKinds { def mkString(underlying: TermName, info: ThisInfo) = s"$underlying$separator${info.name}" + def infoString = s"Qualified $separator" qualifiedNameKinds(tag) = this } + /** An extractor for qualified names of an arbitrary kind */ object AnyQualifiedName { - def unapply(name: DerivedTermName): Option[(TermName, SimpleTermName)] = name match { - case DerivedTermName(qual, info: QualifiedInfo) => + def unapply(name: DerivedName): Option[(TermName, SimpleName)] = name match { + case DerivedName(qual, info: QualifiedInfo) => Some((name.underlying, info.name)) case _ => None } } + /** A base trait for infos that contain a number */ trait NumberedInfo extends NameInfo { def num: Int } + /** The kind of numbered names consisting of an underlying name and a number */ abstract class NumberedNameKind(tag: Int, val infoString: String) extends NameKind(tag) { self => type ThisInfo = NumberedInfo case class NumberedInfo(val num: Int) extends Info with NameKinds.NumberedInfo { @@ -131,43 +174,54 @@ object NameKinds { } 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)) + def unapply(name: DerivedName): Option[(TermName, Int)] = name match { + case DerivedName(underlying, info: this.NumberedInfo) => Some((underlying, info.num)) case _ => None } - protected def skipSeparatorAndNum(name: SimpleTermName, separator: String): Int = { + protected def skipSeparatorAndNum(name: SimpleName, 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 } + + numberedNameKinds(tag) = this } + /** An extractor for numbered names of arbitrary kind */ object AnyNumberedName { - def unapply(name: DerivedTermName): Option[(TermName, Int)] = name match { - case DerivedTermName(qual, info: NumberedInfo) => Some((qual, info.num)) + def unapply(name: DerivedName): Option[(TermName, Int)] = name match { + case DerivedName(qual, info: NumberedInfo) => Some((qual, info.num)) case _ => None } } + /** The kind of unique names that consist of an underlying name (can be empty), + * a separator indicating the class of unique name, and a unique number. + * + * A unique names always constitutes a new name, different from its underlying name. + */ 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) + val safePrefix = str.sanitize(underlying.toString) + separator safePrefix + info.num } + /** Generate fresh unique name of this kind with given prefix name */ def fresh(prefix: TermName = EmptyTermName)(implicit ctx: Context): TermName = ctx.freshNames.newName(prefix, this) uniqueNameKinds(separator) = this } + /** An extractor for unique names of arbitrary kind */ object AnyUniqueName { - def unapply(name: DerivedTermName): Option[(TermName, String, Int)] = name match { - case DerivedTermName(qual, info: NumberedInfo) => + def unapply(name: DerivedName): Option[(TermName, String, Int)] = name match { + case DerivedName(qual, info: NumberedInfo) => info.kind match { case unique: UniqueNameKind => Some((qual, unique.separator, info.num)) case _ => None @@ -176,15 +230,21 @@ object NameKinds { } } - val QualifiedName = new QualifiedNameKind(QUALIFIED, ".") - val FlatName = new QualifiedNameKind(FLATTENED, "$") - val ExpandPrefixName = new QualifiedNameKind(EXPANDPREFIX, "$") + /** Names of the form `prefix . name` */ + val QualifiedName = new QualifiedNameKind(QUALIFIED, ".") + + /** Names of the form `prefix $ name` that are constructed as a result of flattening */ + val FlatName = new QualifiedNameKind(FLATTENED, "$") + + /** Names of the form `prefix $ name` that are prefixes of expanded names */ + val ExpandPrefixName = new QualifiedNameKind(EXPANDPREFIX, "$") + /** Expanded names of the form `prefix $$ name`. */ val ExpandedName = new QualifiedNameKind(EXPANDED, str.EXPAND_SEPARATOR) { private val FalseSuper = termName("$$super") private val FalseSuperLength = FalseSuper.length - override def unmangle(name: SimpleTermName): TermName = { + override def unmangle(name: SimpleName): TermName = { var i = name.lastIndexOfSlice(str.EXPAND_SEPARATOR) if (i < 0) name else { @@ -199,13 +259,16 @@ object NameKinds { } } - val TraitSetterName = new QualifiedNameKind(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR) + /** Expanded names of the form `prefix $_setter_$ name`. These only occur in Scala2. */ + val TraitSetterName = new QualifiedNameKind(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR) + /** Unique names of the form `prefix $ n` or `$ n $` */ val UniqueName = new UniqueNameKind("$") { override def mkString(underlying: TermName, info: ThisInfo) = if (underlying.isEmpty) "$" + info.num + "$" else super.mkString(underlying, info) } + /** Other unique names */ val InlineAccessorName = new UniqueNameKind("$_inlineAccessor_$") val TempResultName = new UniqueNameKind("ev$") val EvidenceParamName = new UniqueNameKind("evidence$") @@ -223,18 +286,22 @@ object NameKinds { val LiftedTreeName = new UniqueNameKind("liftedTree") val SuperArgName = new UniqueNameKind("$superArg$") + /** A kind of unique extension methods; Unlike other unique names, these can be + * unmangled. + */ val UniqueExtMethName = new UniqueNameKind("$extension") { - override def unmangle(name: SimpleTermName): TermName = { + override def unmangle(name: SimpleName): TermName = { val i = skipSeparatorAndNum(name, separator) if (i > 0) { val index = name.drop(i).toString.toInt - var original = name.take(i - separator.length).asTermName + val original = name.take(i - separator.length).asTermName apply(original, index) } else name } } + /** Kinds of unique names generated by the pattern matcher */ 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 @@ -243,29 +310,28 @@ object NameKinds { val PatMatMatchFailName = new UniqueNameKind("matchFail") val PatMatSelectorName = new UniqueNameKind("selector") + /** The kind of names of default argument getters */ 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 + str.DEFAULT_GETTER + (info.num + 1) } // TODO: Reduce code duplication with UniqueExtMethName - override def unmangle(name: SimpleTermName): TermName = { + override def unmangle(name: SimpleName): TermName = { val i = skipSeparatorAndNum(name, str.DEFAULT_GETTER) if (i > 0) { val index = name.drop(i).toString.toInt - 1 var original = name.take(i - str.DEFAULT_GETTER.length).asTermName - if (original == nme.DEFAULT_GETTER_INIT) original = Names.CONSTRUCTOR + if (original == nme.DEFAULT_GETTER_INIT) original = nme.CONSTRUCTOR apply(original, index) } else name } } + /** The kind of names that also encode a variance: 0 for contravariance, 1 for covariance. */ object VariantName extends NumberedNameKind(VARIANT, "Variant") { - val varianceToPrefix = Map(-1 -> '-', 0 -> '=', 1 -> '+') - def mkString(underlying: TermName, info: ThisInfo) = { - varianceToPrefix(info.num).toString + underlying - } + def mkString(underlying: TermName, info: ThisInfo) = "-+"(info.num).toString + underlying } /** Names of the form N_. Emitted by inliner, replaced by outer path @@ -290,9 +356,9 @@ object NameKinds { val ModuleVarName = new SuffixNameKind(OBJECTVAR, "$module") val ModuleClassName = new SuffixNameKind(OBJECTCLASS, "$", optInfoString = "ModuleClass") + /** A name together with a signature. Used in Tasty trees. */ object SignedName extends NameKind(63) { - /** @param parts resultSig followed by paramsSig */ case class SignedInfo(sig: Signature) extends Info { override def toString = s"$infoString $sig" } @@ -300,8 +366,8 @@ object NameKinds { 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)) + def unapply(name: DerivedName): Option[(TermName, Signature)] = name match { + case DerivedName(underlying, info: SignedInfo) => Some((underlying, info.sig)) case _ => None } @@ -309,10 +375,12 @@ object NameKinds { def infoString: String = "Signed" } + /** Possible name kinds of a method that comes from Scala2 pickling info. */ val Scala2MethodNameKinds: List[NameKind] = List(DefaultGetterName, ExtMethName, UniqueExtMethName, ProtectedAccessorName, ProtectedSetterName) def simpleNameKindOfTag : collection.Map[Int, ClassifiedNameKind] = simpleNameKinds def qualifiedNameKindOfTag : collection.Map[Int, QualifiedNameKind] = qualifiedNameKinds + def numberedNameKindOfTag : collection.Map[Int, NumberedNameKind] = numberedNameKinds 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 915bd52abb20..df29a32c523c 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -52,8 +52,8 @@ 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) + def testSimple(f: SimpleName => Boolean): Boolean = name match { + case name: SimpleName => f(name) case name: TypeName => name.toTermName.testSimple(f) case _ => false } @@ -83,7 +83,7 @@ object NameOps { def isOpAssignmentName: Boolean = name match { case raw.NE | raw.LE | raw.GE | EMPTY => false - case name: SimpleTermName => + case name: SimpleName => name.length > 0 && name.last == '=' && name.head != '=' && isOperatorPart(name.head) case _ => false @@ -100,8 +100,10 @@ object NameOps { * it is also called from the backend. */ def stripModuleClassSuffix: N = likeSpaced { - val semName = - if (name.isSimple && name.endsWith("$")) name.unmangleClassName else name + val semName = name.toTermName match { + case name: SimpleName if name.endsWith("$") => name.unmangleClassName + case _ => name + } semName.exclude(ModuleClassName) } @@ -126,15 +128,24 @@ object NameOps { def errorName: N = likeSpaced(name ++ nme.ERROR) + /** Map variance value -1, +1 to 0, 1 */ + private def varianceToNat(v: Int) = (v + 1) / 2 + + /** Map 0, 1 to variance value -1, +1 */ + private def natToVariance(n: Int) = n * 2 - 1 /** Name with variance prefix: `+` for covariant, `-` for contravariant */ - def withVariance(v: Int): N = - likeSpaced { VariantName(name.exclude(VariantName).toTermName, v) } + def withVariance(v: Int): N = { + val underlying = name.exclude(VariantName) + likeSpaced( + if (v == 0) underlying + else VariantName(underlying.toTermName, varianceToNat(v))) + } /** The variance as implied by the variance prefix, or 0 if there is * no variance prefix. */ - def variance = name.collect { case VariantName(_, n) => n }.getOrElse(0) + def variance = name.collect { case VariantName(_, n) => natToVariance(n) }.getOrElse(0) def freshened(implicit ctx: Context): N = likeSpaced { name.toTermName match { @@ -227,7 +238,7 @@ object NameOps { def compactified(implicit ctx: Context): TermName = termName(compactify(name.toString)) def unmangleClassName: N = name.toTermName match { - case name: SimpleTermName + case name: SimpleName if name.endsWith(str.MODULE_SUFFIX) && !nme.falseModuleClassNames.contains(name) => likeSpaced(name.dropRight(str.MODULE_SUFFIX.length).moduleClassName) case _ => name @@ -235,11 +246,11 @@ object NameOps { def unmangle(kind: NameKind): N = likeSpaced { name rewrite { - case unmangled: SimpleTermName => + case unmangled: SimpleName => kind.unmangle(unmangled) case ExpandedName(prefix, last) => kind.unmangle(last) rewrite { - case kernel: SimpleTermName => + case kernel: SimpleName => ExpandedName(prefix, kernel) } } diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 9fb583373b77..bf14049dcdbc 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -8,6 +8,8 @@ import printing.{Showable, Texts, Printer} import Texts.Text import Decorators._ import Contexts.Context +import StdNames.str +import util.Chars.isIdentifierStart import collection.IndexedSeqOptimized import collection.generic.CanBuildFrom import collection.mutable.{ Builder, StringBuilder, AnyRefMap } @@ -17,8 +19,6 @@ import util.{DotClass, SimpleMap} import config.Config import java.util.HashMap -//import annotation.volatile - object Names { import NameKinds._ @@ -32,14 +32,10 @@ object Names { implicit def eqName: Eq[Name, Name] = Eq - /** A name is essentially a string, with three differences - * 1. Names belong in one of two name spaces: they are type names or term names. - * Term names have a sub-category of "local" field names. - * The same string can correspond a name in each of the three namespaces. - * 2. Names are hash-consed. Two names - * representing the same string in the same universe are always reference identical. - * 3. Names are intended to be encoded strings. @see dotc.util.NameTransformer. - * The encoding will be applied when converting a string to a name. + /** A name if either a term name or a type name. Term names can be simple + * or derived. A simple term name is essentially an interned string stored + * in a name table. A derived term name adds a tag, and possibly a number + * or a further simple name to some other name. */ abstract class Name extends DotClass with PreName { @@ -64,65 +60,117 @@ object Names { /** This name downcasted to a term name */ def asTermName: TermName - def isSimple: Boolean - def asSimpleName: SimpleTermName - def toSimpleName: SimpleTermName - def mangled: Name - def mangledString: String = mangled.toString + /** This name downcasted to a simple term name */ + def asSimpleName: SimpleName + + /** This name converted to a simple term name */ + def toSimpleName: SimpleName + + /** This name converted to a simple term name and in addition + * with all symbolic operator characters expanded. + */ + def mangled: ThisName + /** Convert to string after mangling */ + def mangledString: String + + /** Apply rewrite rule given by `f` to some part of this name, skipping and rewrapping + * other decorators. + * Stops at derived names whose kind has `definesNewName = true`. + * If `f` does not apply to any part, return name unchanged. + */ def rewrite(f: PartialFunction[Name, Name]): ThisName + + /** If partial function `f` is defined for some part of this name, apply it + * in a Some, otherwise None. + * Stops at derived names whose kind has `definesNewName = true`. + */ def collect[T](f: PartialFunction[Name, T]): Option[T] - def mapLast(f: SimpleTermName => SimpleTermName): ThisName - def mapParts(f: SimpleTermName => SimpleTermName): ThisName + + /** Apply `f` to last simple term name making up this name */ + def mapLast(f: SimpleName => SimpleName): ThisName + + /** Apply `f` to all simple term names making up this name */ + def mapParts(f: SimpleName => SimpleName): 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 + /** A derived name consisting of this name and the added info, unless it is + * already present in this name. + * @pre This name does not have a different info of the same kind as `info`. + */ def derived(info: NameInfo): ThisName + + /** A derived name consisting of this name and the info of `kind` */ def derived(kind: ClassifiedNameKind): ThisName = derived(kind.info) + + /** This name without any info of the given `kind`. Excepted, as always, + * is the underlying name part of a qualified name. + */ def exclude(kind: NameKind): ThisName + + /** Does this name contain an info of the given kind? Excepted, as always, + * is the underlying name part of a qualified name. + */ def is(kind: NameKind): Boolean + + /** A string showing the internal structure of this name. By contrast, `toString` + * shows the name after conversion to a simple name. + */ def debugString: String + /** Convert name to text via `printer`. */ def toText(printer: Printer): Text = printer.toText(this) - /** Replace \$op_name's by corresponding operator symbols. */ - def decode: Name + /** Replace operator expansions by corresponding operator symbols. */ + def decode: ThisName + + /** Replace operator symbols by corresponding operator expansions */ + def encode: ThisName - /** Replace operator symbols by corresponding \$op_name's. */ - def encode: Name + /** The first part of this (possible qualified) name */ + def firstPart: SimpleName - def firstPart: SimpleTermName - def lastPart: SimpleTermName + /** The last part of this (possible qualified) name */ + def lastPart: SimpleName - /** A more efficient version of concatenation */ + /** Append `other` to the last part of this name */ def ++ (other: Name): ThisName = ++ (other.toString) def ++ (other: String): ThisName = mapLast(n => termName(n.toString + other)) + + /** Replace all occurrences of `from` to `to` in this name */ def replace(from: Char, to: Char): ThisName = mapParts(_.replace(from, to)) + /** Is this name empty? */ def isEmpty: Boolean + /** Does (the first part of) this name start with `str`? */ def startsWith(str: String): Boolean = firstPart.startsWith(str) + + /** Does (the last part of) this name end with `str`? */ def endsWith(str: String): Boolean = lastPart.endsWith(str) override def hashCode = System.identityHashCode(this) override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] } + /** Names for terms, can be simple or derived */ 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 + + override def isTypeName = false + override def isTermName = true + override def toTermName = this + override def asTypeName = throw new ClassCastException(this + " is not a type name") + override def asTermName = this @sharable // because it is only modified in the synchronized block of toTypeName. @volatile private[this] var _typeName: TypeName = null - def toTypeName: TypeName = { + override def toTypeName: TypeName = { if (_typeName == null) synchronized { if (_typeName == null) @@ -131,34 +179,34 @@ object Names { _typeName } - def likeSpaced(name: Name): TermName = name.toTermName + override def likeSpaced(name: Name): TermName = name.toTermName - def info: NameInfo = SimpleTermNameKind.info + def info: NameInfo = SimpleNameKind.info def underlying: TermName = unsupported("underlying") @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 { - case derivedNames: SimpleMap[NameInfo, DerivedTermName] @unchecked => + private def getDerived(info: NameInfo): DerivedName /* | Null */= derivedNames match { + case derivedNames: SimpleMap[NameInfo, DerivedName] @unchecked => derivedNames(info) - case derivedNames: HashMap[NameInfo, DerivedTermName] @unchecked => + case derivedNames: HashMap[NameInfo, DerivedName] @unchecked => derivedNames.get(info) } - private def putDerived(info: NameInfo, name: DerivedTermName): name.type = { + private def putDerived(info: NameInfo, name: DerivedName): name.type = { derivedNames match { - case derivedNames: SimpleMap[NameInfo, DerivedTermName] @unchecked => + case derivedNames: SimpleMap[NameInfo, DerivedName] @unchecked => if (derivedNames.size < 4) this.derivedNames = derivedNames.updated(info, name) else { - val newMap = new HashMap[NameInfo, DerivedTermName] + val newMap = new HashMap[NameInfo, DerivedName] derivedNames.foreachBinding(newMap.put(_, _)) newMap.put(info, name) this.derivedNames = newMap } - case derivedNames: HashMap[NameInfo, DerivedTermName] @unchecked => + case derivedNames: HashMap[NameInfo, DerivedName] @unchecked => derivedNames.put(info, name) } name @@ -166,7 +214,7 @@ object Names { private def add(info: NameInfo): TermName = synchronized { getDerived(info) match { - case null => putDerived(info, new DerivedTermName(this, info)) + case null => putDerived(info, new DerivedName(this, info)) case derivedName => derivedName } } @@ -174,10 +222,7 @@ 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 = { + override def derived(info: NameInfo): TermName = { val thisKind = this.info.kind val thatKind = info.kind if (thisKind.tag < thatKind.tag || thatKind.definesNewName) add(info) @@ -188,73 +233,93 @@ object Names { } } - def exclude(kind: NameKind): TermName = { + override 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: NameKind): Boolean = { + override def is(kind: NameKind): Boolean = { val thisKind = this.info.kind thisKind == kind || !thisKind.definesNewName && thisKind.tag > kind.tag && underlying.is(kind) } + + @sharable // because it's just a cache for performance + private[Names] var myMangledString: String = null + + @sharable // because it's just a cache for performance + private[this] var myMangled: Name = null + + protected[Names] def mangle: ThisName + + final def mangled: ThisName = { + if (myMangled == null) myMangled = mangle + myMangled.asInstanceOf[ThisName] + } + + final def mangledString: String = { + if (myMangledString == null) + myMangledString = qualToString(_.mangledString, _.mangled.toString) + myMangledString + } + + /** If this a qualified name, split it into underlyng, last part, and separator + * Otherwise return an empty name, the name itself, and "") + */ + def split: (TermName, TermName, String) + + /** Convert to string as follows. If this is a qualified name + * ` `, the sanitized version of `f1() f2()`. + * Otherwise `f2` applied to this name. + */ + def qualToString(f1: TermName => String, f2: TermName => String) = { + val (first, last, sep) = split + if (first.isEmpty) f2(last) else str.sanitize(f1(first) + sep + f2(last)) + } } - class SimpleTermName(val start: Int, val length: Int, @sharable private[Names] var next: SimpleTermName) extends TermName { + /** A simple name is essentiall an interned string */ + final class SimpleName(val start: Int, val length: Int, @sharable private[Names] var next: SimpleName) extends TermName { // `next` is @sharable because it is only modified in the synchronized block of termName. + /** The n'th character */ def apply(n: Int) = chrs(start + n) + /** A character in this name satisfies predicate `p` */ def exists(p: Char => Boolean): Boolean = { var i = 0 while (i < length && !p(chrs(start + i))) i += 1 i < length } + /** All characters in this name satisfy predicate `p` */ def forall(p: Char => Boolean) = !exists(!p(_)) + /** The name contains given character `ch` */ def contains(ch: Char): Boolean = { var i = 0 while (i < length && chrs(start + i) != ch) i += 1 i < length } - def isEmpty = length == 0 - - override 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 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 - } - + /** The index of the last occurrence of `ch` in this name which is at most + * `start`. + */ def lastIndexOf(ch: Char, start: Int = length - 1): Int = { var i = start while (i >= 0 && apply(i) != ch) i -= 1 i } + /** The index of the last occurrence of `str` in this name */ 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) - for (i <- 0 until length) { - if (cs(i) == from) cs(i) = to - } - termName(cs, 0, length) - } - - def slice(from: Int, until: Int): SimpleTermName = { - assert(0 <= from && from <= until && until <= length) - termName(chrs, start + from, until - from) + /** A slice of this name making up the characters between `from` and `until` (exclusive) */ + def slice(from: Int, end: Int): SimpleName = { + assert(0 <= from && from <= end && end <= length) + termName(chrs, start + from, end - from) } def drop(n: Int) = slice(n, length) @@ -262,29 +327,58 @@ object Names { def dropRight(n: Int) = slice(0, length - n) def takeRight(n: Int) = slice(length - n, length) + /** Same as slice, but as a string */ + def sliceToString(from: Int, end: Int) = + if (end <= from) "" else new String(chrs, start + from, end - from) + def head = apply(0) def last = apply(length - 1) - def isSimple = true - def asSimpleName = this - def toSimpleName = this - def mangled = this + override def asSimpleName = this + override def toSimpleName = this + override final def mangle = encode - def rewrite(f: PartialFunction[Name, Name]): ThisName = + override 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) - def mapLast(f: SimpleTermName => SimpleTermName) = f(this) - def mapParts(f: SimpleTermName => SimpleTermName) = f(this) + override def collect[T](f: PartialFunction[Name, T]): Option[T] = f.lift(this) + override def mapLast(f: SimpleName => SimpleName) = f(this) + override def mapParts(f: SimpleName => SimpleName) = f(this) + override def split = (EmptyTermName, this, "") + + override def encode: SimpleName = { + val dontEncode = + length >= 3 && + head == '<' && last == '>' && isIdentifierStart(apply(1)) + if (dontEncode) this else NameTransformer.encode(this) + } - def encode: SimpleTermName = - if (dontEncode(toTermName)) this else NameTransformer.encode(this) + override def decode: SimpleName = NameTransformer.decode(this) - /** Replace \$op_name's by corresponding operator symbols. */ - def decode: SimpleTermName = - if (contains('$')) termName(NameTransformer.decode(toString)) else this + override def isEmpty = length == 0 - def firstPart = this - def lastPart = this + override 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 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): SimpleName = { + 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 + } + termName(cs, 0, length) + } + + override def firstPart = this + override def lastPart = this override def hashCode: Int = start @@ -297,16 +391,16 @@ object Names { // because asserts are caught in exception handlers which might // cause other failures. In that case the first, important failure // is lost. - println("Backend should not call Name#toString, Name#mangledString should be used instead.") - new Error().printStackTrace() + System.err.println("Backend should not call Name#toString, Name#mangledString should be used instead.") + Thread.dumpStack() assert(false) } } new String(chrs, start, length) } - /** It's OK to take a toString if the stacktrace does not occur a method - * in GenBCode or it also contains one of the whitelisted methods below. + /** It's OK to take a toString if the stacktrace does not contain a method + * from GenBCode or it also contains one of the whitelisted methods below. */ private def toStringOK = { val trace = Thread.currentThread.getStackTrace @@ -327,37 +421,38 @@ object Names { def debugString: String = toString } - class TypeName(val toTermName: TermName) extends Name { + final class TypeName(val toTermName: TermName) extends Name { + + type ThisName = TypeName - def isEmpty = toTermName.isEmpty + override def isTypeName = true + override def isTermName = false + override def toTypeName = this + override def asTypeName = this + override def asTermName = throw new ClassCastException(this + " is not a term name") - def encode = toTermName.encode.toTypeName - def decode = toTermName.decode.toTypeName - def firstPart = toTermName.firstPart - def lastPart = toTermName.lastPart + override def asSimpleName = toTermName.asSimpleName + override def toSimpleName = toTermName.toSimpleName + override def mangled = toTermName.mangled.toTypeName + override def mangledString = toTermName.mangledString - type ThisName = TypeName - def isTypeName = true - def isTermName = false - def toTypeName = this - def asTypeName = this - def asTermName = throw new ClassCastException(this + " is not a term name") + override def rewrite(f: PartialFunction[Name, Name]): ThisName = toTermName.rewrite(f).toTypeName + override def collect[T](f: PartialFunction[Name, T]): Option[T] = toTermName.collect(f) + override def mapLast(f: SimpleName => SimpleName) = toTermName.mapLast(f).toTypeName + override def mapParts(f: SimpleName => SimpleName) = toTermName.mapParts(f).toTypeName - def isSimple = toTermName.isSimple - def asSimpleName = toTermName.asSimpleName - def toSimpleName = toTermName.toSimpleName - def mangled = toTermName.toSimpleName.toTypeName + override def likeSpaced(name: Name): TypeName = name.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 - def mapParts(f: SimpleTermName => SimpleTermName) = toTermName.mapParts(f).toTypeName + override def derived(info: NameInfo): TypeName = toTermName.derived(info).toTypeName + override def exclude(kind: NameKind): TypeName = toTermName.exclude(kind).toTypeName + override def is(kind: NameKind) = toTermName.is(kind) - def likeSpaced(name: Name): TypeName = name.toTypeName + override def isEmpty = toTermName.isEmpty - def derived(info: NameInfo): TypeName = toTermName.derived(info).toTypeName - def exclude(kind: NameKind): TypeName = toTermName.exclude(kind).toTypeName - def is(kind: NameKind) = toTermName.is(kind) + override def encode = toTermName.encode.toTypeName + override def decode = toTermName.decode.toTypeName + override def firstPart = toTermName.firstPart + override def lastPart = toTermName.lastPart override def toString = toTermName.toString override def debugString = toTermName.debugString + "/T" @@ -366,54 +461,58 @@ object Names { /** A term name that's derived from an `underlying` name and that * adds `info` to it. */ - case class DerivedTermName(override val underlying: TermName, override val info: NameInfo) + final case class DerivedName(override val underlying: TermName, override val info: NameInfo) extends TermName { - def isEmpty = false - def encode: Name = underlying.encode.derived(info.map(_.encode)) - def decode: Name = underlying.decode.derived(info.map(_.decode)) - def firstPart = underlying.firstPart - def lastPart = info match { - case qual: QualifiedInfo => qual.name - case _ => underlying.lastPart - } - 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") + override def asSimpleName = throw new UnsupportedOperationException(s"$debugString is not a simple name") - private[this] var simpleName: SimpleTermName = null - def toSimpleName = { - if (simpleName == null) simpleName = termName(toString) - simpleName - } - def mangled = toSimpleName + override def toSimpleName = termName(toString) + override final def mangle = encode.toSimpleName - def rewrite(f: PartialFunction[Name, Name]): ThisName = + override def rewrite(f: PartialFunction[Name, Name]): ThisName = if (f.isDefinedAt(this)) likeSpaced(f(this)) else info match { case qual: QualifiedInfo => this case _ => underlying.rewrite(f).derived(info) } - def collect[T](f: PartialFunction[Name, T]): Option[T] = + override def collect[T](f: PartialFunction[Name, T]): Option[T] = if (f.isDefinedAt(this)) Some(f(this)) else info match { case qual: QualifiedInfo => None case _ => underlying.collect(f) } - def mapLast(f: SimpleTermName => SimpleTermName): ThisName = + override def mapLast(f: SimpleName => SimpleName): ThisName = info match { case qual: QualifiedInfo => underlying.derived(qual.map(f)) case _ => underlying.mapLast(f).derived(info) } - def mapParts(f: SimpleTermName => SimpleTermName): ThisName = + override def mapParts(f: SimpleName => SimpleName): ThisName = info match { case qual: QualifiedInfo => underlying.mapParts(f).derived(qual.map(f)) case _ => underlying.mapParts(f).derived(info) } + + override def split = info match { + case info: QualifiedInfo => + (underlying, info.name, info.kind.asInstanceOf[QualifiedNameKind].separator) + case _ => + val (prefix, suffix, separator) = underlying.split + (prefix, suffix.derived(info), separator) + } + + override def isEmpty = false + override def encode: ThisName = underlying.encode.derived(info.map(_.encode)) + override def decode: ThisName = underlying.decode.derived(info.map(_.decode)) + override def firstPart = underlying.firstPart + override def lastPart = info match { + case qual: QualifiedInfo => qual.name + case _ => underlying.lastPart + } + override def toString = info.mkString(underlying) + override def debugString = s"${underlying.debugString}[$info]" } // Nametable @@ -432,7 +531,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[SimpleTermName](InitialHashSize) + private var table = new Array[SimpleName](InitialHashSize) /** The number of defined names. */ @sharable // because it's only mutated in synchronized block of termName @@ -460,7 +559,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): SimpleTermName = synchronized { + def termName(cs: Array[Char], offset: Int, len: Int): SimpleName = synchronized { util.Stats.record("termName") val h = hashValue(cs, offset, len) & (table.size - 1) @@ -484,7 +583,7 @@ object Names { } /** Rehash chain of names */ - def rehash(name: SimpleTermName): Unit = + def rehash(name: SimpleName): Unit = if (name != null) { val oldNext = name.next val h = hashValue(chrs, name.start, name.length) & (table.size - 1) @@ -498,7 +597,7 @@ object Names { size += 1 if (size.toDouble / table.size > fillFactor) { val oldTable = table - table = new Array[SimpleTermName](table.size * 2) + table = new Array[SimpleName](table.size * 2) for (i <- 0 until oldTable.size) rehash(oldTable(i)) } } @@ -510,7 +609,7 @@ object Names { return name name = name.next } - name = new SimpleTermName(nc, len, next) + name = new SimpleName(nc, len, next) enterChars() table(h) = name incTableSize() @@ -526,7 +625,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): SimpleTermName = { + def termName(bs: Array[Byte], offset: Int, len: Int): SimpleName = { val chars = Codec.fromUTF8(bs, offset, len) termName(chars, 0, chars.length) } @@ -538,12 +637,12 @@ object Names { termName(bs, offset, len).toTypeName /** Create a term name from a string, without encoding operators */ - def termName(s: String): SimpleTermName = termName(s.toCharArray, 0, s.length) + def termName(s: String): SimpleName = 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) - table(0) = new SimpleTermName(-1, 0, null) + table(0) = new SimpleName(-1, 0, null) /** The term name represented by the empty string */ val EmptyTermName: TermName = table(0) @@ -551,14 +650,6 @@ object Names { /** The type name represented by the empty string */ val EmptyTypeName = EmptyTermName.toTypeName - // can't move CONSTRUCTOR/EMPTY_PACKAGE to `nme` because of bootstrap failures in `encode`. - val CONSTRUCTOR: TermName = termName("") - val STATIC_CONSTRUCTOR: TermName = termName("") - val EMPTY_PACKAGE: TermName = termName("") - val REFINEMENT: TermName = termName("") - - val dontEncode = Set(CONSTRUCTOR, EMPTY_PACKAGE, REFINEMENT) - 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 @@ -577,7 +668,7 @@ object Names { assert(x == y) 0 } - private def compareSimpleNames(x: SimpleTermName, y: SimpleTermName): Int = { + private def compareSimpleNames(x: SimpleName, y: SimpleName): Int = { val until = x.length min y.length var i = 0 while (i < until && x(i) == y(i)) i = i + 1 @@ -589,14 +680,14 @@ object Names { } } private def compareTermNames(x: TermName, y: TermName): Int = x match { - case x: SimpleTermName => + case x: SimpleName => y match { - case y: SimpleTermName => compareSimpleNames(x, y) + case y: SimpleName => compareSimpleNames(x, y) case _ => -1 } - case DerivedTermName(xPre, xInfo) => + case DerivedName(xPre, xInfo) => y match { - case DerivedTermName(yPre, yInfo) => + case DerivedName(yPre, yInfo) => val s = compareInfos(xInfo, yInfo) if (s == 0) compareTermNames(xPre, yPre) else s case _ => 1 diff --git a/compiler/src/dotty/tools/dotc/core/Signature.scala b/compiler/src/dotty/tools/dotc/core/Signature.scala index 4699cecf2421..fcd1e23767df 100644 --- a/compiler/src/dotty/tools/dotc/core/Signature.scala +++ b/compiler/src/dotty/tools/dotc/core/Signature.scala @@ -34,14 +34,6 @@ 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/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 444d400094e7..a7f658849dd8 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -16,14 +16,15 @@ object StdNames { /** Base strings from which synthetic names are derived. */ object str { - final val SETTER_SUFFIX = "_$eq" + final val SETTER_SUFFIX = "_=" 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 MODULE_SUFFIX = "$" + final val NAME_JOIN = "$" final val DEFAULT_GETTER = "$default$" final val LOCALDUMMY_PREFIX = ">") - val DIV = encode("/") - val EQ = encode("==") - val EQL = encode("=") - val GE = encode(">=") - val GT = encode(">") - val HASHHASH = encode("##") - val LE = encode("<=") - val LSL = encode("<<") - val LSR = encode(">>>") - val LT = encode("<") - val MINUS = encode("-") - val MOD = encode("%") - val MUL = encode("*") - val NE = encode("!=") - val OR = encode("|") + val ADD : N = "+" + val AND : N = "&" + val ASR : N = ">>" + val DIV : N = "/" + val EQ : N = "==" + val EQL : N = "=" + val GE : N = ">=" + val GT : N = ">" + val HASHHASH : N = "##" + val LE : N = "<=" + val LSL : N = "<<" + val LSR : N = ">>>" + val LT : N = "<" + val MINUS : N = "-" + val MOD : N = "%" + val MUL : N = "*" + val NE : N = "!=" + val OR : N = "|" val PLUS = ADD // technically redundant, but ADD looks funny with MINUS val SUB = MINUS // ... as does SUB with PLUS - val XOR = encode("^") - val ZAND = encode("&&") - val ZOR = encode("||") + val XOR : N = "^" + val ZAND : N = "&&" + val ZOR : N = "||" // unary operators val UNARY_PREFIX: N = "unary_" - val UNARY_~ = encode("unary_~") - val UNARY_+ = encode("unary_+") - val UNARY_- = encode("unary_-") - val UNARY_! = encode("unary_!") + val UNARY_~ : N = "unary_~" + val UNARY_+ : N = "unary_+" + val UNARY_- : N = "unary_-" + val UNARY_! : N = "unary_!" // Grouped here so Cleanup knows what tests to perform. val CommonOpNames = Set[Name](OR, XOR, AND, EQ, NE) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 6902617e0b13..e01dab87228c 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, - initName: Name, + final val name: Name, initFlags: FlagSet, initInfo: Type, initPrivateWithin: Symbol = NoSymbol) extends SingleDenotation(symbol) { @@ -125,18 +125,11 @@ 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 @@ -375,27 +368,16 @@ object SymDenotations { /** The expanded name of this denotation. */ final def expandedName(implicit ctx: Context) = 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 - legalize(name.expandedName(initial.owner)) - } + else name.expandedName(initial.owner) // need to use initial owner to disambiguate, as multiple private symbols with the same name // 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) = - initial.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. - * Never translates expansions of operators back to operator symbol. - * 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. + * are separated by `separator` strings as indicated by the given name kind. + * Drops package objects. Represents each term in the owner chain by a simple `_$`. */ def fullNameSeparated(kind: QualifiedNameKind)(implicit ctx: Context): Name = if (symbol == NoSymbol || @@ -407,17 +389,17 @@ object SymDenotations { var encl = owner while (!encl.isClass && !encl.isPackageObject) { encl = encl.owner - filler += "~" + filler += "_$" } 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) = + def qualify(n: SimpleName) = 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) + case name: SimpleName => qualify(name) + case name @ AnyQualifiedName(_, _) => qualify(name.mangled.toSimpleName) } if (isType) fn.toTypeName else fn.toTermName } @@ -509,7 +491,7 @@ object SymDenotations { * step for creating Refinement types. */ final def isRefinementClass(implicit ctx: Context): Boolean = - name.decode == tpnme.REFINE_CLASS + name == tpnme.REFINE_CLASS /** Is this symbol a package object or its module class? */ def isPackageObject(implicit ctx: Context): Boolean = { @@ -1218,12 +1200,12 @@ object SymDenotations { class ClassDenotation private[SymDenotations] ( symbol: Symbol, ownerIfExists: Symbol, - initName: Name, + name: Name, initFlags: FlagSet, initInfo: Type, initPrivateWithin: Symbol, initRunId: RunId) - extends SymDenotation(symbol, ownerIfExists, initName, initFlags, initInfo, initPrivateWithin) { + extends SymDenotation(symbol, ownerIfExists, name, 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 9e19c5f05eec..24e0d9841801 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -41,7 +41,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.decode, flags, completer, assocFile = completer.sourceFileOrNull) enterNew(owner, cls, completer, scope) } @@ -51,7 +51,7 @@ class SymbolLoaders { owner: Symbol, name: PreName, completer: SymbolLoader, modFlags: FlagSet = EmptyFlags, clsFlags: FlagSet = EmptyFlags, scope: Scope = EmptyScope)(implicit ctx: Context): Symbol = { val module = ctx.newModuleSymbol( - owner, name.toTermName, modFlags, clsFlags, + owner, name.toTermName.decode, modFlags, clsFlags, (module, _) => completer.proxy withDecls newScope withSourceModule (_ => module), assocFile = completer.sourceFileOrNull) enterNew(owner, module, completer, scope) @@ -186,7 +186,7 @@ class SymbolLoaders { private[core] val currentDecls: MutableScope = new PackageScope() - def isFlatName(name: SimpleTermName) = name.lastIndexOf('$', name.length - 2) >= 0 + def isFlatName(name: SimpleName) = name.lastIndexOf('$', name.length - 2) >= 0 def isFlatName(classRep: ClassRepresentation) = { val idx = classRep.name.indexOf('$') diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 1eb90b8ebe48..b8a7d2aeed97 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -536,7 +536,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean } } catch { case ex: AssertionError => - println(s"no sig for $tp") + println(s"no sig for $tp because of ${ex.printStackTrace()}") throw ex } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 32fb28f405cc..9d6bc0a01c55 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3444,7 +3444,7 @@ object Types { abstract class FlexType extends UncachedGroundType with ValueType class ErrorType(_msg: => Message) extends FlexType { - val msg = _msg + def msg = _msg } object UnspecifiedErrorType extends ErrorType("unspecified error") diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index eef8faf8a233..c23ff6d2affe 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: SimpleTermName = _ // JVM name of the current class + protected var currentClassName: SimpleName = _ // JVM name of the current class protected var classTParams = Map[Name,Symbol]() classRoot.info = (new NoCompleter).withDecls(instanceScope) @@ -47,7 +47,7 @@ class ClassfileParser( private def currentIsTopLevel(implicit ctx: Context) = classRoot.owner is Flags.PackageClass - private def mismatchError(className: SimpleTermName) = + private def mismatchError(className: SimpleName) = 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 { @@ -92,7 +92,9 @@ class ClassfileParser( val nameIdx = in.nextChar currentClassName = pool.getClassName(nameIdx) - if (currentIsTopLevel && currentClassName != classRoot.fullName.toSimpleName) + if (currentIsTopLevel && + currentClassName != classRoot.fullName.toSimpleName && + currentClassName != classRoot.fullName.encode.toSimpleName) mismatchError(currentClassName) addEnclosingTParams() @@ -252,14 +254,14 @@ 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: SimpleTermName, owner: Symbol = null)(implicit ctx: Context): Type = { + private def sigToType(sig: SimpleName, 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): SimpleTermName = { + def subName(isDelimiter: Char => Boolean): SimpleName = { val start = index while (!isDelimiter(sig(index))) { index += 1 } sig.slice(start, index) @@ -899,7 +901,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[SimpleTermName](len) + private val internalized = new Array[SimpleName](len) { var i = 1 while (i < starts.length) { @@ -926,12 +928,12 @@ class ClassfileParser( } /** Return the name found at given index. */ - def getName(index: Int): SimpleTermName = { + def getName(index: Int): SimpleName = { if (index <= 0 || len <= index) errorBadIndex(index) values(index) match { - case name: SimpleTermName => name + case name: SimpleName => name case null => val start = starts(index) if (in.buf(start).toInt != CONSTANT_UTF8) errorBadTag(start) @@ -946,7 +948,7 @@ class ClassfileParser( new DataInputStream(new ByteArrayInputStream(bytes, offset, len)).readUTF /** Return the name found at given index in the constant pool, with '/' replaced by '.'. */ - def getExternalName(index: Int): SimpleTermName = { + def getExternalName(index: Int): SimpleName = { if (index <= 0 || len <= index) errorBadIndex(index) @@ -975,7 +977,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): SimpleTermName = { + def getClassName(index: Int): SimpleName = { val start = starts(index) if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start) getExternalName(in.getChar(start + 1)) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index 270d6be56d8f..df83b8d50573 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, SimpleTermName, DerivedTermName} +import Names.{Name, chrs, SimpleName, DerivedName} import NameOps.NameDecorator import NameKinds._ import Decorators._ @@ -31,7 +31,7 @@ class NameBuffer extends TastyBuffer(10000) { case AnyUniqueName(original, separator, num) => nameIndex(separator.toTermName) if (!original.isEmpty) nameIndex(original) - case DerivedTermName(original, _) => + case DerivedName(original, _) => nameIndex(original) case _ => } @@ -56,7 +56,7 @@ class NameBuffer extends TastyBuffer(10000) { val tag = name.toTermName.info.kind.tag writeByte(tag) name.toTermName match { - case name: SimpleTermName => + case name: SimpleName => val bytes = if (name.length == 0) new Array[Byte](0) else Codec.toUTF8(chrs, name.start, name.length) @@ -70,15 +70,13 @@ class NameBuffer extends TastyBuffer(10000) { writeNat(num) if (!original.isEmpty) writeNameRef(original) } - 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) }, if ((params.length + 2) * maxIndexWidth <= maxNumInByte) 1 else 2) - case DerivedTermName(original, _) => + case DerivedName(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 b564c09e996d..7ef92f038fab 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -29,16 +29,29 @@ Macro-format: Section = NameRef Length Bytes Length = Nat // length of rest of entry in bytes - Name = UTF8 Length UTF8-CodePoint* - 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 - ... + Name = UTF8 Length UTF8-CodePoint* + QUALIFIED Length qualified_NameRef selector_NameRef + FLATTENED Length qualified_NameRef selector_NameRef + EXPANDED Length qualified_NameRef selector_NameRef + EXPANDEDPREFIX Length qualified_NameRef selector_NameRef + TRAITSETTER Length qualified_NameRef selector_NameRef + UNIQUE Length separator_NameRef uniqid_Nat underlying_NameRef? + DEFAULTGETTER Length underlying_NameRef index_Nat + VARIANT Length underlying_NameRef variance_Nat // 0: Contravariant, 1: Covariant + OUTERSELECT Length underlying_NameRef nhops_Nat // a reference to `nhops` selections, followed by `underlying` + + SUPERACCESSOR Length underlying_NameRef + PROTECTEDACCESSOR Length underlying_NameRef + PROTECTEDSETTER Length underlying_NameRef + INITIALIZER Length underlying_NameRef + SHADOWED Length underlying_NameRef + AVOIDCLASH Length underlying_NameRef + DIRECT Length underlying_NameRef + FIELD Length underlying_NameRef + EXTMETH Length underlying_NameRef + OBJECTVAR Length underlying_NameRef + OBJECTCLASS Length underlying_NameRef + SIGNED Length original_NameRef resultSig_NameRef paramSig_NameRef* NameRef = Nat // ordinal number of name in name table, starting from 1. @@ -238,8 +251,7 @@ object TastyFormat { final val AVOIDCLASH = 30 final val DIRECT = 31 final val FIELD = 32 - final val SETTER = 33 - final val EXTMETH = 34 + final val EXTMETH = 33 final val OBJECTVAR = 39 final val OBJECTCLASS = 40 @@ -428,12 +440,26 @@ object TastyFormat { case QUALIFIED => "QUALIFIED" case FLATTENED => "FLATTENED" case EXPANDED => "EXPANDED" - case SIGNED => "SIGNED" - case OBJECTCLASS => "OBJECTCLASS" - case SUPERACCESSOR => "SUPERACCESSOR" + case EXPANDPREFIX => "EXPANDPREFIX" + case TRAITSETTER => "TRAITSETTER" + case UNIQUE => "UNIQUE" case DEFAULTGETTER => "DEFAULTGETTER" - case SHADOWED => "SHADOWED" case VARIANT => "VARIANT" + case OUTERSELECT => "OUTERSELECT" + + case SUPERACCESSOR => "SUPERACCESSOR" + case PROTECTEDACCESSOR => "PROTECTEDACCESSOR" + case PROTECTEDSETTER => "PROTECTEDSETTER" + case INITIALIZER => "INITIALIZER" + case SHADOWED => "SHADOWED" + case AVOIDCLASH => "AVOIDCLASH" + case DIRECT => "DIRECT" + case FIELD => "FIELD" + case EXTMETH => "EXTMETH" + case OBJECTVAR => "OBJECTVAR" + case OBJECTCLASS => "OBJECTCLASS" + + case SIGNED => "SIGNED" } def astTagToString(tag: Int): String = tag match { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala index 37a3c2e762ad..67f0c763755f 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala @@ -57,12 +57,8 @@ class TastyUnpickler(reader: TastyReader) { val originals = until(end)(readName()) val original = if (originals.isEmpty) EmptyTermName else originals.head uniqueNameKindOfSeparator(separator)(original, num) - case DEFAULTGETTER => - DefaultGetterName(readName(), readNat()) - case VARIANT => - VariantName(readName(), readNat() - 1) - case OUTERSELECT => - OuterSelectName(readName(), readNat()) + case DEFAULTGETTER | VARIANT | OUTERSELECT => + numberedNameKindOfTag(tag)(readName(), readNat()) case SIGNED => val original = readName() val result = readName().toTypeName diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 460af7c0ceea..602e5f2c7fd1 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -417,7 +417,6 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val end = readEnd() var name: Name = readName() if (tag == TYPEDEF || tag == TYPEPARAM) name = name.toTypeName - val mname = name.mangled skipParams() val ttag = nextUnsharedTag val isAbsType = isAbstractType(ttag) @@ -433,10 +432,9 @@ 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.mangled == mname) match { + roots.find(root => (root.owner eq ctx.owner) && root.name == name) 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 1db3ebcb066c..712148756c7e 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -227,7 +227,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas val major = readNat() val minor = readNat() if (major != MajorVersion || minor > MinorVersion) - throw new IOException("Scala signature " + classRoot.fullName.decode + + throw new IOException("Scala signature " + classRoot.fullName + " has wrong version\n expected: " + MajorVersion + "." + MinorVersion + "\n found: " + major + "." + minor + @@ -338,7 +338,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas def atEnd = readIndex == end def readExtSymbol(): Symbol = { - val name = readNameRef() + val name = readNameRef().decode val owner = if (atEnd) loadingMirror.RootClass else readSymbolRef() def adjust(denot: Denotation) = { @@ -401,7 +401,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas // println(owner.info.decls.toList.map(_.debugString).mkString("\n ")) // !!! DEBUG // } // (5) Create a stub symbol to defer hard failure a little longer. - System.err.println(i"***** missing reference, looking for $name in $owner") + System.err.println(i"***** missing reference, looking for ${name.debugString} in $owner") System.err.println(i"decls = ${owner.info.decls}") owner.info.decls.checkConsistent() if (slowSearch(name).exists) @@ -439,7 +439,7 @@ 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.isSimple) { + if ((flags is Scala2ExpandedName)) { name = name.unmangle(ExpandedName) flags = flags &~ Scala2ExpandedName } @@ -447,9 +447,9 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas name = name.asTermName.unmangle(SuperAccessorName) flags = flags &~ Scala2SuperAccessor } + name = name.mapLast(_.decode) - val mname = name.mangled - def nameMatches(rootName: Name) = mname == rootName.mangled + def nameMatches(rootName: Name) = name == rootName 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) @@ -459,7 +459,6 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas //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 diff --git a/compiler/src/dotty/tools/dotc/parsing/CharArrayReader.scala b/compiler/src/dotty/tools/dotc/parsing/CharArrayReader.scala index e20eb392d52c..0ecd43263aee 100644 --- a/compiler/src/dotty/tools/dotc/parsing/CharArrayReader.scala +++ b/compiler/src/dotty/tools/dotc/parsing/CharArrayReader.scala @@ -120,7 +120,7 @@ abstract class CharArrayReader { self => def isAtEnd = charOffset >= buf.length /** A new reader that takes off at the current character position */ - def lookaheadReader = new CharArrayLookaheadReader + def lookaheadReader() = new CharArrayLookaheadReader class CharArrayLookaheadReader extends CharArrayReader { val buf = self.buf diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala index 47f201a09a0d..323308caa955 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -111,7 +111,7 @@ object JavaParsers { def makeTemplate(parents: List[Tree], stats: List[Tree], tparams: List[TypeDef], needsDummyConstr: Boolean) = { def pullOutFirstConstr(stats: List[Tree]): (Tree, List[Tree]) = stats match { - case (meth: DefDef) :: rest if meth.name == CONSTRUCTOR => (meth, rest) + case (meth: DefDef) :: rest if meth.name == nme.CONSTRUCTOR => (meth, rest) case first :: rest => val (constr, tail) = pullOutFirstConstr(rest) (constr, first :: tail) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index ce74fbedb3c8..d207af862b43 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -266,7 +266,7 @@ object Parsers { def accept(token: Int): Int = { val offset = in.offset if (in.token != token) { - syntaxErrorOrIncomplete(ExpectedTokenButFound(token, in.token, in.name)) + syntaxErrorOrIncomplete(ExpectedTokenButFound(token, in.token)) } if (in.token == token) in.nextToken() offset @@ -477,7 +477,7 @@ object Parsers { in.nextToken() name } else { - syntaxErrorOrIncomplete(ExpectedTokenButFound(IDENTIFIER, in.token, in.name)) + syntaxErrorOrIncomplete(ExpectedTokenButFound(IDENTIFIER, in.token)) nme.ERROR } diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index b0fa8d760ec3..b37d5e774c4c 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -7,6 +7,7 @@ import core.StdNames._, core.Comments._ import util.SourceFile import java.lang.Character.isDigit import util.Chars._ +import util.NameTransformer.avoidIllegalChars import Tokens._ import scala.annotation.{ switch, tailrec } import scala.collection.mutable @@ -37,7 +38,7 @@ object Scanners { var lastOffset: Offset = 0 /** the name of an identifier */ - var name: SimpleTermName = null + var name: SimpleName = null /** the string value of a literal */ var strVal: String = null @@ -179,7 +180,7 @@ object Scanners { private[this] var docstringMap: SortedMap[Int, Comment] = SortedMap.empty private[this] def addComment(comment: Comment): Unit = { - val lookahead = lookaheadReader + val lookahead = lookaheadReader() def nextPos: Int = (lookahead.getc(): @switch) match { case ' ' | '\t' => nextPos case CR | LF | FF => @@ -622,6 +623,7 @@ object Scanners { if (ch == '`') { nextChar() finishNamed(BACKQUOTED_IDENT) + name = avoidIllegalChars(name) if (name.length == 0) error("empty quoted identifier") else if (name == nme.WILDCARD) @@ -861,7 +863,7 @@ object Scanners { nextChar() } if (ch == 'e' || ch == 'E') { - val lookahead = lookaheadReader + val lookahead = lookaheadReader() lookahead.nextChar() if (lookahead.ch == '+' || lookahead.ch == '-') { lookahead.nextChar() @@ -905,36 +907,10 @@ object Scanners { } token = INTLIT if (base == 10 && ch == '.') { - val isDefinitelyNumber = { - val lookahead = lookaheadReader - val c = lookahead.getc() - (c: @switch) match { - /** Another digit is a giveaway. */ - case '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => - true - - /** Backquoted idents like 22.`foo`. */ - case '`' => - false - - /** These letters may be part of a literal, or a method invocation on an Int. - */ - case 'd' | 'D' | 'f' | 'F' => - !isIdentifierPart(lookahead.getc()) - - /** A little more special handling for e.g. 5e7 */ - case 'e' | 'E' => - val ch = lookahead.getc() - !isIdentifierPart(ch) || (isDigit(ch) || ch == '+' || ch == '-') - - case x => - !isIdentifierStart(x) - } - } - if (isDefinitelyNumber) { - putChar(ch) - nextChar() - getFraction() + val lookahead = lookaheadReader() + lookahead.nextChar() + if ('0' <= lookahead.ch && lookahead.ch <= '9') { + putChar('.'); nextChar(); getFraction() } } else (ch: @switch) match { case 'e' | 'E' | 'f' | 'F' | 'd' | 'D' => diff --git a/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala b/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala index c99826488123..97b04669221b 100644 --- a/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala +++ b/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala @@ -54,7 +54,7 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(implicit ctx: Cont val __Text: TermName = "Text" val _buf: TermName = "$buf" val _md: TermName = "$md" - val _plus: TermName = "$amp$plus" + val _plus: TermName = "&+" val _tmpscope: TermName = "$tmpscope" val _xml: TermName = "xml" } diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 03e83e93e001..8aec867921eb 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -208,9 +208,7 @@ class PlainPrinter(_ctx: Context) extends Printer { protected def ParamRefNameString(param: ParamRef): String = ParamRefNameString(param.binder.paramNames(param.paramNum)) - /** The name of the symbol without a unique id. Under refined printing, - * the decoded original name. - */ + /** The name of the symbol without a unique id. */ protected def simpleNameString(sym: Symbol): String = nameString(sym.name) /** If -uniqid is set, the hashcode of the lambda type, after a # */ diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index c3f36cc463f7..fcda277012f3 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -60,7 +60,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { protected val PrintableFlags = (SourceModifierFlags | Label | Module | Local).toCommonFlags override def nameString(name: Name): String = - if (ctx.settings.debugNames.value) name.debugString else name.decode.toString + if (ctx.settings.debugNames.value) name.debugString else name.toString override protected def simpleNameString(sym: Symbol): String = { val name = if (ctx.property(XprintMode).isEmpty) sym.originalName else sym.name @@ -157,7 +157,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { withoutPos(super.toText(tp)) case tp: SelectionProto => return "?{ " ~ toText(tp.name) ~ - (" " provided !tp.name.toSimpleName.decode.last.isLetterOrDigit) ~ + (" " provided !tp.name.toSimpleName.last.isLetterOrDigit) ~ ": " ~ toText(tp.memberProto) ~ " }" case tp: ViewProto => return toText(tp.argType) ~ " ?=>? " ~ toText(tp.resultType) diff --git a/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala b/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala index eed75fe886b7..98f098fbcbf3 100644 --- a/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala +++ b/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala @@ -742,7 +742,7 @@ class CompilingInterpreter( override def shouldShowResult(req: Request): Boolean = !statement.mods.is(Flags.AccessFlags) && !(isGeneratedVarName(statement.name.toString) && - req.typeOf(statement.name.encode) == "Unit") + req.typeOf(statement.name) == "Unit") } @@ -812,7 +812,7 @@ class CompilingInterpreter( /** Print out lhs instead of the generated varName */ override def resultExtractionCode(req: Request, code: PrintWriter): Unit = { code.print(" + \"" + lhs.show + ": " + - string2code(req.typeOf(helperName.encode)) + + string2code(req.typeOf(helperName)) + " = \" + " + string2code(req.fullPath(helperName)) + " + \"\\n\"") diff --git a/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index dbaa68f30fda..10ec402b8432 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -41,18 +41,25 @@ class ConsoleReporter( } /** Show prompt if `-Xprompt` is passed as a flag to the compiler */ - def displayPrompt()(implicit ctx: Context): Unit = { - printMessage("\na)bort, s)tack, r)esume: ") - flush() + def displayPrompt(): Unit = { + writer.println() + writer.print("a)bort, s)tack, r)esume: ") + writer.flush() if (reader != null) { - val response = reader.read().asInstanceOf[Char].toLower - if (response == 'a' || response == 's') { - Thread.dumpStack() - if (response == 'a') - sys.exit(1) + def loop(): Unit = reader.read match { + case 'a' | 'A' => + new Throwable().printStackTrace(writer) + System.exit(1) + case 's' | 'S' => + new Throwable().printStackTrace(writer) + writer.println() + writer.flush() + case 'r' | 'R' => + () + case _ => + loop() } - print("\n") - flush() + loop() } } diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index b3c49a333822..a862825d0263 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1057,7 +1057,7 @@ object messages { |""".stripMargin } - case class ExpectedTokenButFound(expected: Token, found: Token, foundName: TermName)(implicit ctx: Context) + case class ExpectedTokenButFound(expected: Token, found: Token)(implicit ctx: Context) extends Message(ExpectedTokenButFoundID) { val kind = "Syntax" @@ -1065,9 +1065,7 @@ object messages { if (Tokens.isIdentifier(expected)) "an identifier" else Tokens.showToken(expected) - private val foundText = - if (foundName != null) hl"`${foundName.show}`" - else Tokens.showToken(found) + private val foundText = Tokens.showToken(found) val msg = hl"""${expectedText} expected, but ${foundText} found""" @@ -1077,10 +1075,7 @@ object messages { |If you necessarily want to use $foundText as identifier, you may put it in backticks.""".stripMargin else "" - - val explanation = - s"""|The text ${foundText} may not occur at that position, the compiler expected ${expectedText}.$ifKeyword - |""".stripMargin + val explanation = s"$ifKeyword" } case class MixedLeftAndRightAssociativeOps(op1: Name, op2: Name, op2LeftAssoc: Boolean)(implicit ctx: Context) diff --git a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala index ba764a91069c..81a114e03fbc 100644 --- a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -8,7 +8,7 @@ import core.Contexts._ import core.Types._ import core.Flags._ import core.Decorators._ -import core.StdNames.nme +import core.StdNames.{nme, str} import core.Names._ import core.NameOps._ import core.NameKinds.ExpandPrefixName @@ -334,7 +334,7 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform private def newName(sym: Symbol)(implicit ctx: Context): Name = if (sym.isAnonymousFunction && sym.owner.is(Method, butNot = Label)) sym.name.rewrite { - case name: SimpleTermName => ExpandPrefixName(sym.owner.name.asTermName, name) + case name: SimpleName => ExpandPrefixName(sym.owner.name.asTermName, name) }.freshened else sym.name.freshened diff --git a/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala b/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala index 652320639ecf..0942c0b4af11 100644 --- a/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala +++ b/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala @@ -9,6 +9,7 @@ import dotty.tools.dotc.core.Decorators._ import dotty.tools.dotc.core.NameOps._ import dotty.tools.dotc.core.{Flags, Names} import dotty.tools.dotc.core.Names.Name +import dotty.tools.dotc.core.StdNames.nme import dotty.tools.dotc.core.Phases.Phase import dotty.tools.dotc.core.Symbols._ import dotty.tools.dotc.core.Types.MethodType @@ -42,7 +43,7 @@ class MoveStatics extends MiniPhaseTransform with SymTransformer { thisTransform val newBodyWithStaticConstr = if (staticFields.nonEmpty) { /* do NOT put Flags.JavaStatic here. It breaks .enclosingClass */ - val staticCostructor = ctx.newSymbol(orig.symbol, Names.STATIC_CONSTRUCTOR, Flags.Synthetic | Flags.Method | Flags.Private, MethodType(Nil, defn.UnitType)) + val staticCostructor = ctx.newSymbol(orig.symbol, nme.STATIC_CONSTRUCTOR, Flags.Synthetic | Flags.Method | Flags.Private, MethodType(Nil, defn.UnitType)) staticCostructor.addAnnotation(Annotation(defn.ScalaStaticAnnot)) staticCostructor.entered diff --git a/compiler/src/dotty/tools/dotc/transform/Pickler.scala b/compiler/src/dotty/tools/dotc/transform/Pickler.scala index bf37067b1c2e..e62cb0225b89 100644 --- a/compiler/src/dotty/tools/dotc/transform/Pickler.scala +++ b/compiler/src/dotty/tools/dotc/transform/Pickler.scala @@ -11,6 +11,7 @@ import Periods._ import Phases._ import Symbols._ import Flags.Module +import reporting.ThrowingReporter import collection.mutable /** This phase pickles trees */ @@ -77,6 +78,7 @@ class Pickler extends Phase { testUnpickler( ctx.fresh .setPeriod(Period(ctx.runId + 1, FirstPhaseId)) + .setReporter(new ThrowingReporter(ctx.reporter)) .addMode(Mode.ReadPositions)) result } diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index bacb88091e50..049ccb22e00d 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -265,7 +265,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran case Import(expr, selectors) => val exprTpe = expr.tpe def checkIdent(ident: untpd.Ident): Unit = { - val name = ident.name.asTermName.encode + val name = ident.name.asTermName if (name != nme.WILDCARD && !exprTpe.member(name).exists && !exprTpe.member(name.toTypeName).exists) ctx.error(s"${ident.name} is not a member of ${expr.show}", ident.pos) } diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala index e7936e8d95b4..de0242f79b27 100644 --- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -19,7 +19,6 @@ 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. @@ -96,7 +95,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 SuperAccessorName(memberName) = acc.name.unexpandedName // dotty deviation: ": Name" needed otherwise pattern type is neither a subtype nor a supertype of selector type + val SuperAccessorName(memberName) = acc.name.unexpandedName 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/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index 84a32f93bf08..0e723c58e720 100644 --- a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -107,7 +107,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { // ParamForwaders as installed ParamForwarding.scala do use super calls to vals ctx.error(s"super may be not be used on ${sym.underlyingSymbol}", sel.pos) else if (isDisallowed(sym)) - ctx.error(s"super not allowed here: use this.${sel.name.decode} instead", sel.pos) + ctx.error(s"super not allowed here: use this.${sel.name} instead", sel.pos) else if (sym is Deferred) { val member = sym.overridingSymbol(clazz) if (!mix.name.isEmpty || diff --git a/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala b/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala index d37e47d49ba6..c8bef28dcd66 100644 --- a/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala @@ -82,7 +82,7 @@ class SyntheticMethods(thisTransformer: DenotTransformer) { ref(defn.runtimeMethodRef("_" + sym.name.toString)).appliedToArgs(This(clazz) :: vrefss.head) def ownName(vrefss: List[List[Tree]]): Tree = - Literal(Constant(clazz.name.stripModuleClassSuffix.decode.toString)) + Literal(Constant(clazz.name.stripModuleClassSuffix.toString)) def syntheticRHS(implicit ctx: Context): List[List[Tree]] => Tree = synthetic.name match { case nme.hashCode_ if isDerivedValueClass(clazz) => vrefss => valueHashCodeBody diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index d553868fb813..2205a104ef9c 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -25,6 +25,7 @@ import reporting.ThrowingReporter import ast.Trees._ import ast.{tpd, untpd} import util.SourcePosition +import util.Chars._ import collection.mutable import ProtoTypes._ import config.Printers @@ -51,11 +52,9 @@ class TreeChecker extends Phase with SymTransformer { private val seenClasses = collection.mutable.HashMap[String, Symbol]() private val seenModuleVals = collection.mutable.HashMap[String, Symbol]() - def isValidJVMName(name: Name) = - !name.toString.exists(c => c == '.' || c == ';' || c =='[' || c == '/') + def isValidJVMName(name: Name) = name.toString.forall(isValidJVMChar) - def isValidJVMMethodName(name: Name) = - !name.toString.exists(c => c == '.' || c == ';' || c =='[' || c == '/' || c == '<' || c == '>') + def isValidJVMMethodName(name: Name) = name.toString.forall(isValidJVMMethodChar) def printError(str: String)(implicit ctx: Context) = { ctx.echo(Console.RED + "[error] " + Console.WHITE + str) @@ -149,7 +148,7 @@ class TreeChecker extends Phase with SymTransformer { def withDefinedSym[T](tree: untpd.Tree)(op: => T)(implicit ctx: Context): T = tree match { case tree: untpd.DefTree => val sym = tree.symbol - assert(isValidJVMName(sym.name), s"${sym.fullName} name is invalid on jvm") + assert(isValidJVMName(sym.name.encode), s"${sym.name.debugString} name is invalid on jvm") everDefinedSyms.get(sym) match { case Some(t) => if (t ne tree) @@ -385,8 +384,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.name.debugString} name is invalid on jvm") + if (!sym.isClassConstructor && !(sym.name eq nme.STATIC_CONSTRUCTOR)) + assert(isValidJVMMethodName(sym.name.encode), s"${sym.name.debugString} name is invalid on jvm") ddef.vparamss.foreach(_.foreach { vparam => assert(vparam.symbol.is(Param), diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 6bfbc2b70eaf..1ce97098a61b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -257,7 +257,7 @@ class Namer { typer: Typer => /** Add moduleClass/sourceModule to completer if it is for a module val or class */ def adjustIfModule(completer: LazyType, tree: MemberDef) = - if (tree.mods is Module) ctx.adjustModuleCompleter(completer, tree.name.encode) + if (tree.mods is Module) ctx.adjustModuleCompleter(completer, tree.name) else completer typr.println(i"creating symbol for $tree in ${ctx.mode}") @@ -280,7 +280,7 @@ class Namer { typer: Typer => tree match { case tree: TypeDef if tree.isClassDef => - val name = checkNoConflict(tree.name.encode).toTypeName + val name = checkNoConflict(tree.name).asTypeName val flags = checkFlags(tree.mods.flags &~ Implicit) val cls = recordSym(ctx.newClassSymbol( ctx.owner, name, flags, @@ -289,7 +289,7 @@ class Namer { typer: Typer => cls.completer.asInstanceOf[ClassCompleter].init() cls case tree: MemberDef => - val name = checkNoConflict(tree.name.encode) + val name = checkNoConflict(tree.name) val flags = checkFlags(tree.mods.flags) val isDeferred = lacksDefinition(tree) val deferred = if (isDeferred) Deferred else EmptyFlags @@ -566,8 +566,8 @@ class Namer { typer: Typer => /** Create links between companion object and companion class */ def createLinks(classTree: TypeDef, moduleTree: TypeDef)(implicit ctx: Context) = { - val claz = ctx.effectiveScope.lookup(classTree.name.encode) - val modl = ctx.effectiveScope.lookup(moduleTree.name.encode) + val claz = ctx.effectiveScope.lookup(classTree.name) + val modl = ctx.effectiveScope.lookup(moduleTree.name) ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, claz, modl).entered ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, modl, claz).entered } @@ -609,10 +609,10 @@ class Namer { typer: Typer => // matters. if (ctx.owner.is(PackageClass)) { for (cdef @ TypeDef(moduleName, _) <- moduleDef.values) { - val moduleSym = ctx.effectiveScope.lookup(moduleName.encode) + val moduleSym = ctx.effectiveScope.lookup(moduleName) if (moduleSym.isDefinedInCurrentRun) { val className = moduleName.stripModuleClassSuffix.toTypeName - val classSym = ctx.effectiveScope.lookup(className.encode) + val classSym = ctx.effectiveScope.lookup(className) if (!classSym.isDefinedInCurrentRun) { val absentClassSymbol = ctx.newClassSymbol(ctx.owner, className, EmptyFlags, _ => NoType) enterSymbol(absentClassSymbol) diff --git a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala index 73e676b574e6..67fee03c1964 100644 --- a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala @@ -82,8 +82,6 @@ class ReTyper extends Typer { override def ensureConstrCall(cls: ClassSymbol, parents: List[Tree])(implicit ctx: Context): List[Tree] = parents - override def encodeName(tree: untpd.NameTree)(implicit ctx: Context) = tree - override def handleUnexpectedFunType(tree: untpd.Apply, fun: Tree)(implicit ctx: Context): Tree = fun.tpe match { case mt: MethodType => val args: List[Tree] = tree.args.zipWithConserve(mt.paramInfos)(typedExpr(_, _)).asInstanceOf[List[Tree]] diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 91e8859bb506..ebe79cdb4f41 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -698,7 +698,7 @@ object RefChecks { if (!concrOvers.isEmpty) ctx.deprecationWarning( symbol.toString + " overrides concrete, non-deprecated symbol(s):" + - concrOvers.map(_.name.decode).mkString(" ", ", ", ""), tree.pos) + concrOvers.map(_.name).mkString(" ", ", ", ""), tree.pos) } } diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index ec6fb1770000..71806facfd44 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -216,7 +216,7 @@ trait TypeAssigner { else if (site.derivesFrom(defn.DynamicClass) && !Dynamic.isDynamicMethod(name)) { TryDynamicCallType } else { - if (site.isErroneous) UnspecifiedErrorType + if (site.isErroneous || name.toTermName == nme.ERROR) UnspecifiedErrorType else { def kind = if (name.isTypeName) "type" else "value" def addendum = diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 06a225d77ac8..e3be171f080c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -197,7 +197,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit * from given `site` and `selectors`. */ def namedImportRef(imp: ImportInfo)(implicit ctx: Context): Type = { - val Name = name.toTermName.decode + val Name = name.toTermName def recur(selectors: List[untpd.Tree]): Type = selectors match { case selector :: rest => def checkUnambiguous(found: Type) = { @@ -354,6 +354,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit // awaiting a better implicits based solution for library-supported xml return ref(defn.XMLTopScopeModuleRef) } + else if (name.toTermName == nme.ERROR) + UnspecifiedErrorType else errorType(new MissingIdent(tree, kind, name.show), tree.pos) @@ -1572,15 +1574,12 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit !ctx.isAfterTyper) makeImplicitFunction(xtree, pt) else xtree match { - case xtree: untpd.NameTree => typedNamed(encodeName(xtree), pt) + case xtree: untpd.NameTree => typedNamed(xtree, pt) case xtree => typedUnnamed(xtree) } } } - protected def encodeName(tree: untpd.NameTree)(implicit ctx: Context): untpd.NameTree = - untpd.rename(tree, tree.name.encode) - protected def makeImplicitFunction(tree: untpd.Tree, pt: Type)(implicit ctx: Context): Tree = { val defn.FunctionOf(formals, resType, true) = pt.dealias val paramTypes = formals.map(fullyDefinedType(_, "implicit function parameter", tree.pos)) diff --git a/compiler/src/dotty/tools/dotc/util/Chars.scala b/compiler/src/dotty/tools/dotc/util/Chars.scala index 6f95b87c474b..29a88aeb13ea 100644 --- a/compiler/src/dotty/tools/dotc/util/Chars.scala +++ b/compiler/src/dotty/tools/dotc/util/Chars.scala @@ -77,6 +77,12 @@ object Chars { chtp == JCharacter.MATH_SYMBOL.toInt || chtp == JCharacter.OTHER_SYMBOL.toInt } + def isValidJVMChar(c: Char) = + !(c == '.' || c == ';' || c =='[' || c == '/') + + def isValidJVMMethodChar(c: Char) = + !(c == '.' || c == ';' || c =='[' || c == '/' || c == '<' || c == '>') + private final val otherLetters = Set[Char]('\u0024', '\u005F') // '$' and '_' private final val letterGroups = { import JCharacter._ diff --git a/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala b/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala index 5dbec3e5a586..5882eb4b9cd9 100644 --- a/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala +++ b/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala @@ -22,10 +22,9 @@ object FreshNameCreator { * call to this function (provided the prefix does not end in a digit). */ def newName(prefix: TermName, unique: UniqueNameKind): TermName = { - val key = str.sanitize(prefix.toString + unique.separator) + val key = str.sanitize(prefix.toString) + unique.separator counters(key) += 1 - val counter = counters(key) - prefix.derived(unique.NumberedInfo(counter)) + prefix.derived(unique.NumberedInfo(counters(key))) } } } diff --git a/compiler/src/dotty/tools/dotc/util/NameTransformer.scala b/compiler/src/dotty/tools/dotc/util/NameTransformer.scala index 52f8e6ec0bb4..18c5b09823b2 100644 --- a/compiler/src/dotty/tools/dotc/util/NameTransformer.scala +++ b/compiler/src/dotty/tools/dotc/util/NameTransformer.scala @@ -1,38 +1,24 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package dotty.tools.dotc +package dotty.tools +package dotc package util import core.Names._ import core.Decorators._ +import collection.mutable +import util.Chars.isValidJVMMethodChar /** Provides functions to encode and decode Scala symbolic names. - * Also provides some constants. */ object NameTransformer { - // XXX Short term: providing a way to alter these without having to recompile - // the compiler before recompiling the compiler. - val MODULE_SUFFIX_STRING = sys.props.getOrElse("SCALA_MODULE_SUFFIX_STRING", "$") - val NAME_JOIN_STRING = sys.props.getOrElse("SCALA_NAME_JOIN_STRING", "$") - val MODULE_INSTANCE_NAME = "MODULE$" private val nops = 128 - private val ncodes = 26 * 26 - private class OpCodes(val op: Char, val code: String, val next: OpCodes) + @sharable private val op2code = new Array[String](nops) + @sharable private val str2op = new mutable.HashMap[String, Char] - private val op2code = new Array[String](nops) - private val code2op = new Array[OpCodes](ncodes) private def enterOp(op: Char, code: String) = { op2code(op) = code - val c = (code.charAt(1) - 'a') * 26 + code.charAt(2) - 'a' - code2op(c) = new OpCodes(op, code, code2op(c)) + str2op(code) = op } /* Note: decoding assumes opcodes are only ever lowercase. */ @@ -55,108 +41,76 @@ object NameTransformer { enterOp('?', "$qmark") enterOp('@', "$at") - /** Replace operator symbols by corresponding `\$opname`. + /** Expand characters that are illegal as JVM method names by `$u`, followed + * by the character's unicode expansion. + */ + def avoidIllegalChars(name: SimpleName) = { + var i = name.length - 1 + while (i >= 0 && isValidJVMMethodChar(name(i))) i -= 1 + if (i >= 0) + termName( + name.toString.flatMap(ch => + if (isValidJVMMethodChar(ch)) ch.toString else "$u%04X".format(ch.toInt))) + else name + } + + /** Replace operator symbols by corresponding expansion strings. * * @param name the string to encode * @return the string with all recognized opchars replaced with their encoding + * + * Operator symbols are only recognized if they make up the whole name, or + * if they make up the last part of the name which follows a `_`. */ - def encode(name: SimpleTermName): SimpleTermName = { - var buf: StringBuilder = null - val len = name.length - var i = 0 - while (i < len) { - val c = name(i) - if (c < nops && (op2code(c) ne null)) { - if (buf eq null) { - buf = new StringBuilder() - buf.append(name.slice(0, i)) - } - buf.append(op2code(c)) - /* Handle glyphs that are not valid Java/JVM identifiers */ - } - else if (!Character.isJavaIdentifierPart(c)) { - if (buf eq null) { - buf = new StringBuilder() - buf.append(name.slice(0, i)) + def encode(name: SimpleName): SimpleName = { + def loop(len: Int, ops: List[String]): SimpleName = { + def convert = + if (ops.isEmpty) name + else { + val buf = new java.lang.StringBuilder + buf.append(chrs, name.start, len) + for (op <- ops) buf.append(op) + termName(buf.toString) } - buf.append("$u%04X".format(c.toInt)) - } - else if (buf ne null) { - buf.append(c) + if (len == 0 || name(len - 1) == '_') convert + else { + val ch = name(len - 1) + if (ch <= nops && op2code(ch) != null) + loop(len - 1, op2code(ch) :: ops) + else if (Chars.isSpecial(ch)) + loop(len - 1, ch.toString :: ops) + else name } - i += 1 } - if (buf eq null) name - else termName(buf.toString) + loop(name.length, Nil) } - /** Replace `\$opname` by corresponding operator symbol. - * - * @param name0 the string to decode - * @return the string with all recognized operator symbol encodings replaced with their name + /** Replace operator expansions by the operators themselves. + * Operator expansions are only recognized if they make up the whole name, or + * if they make up the last part of the name which follows a `_`. */ - def decode(name0: String): String = { - //System.out.println("decode: " + name);//DEBUG - val name = if (name0.endsWith("")) name0.substring(0, name0.length() - ("").length()) + "this" - else name0 - var buf: StringBuilder = null - val len = name.length() - var i = 0 - while (i < len) { - var ops: OpCodes = null - var unicode = false - val c = name charAt i - if (c == '$' && i + 2 < len) { - val ch1 = name.charAt(i + 1) - if ('a' <= ch1 && ch1 <= 'z') { - val ch2 = name.charAt(i + 2) - if ('a' <= ch2 && ch2 <= 'z') { - ops = code2op((ch1 - 'a') * 26 + ch2 - 'a') - while ((ops ne null) && !name.startsWith(ops.code, i)) ops = ops.next - if (ops ne null) { - if (buf eq null) { - buf = new StringBuilder() - buf.append(name.substring(0, i)) - } - buf.append(ops.op) - i += ops.code.length() - } - /* Handle the decoding of Unicode glyphs that are - * not valid Java/JVM identifiers */ - } else if ((len - i) >= 6 && // Check that there are enough characters left - ch1 == 'u' && - ((Character.isDigit(ch2)) || - ('A' <= ch2 && ch2 <= 'F'))) { - /* Skip past "$u", next four should be hexadecimal */ - val hex = name.substring(i + 2, i + 6) - try { - val str = Integer.parseInt(hex, 16).toChar - if (buf eq null) { - buf = new StringBuilder() - buf.append(name.substring(0, i)) - } - buf.append(str) - /* 2 for "$u", 4 for hexadecimal number */ - i += 6 - unicode = true - } catch { - case _:NumberFormatException => - /* `hex` did not decode to a hexadecimal number, so - * do nothing. */ - } - } + def decode(name: SimpleName): SimpleName = { + def loop(len: Int, ops: List[Char]): SimpleName = { + def convert = + if (ops.isEmpty) name + else { + val buf = new java.lang.StringBuilder + buf.append(chrs, name.start, len) + for (op <- ops) buf.append(op) + termName(buf.toString) } - } - /* If we didn't see an opcode or encoded Unicode glyph, and the - buffer is non-empty, write the current character and advance - one */ - if ((ops eq null) && !unicode) { - if (buf ne null) - buf.append(c) - i += 1 + if (len == 0 || name(len - 1) == '_') convert + else if (Chars.isSpecial(name(len - 1))) loop(len - 1, name(len - 1) :: ops) + else { + val idx = name.lastIndexOf('$', len - 1) + if (idx >= 0 && idx + 2 < len) + str2op.get(name.sliceToString(idx, len)) match { + case Some(ch) => loop(idx, ch :: ops) + case None => name + } + else name } } - //System.out.println("= " + (if (buf == null) name else buf.toString()));//DEBUG - if (buf eq null) name else buf.toString() + loop(name.length, Nil) } } diff --git a/compiler/test/dotty/tools/dotc/ast/TreeInfoTest.scala b/compiler/test/dotty/tools/dotc/ast/TreeInfoTest.scala index a55973c43db4..8869a2a9af7b 100644 --- a/compiler/test/dotty/tools/dotc/ast/TreeInfoTest.scala +++ b/compiler/test/dotty/tools/dotc/ast/TreeInfoTest.scala @@ -4,6 +4,7 @@ package ast import org.junit.Test import core.Names._ +import core.StdNames.nme import core.Types._ import core.Symbols._ import org.junit.Assert._ @@ -19,7 +20,7 @@ class TreeInfoTest extends DottyTest { val xTree = tree.find(tree => tree.symbol.name == termName("x")).get val path = defPath(xTree.symbol, tree) assertEquals(List( - ("PackageDef", EMPTY_PACKAGE), + ("PackageDef", nme.EMPTY_PACKAGE), ("TypeDef", typeName("A")), ("Template", termName("")), ("DefDef", termName("bar")), diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index be160ac7fba0..4676b5110f23 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -121,10 +121,9 @@ class ErrorMessagesTests extends ErrorMessagesTest { val defn = ictx.definitions assertMessageCount(1, messages) - val ExpectedTokenButFound(expected, found, foundName) :: Nil = messages + val ExpectedTokenButFound(expected, found) :: Nil = messages assertEquals(Tokens.IDENTIFIER, expected) assertEquals(Tokens.VAL, found) - assertEquals("val", foundName.show) } @Test def expectedToken = diff --git a/sbt-bridge/test/xsbt/ExtractUsedNamesSpecification.scala b/sbt-bridge/test/xsbt/ExtractUsedNamesSpecification.scala index 6cff284feb15..5044c771872e 100644 --- a/sbt-bridge/test/xsbt/ExtractUsedNamesSpecification.scala +++ b/sbt-bridge/test/xsbt/ExtractUsedNamesSpecification.scala @@ -81,7 +81,7 @@ class ExtractUsedNamesSpecification extends Specification { // We could avoid this by checking if the untyped tree has a return type // but is it worth it? Revisit this after https://github.com/sbt/sbt/issues/1104 // has landed. - val expectedNames = standardNames ++ Set("A", "a", "$eq", "Int") + val expectedNames = standardNames ++ Set("A", "a", "=", "Int") usedNames === expectedNames } @@ -114,7 +114,7 @@ class ExtractUsedNamesSpecification extends Specification { val compilerForTesting = new ScalaCompilerForUnitTesting(nameHashing = true) val usedNames = compilerForTesting.extractUsedNamesFromSrc(src1, src2) val expectedNames = standardNames ++ Set("Test", "Test$", "B", "B$", - "Predef", "Predef$", "$qmark$qmark$qmark", "Nothing", + "Predef", "Predef$", "???", "Nothing", "lista", "List", "A", "at", "T", "X1", "X0", "as", "S", "Y", diff --git a/tests/neg/floatlits.scala b/tests/neg/floatlits.scala new file mode 100644 index 000000000000..81ccd1c2ce3a --- /dev/null +++ b/tests/neg/floatlits.scala @@ -0,0 +1,11 @@ +object Test { + + val y = .2 // ok + + val z = 3.2 // ok + + val a = 1.0e2 + val b = 1e-3 + + val x = 2. +} // error: identifier expected