diff options
81 files changed, 1471 insertions, 1112 deletions
diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 77e979e4d..8e054c9c2 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -30,9 +30,9 @@ import Decorators._ import tpd._ import scala.tools.asm -import NameOps._ import StdNames.nme import NameOps._ +import NameKinds.DefaultGetterName import dotty.tools.dotc.core import dotty.tools.dotc.core.Names.TypeName @@ -255,7 +255,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma val evalue = t.symbol.name.toString // value the actual enumeration value. av.visitEnum(name, edesc, evalue) } else { - assert(toDenot(t.symbol).name.toTermName.defaultGetterIndex >= 0) // this should be default getter. do not emmit. + assert(toDenot(t.symbol).name.is(DefaultGetterName)) // this should be default getter. do not emmit. } case t: SeqLiteral => val arrAnnotV: AnnotationVisitor = av.visitArray(name) @@ -421,7 +421,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma val Flag_METHOD: Flags = Flags.Method.bits val ExcludedForwarderFlags: Flags = { Flags.Specialized | Flags.Lifted | Flags.Protected | Flags.JavaStatic | - Flags.ExpandedName | Flags.Bridge | Flags.VBridge | Flags.Private | Flags.Macro + Flags.Bridge | Flags.VBridge | Flags.Private | Flags.Macro }.bits @@ -544,8 +544,8 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def toTermName: Name = n.toTermName def dropModule: Name = n.stripModuleClassSuffix - def len: Int = n.length - def offset: Int = n.start + def len: Int = n.toSimpleName.length + def offset: Int = n.toSimpleName.start def isTermName: Boolean = n.isTermName def startsWith(s: String): Boolean = n.startsWith(s) } @@ -557,7 +557,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def fullName: String = sym.showFullName def simpleName: Name = sym.name def javaSimpleName: Name = toDenot(sym).name // addModuleSuffix(simpleName.dropLocal) - def javaBinaryName: Name = toDenot(sym).fullNameSeparated("/") // addModuleSuffix(fullNameInternal('/')) + def javaBinaryName: Name = javaClassName.replace('.', '/').toTypeName // TODO: can we make this a string? addModuleSuffix(fullNameInternal('/')) def javaClassName: String = toDenot(sym).fullName.toString// addModuleSuffix(fullNameInternal('.')).toString def name: Name = sym.name def rawname: Name = { @@ -794,7 +794,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def memberInfo(s: Symbol): Type = tp.memberInfo(s) - def decls: List[Symbol] = tp.decls.map(_.symbol).toList + def decls: List[Symbol] = tp.decls.toList def members: List[Symbol] = tp.memberDenots(takeAllFilter, (name, buf) => buf ++= tp.member(name).alternatives).map(_.symbol).toList diff --git a/compiler/src/dotty/tools/dotc/FromTasty.scala b/compiler/src/dotty/tools/dotc/FromTasty.scala index b060a2054..da0190fa1 100644 --- a/compiler/src/dotty/tools/dotc/FromTasty.scala +++ b/compiler/src/dotty/tools/dotc/FromTasty.scala @@ -17,6 +17,7 @@ import Decorators._ import dotty.tools.dotc.transform.Pickler import tasty.DottyUnpickler import ast.tpd._ +import NameKinds.QualifiedName /** Compiler for TASTY files. * Usage: @@ -74,7 +75,7 @@ object FromTasty extends Driver { case unit: TASTYCompilationUnit => val className = unit.className.toTypeName val clsd = - if (className.contains('.')) ctx.base.staticRef(className) + if (className.is(QualifiedName)) ctx.base.staticRef(className) else defn.EmptyPackageClass.info.decl(className) def cannotUnpickle(reason: String) = { ctx.error(s"class $className cannot be unpickled because $reason") diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 66fc6bf84..111382b18 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -6,6 +6,7 @@ import core._ import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ import Decorators._ +import NameKinds.{UniqueName, EvidenceParamName, DefaultGetterName} import language.higherKinds import typer.FrontEnd import collection.mutable.ListBuffer @@ -128,7 +129,7 @@ object desugar { def makeImplicitParameters(tpts: List[Tree], forPrimaryConstructor: Boolean)(implicit ctx: Context) = for (tpt <- tpts) yield { val paramFlags: FlagSet = if (forPrimaryConstructor) PrivateLocalParamAccessor else Param - val epname = ctx.freshName(nme.EVIDENCE_PARAM_PREFIX).toTermName + val epname = EvidenceParamName.fresh() ValDef(epname, tpt, EmptyTree).withFlags(paramFlags | Implicit) } @@ -186,7 +187,7 @@ object desugar { case (vparam :: vparams) :: vparamss1 => def defaultGetter: DefDef = DefDef( - name = meth.name.defaultGetterName(n), + name = DefaultGetterName(meth.name, n), tparams = meth.tparams.map(tparam => dropContextBound(toDefParam(tparam))), vparamss = takeUpTo(normalizedVparamss.nestedMap(toDefParam), n), tpt = TypeTree(), @@ -230,7 +231,7 @@ object desugar { private def evidenceParams(meth: DefDef)(implicit ctx: Context): List[ValDef] = meth.vparamss.reverse match { case (vparams @ (vparam :: _)) :: _ if vparam.mods is Implicit => - vparams.dropWhile(!_.name.startsWith(nme.EVIDENCE_PARAM_PREFIX)) + vparams.dropWhile(!_.name.is(EvidenceParamName)) case _ => Nil } @@ -244,7 +245,7 @@ object desugar { def typeDef(tdef: TypeDef)(implicit ctx: Context): Tree = { if (tdef.mods is PrivateLocalParam) { val tparam = cpy.TypeDef(tdef)(name = tdef.name.expandedName(ctx.owner)) - .withMods(tdef.mods &~ PrivateLocal | ExpandedName) + .withMods(tdef.mods &~ PrivateLocal) val alias = cpy.TypeDef(tdef)(rhs = refOfDef(tparam)) .withMods(tdef.mods & VarianceFlags | PrivateLocalParamAccessor | Synthetic) Thicket(tparam, alias) @@ -402,7 +403,7 @@ object desugar { def anyRef = ref(defn.AnyRefAlias.typeRef) def productConstr(n: Int) = { - val tycon = scalaDot((tpnme.Product.toString + n).toTypeName) + val tycon = scalaDot((str.Product + n).toTypeName) val targs = constrVparamss.head map (_.tpt) if (targs.isEmpty) tycon else AppliedTypeTree(tycon, targs) } @@ -635,7 +636,7 @@ object desugar { case (named, tpt) :: Nil => derivedValDef(original, named, tpt, matchExpr, mods) case _ => - val tmpName = ctx.freshName().toTermName + val tmpName = UniqueName.fresh() val patMods = mods & Lazy | Synthetic | (if (ctx.owner.isClass) PrivateLocal else EmptyFlags) val firstDef = @@ -810,7 +811,7 @@ object desugar { val selectPos = Position(left.pos.start, op.pos.end, op.pos.start) Apply(Select(left, op.name).withPos(selectPos), args) } else { - val x = ctx.freshName().toTermName + val x = UniqueName.fresh() val selectPos = Position(op.pos.start, right.pos.end, op.pos.start) new InfixOpBlock( ValDef(x, TypeTree(), left).withMods(synthetic), @@ -888,7 +889,7 @@ object desugar { case id: Ident if isVarPattern(id) && id.name != nme.WILDCARD => (id, id) case Typed(id: Ident, _) if isVarPattern(id) && id.name != nme.WILDCARD => (pat, id) case _ => - val name = ctx.freshName().toTermName + val name = UniqueName.fresh() (Bind(name, pat), Ident(name)) } diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index 037ab73af..f3bce4000 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -157,7 +157,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => } /** Is name a left-associative operator? */ - def isLeftAssoc(operator: Name) = operator.nonEmpty && (operator.last != ':') + def isLeftAssoc(operator: Name) = !operator.isEmpty && (operator.toSimpleName.last != ':') /** can this type be a type pattern? */ def mayBeTypePat(tree: untpd.Tree): Boolean = unsplice(tree) match { diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 20d7c1458..0ff335e40 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -316,7 +316,7 @@ object Trees { def namePos = if (pos.exists) if (rawMods.is(Synthetic)) Position(pos.point, pos.point) - else Position(pos.point, pos.point + name.stripModuleClassSuffix.length, pos.point) + else Position(pos.point, pos.point + name.stripModuleClassSuffix.lastPart.length, pos.point) else pos } diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index ff66c8c8e..cd0115a99 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -12,6 +12,7 @@ import Denotations._, Decorators._, DenotTransformers._ import collection.mutable import util.{Property, SourceFile, NoSource} import typer.ErrorReporting._ +import NameKinds.TempResultName import scala.annotation.tailrec import scala.io.Codec @@ -897,7 +898,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def evalOnce(tree: Tree)(within: Tree => Tree)(implicit ctx: Context) = { if (isIdempotentExpr(tree)) within(tree) else { - val vdef = SyntheticValDef(ctx.freshName("ev$").toTermName, tree) + val vdef = SyntheticValDef(TempResultName.fresh(), tree) Block(vdef :: Nil, within(Ident(vdef.namedType))) } } diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 49b64d869..63c3d5f74 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -65,9 +65,9 @@ class ScalaSettings extends Settings.SettingGroup { val YcheckMods = BooleanSetting("-Ycheck-mods", "Check that symbols and their defining trees have modifiers in sync") val debug = BooleanSetting("-Ydebug", "Increase the quantity of debugging output.") val debugAlias = BooleanSetting("-Ydebug-alias", "Never follow alias when printing types") - val debugNames = BooleanSetting("-YdebugNames", "Show name-space indicators when printing names") val debugTrace = BooleanSetting("-Ydebug-trace", "Trace core operations") val debugFlags = BooleanSetting("-Ydebug-flags", "Print all flags of definitions") + val debugNames = BooleanSetting("-Ydebug-names", "Show internal representation of names") val debugOwners = BooleanSetting("-Ydebug-owners", "Print all owners of definitions (requires -Yprint-syms)") val termConflict = ChoiceSetting("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error") val log = PhasesSetting("-Ylog", "Log operations during") diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 8707b66f9..b299de434 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -174,9 +174,6 @@ object Contexts { protected def freshNames_=(freshNames: FreshNameCreator) = _freshNames = freshNames def freshNames: FreshNameCreator = _freshNames - def freshName(prefix: String = ""): String = freshNames.newName(prefix) - def freshName(prefix: Name): String = freshName(prefix.toString) - /** A map in which more contextual properties can be stored */ private var _moreProperties: Map[Key[Any], Any] = _ protected def moreProperties_=(moreProperties: Map[Key[Any], Any]) = _moreProperties = moreProperties @@ -297,7 +294,7 @@ object Contexts { /** Is this a context that introduces a non-empty scope? */ def isNonEmptyScopeContext: Boolean = - (this.scope ne outer.scope) && this.scope.nonEmpty + (this.scope ne outer.scope) && !this.scope.isEmpty /** Leave message in diagnostics buffer if it exists */ def diagnose(str: => String) = diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index b70fcb093..c7b1538c7 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -67,7 +67,7 @@ class Definitions { enterTypeField(cls, name, flags | ClassTypeParamCreationFlags, scope) private def enterSyntheticTypeParam(cls: ClassSymbol, paramFlags: FlagSet, scope: MutableScope, suffix: String = "T0") = - enterTypeParam(cls, suffix.toTypeName.expandedName(cls), ExpandedName | paramFlags, scope) + enterTypeParam(cls, suffix.toTypeName.expandedName(cls), paramFlags, scope) // NOTE: Ideally we would write `parentConstrs: => Type*` but SIP-24 is only // implemented in Dotty and not in Scala 2. @@ -108,7 +108,7 @@ class Definitions { * def apply(implicit $x0: T0, ..., $x{N_1}: T{N-1}): R * } */ - private def newFunctionNTrait(name: TypeName) = { + def newFunctionNTrait(name: TypeName) = { val completer = new LazyType { def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { val cls = denot.asClass.classSymbol @@ -119,7 +119,7 @@ class Definitions { enterTypeParam(cls, name ++ "$T" ++ i.toString, Contravariant, decls) val resParam = enterTypeParam(cls, name ++ "$R", Covariant, decls) val (methodType, parentTraits) = - if (name.startsWith(tpnme.ImplicitFunction)) { + if (name.firstPart.startsWith(str.ImplicitFunction)) { val superTrait = FunctionType(arity).appliedTo(argParams.map(_.typeRef) ::: resParam.typeRef :: Nil) (ImplicitMethodType, ctx.normalizeToClassRefs(superTrait :: Nil, cls, decls)) @@ -723,12 +723,11 @@ class Definitions { /** If type `ref` refers to a class in the scala package, its name, otherwise EmptyTypeName */ def scalaClassName(ref: Type)(implicit ctx: Context): TypeName = scalaClassName(ref.classSymbol) - private def isVarArityClass(cls: Symbol, prefix: Name) = { - val name = scalaClassName(cls) - name.startsWith(prefix) && - name.length > prefix.length && - name.drop(prefix.length).forall(_.isDigit) - } + private def isVarArityClass(cls: Symbol, prefix: String) = + scalaClassName(cls).testSimple(name => + name.startsWith(prefix) && + name.length > prefix.length && + name.drop(prefix.length).forall(_.isDigit)) def isBottomClass(cls: Symbol) = cls == NothingClass || cls == NullClass @@ -758,9 +757,9 @@ class Definitions { */ def isSyntheticFunctionClass(cls: Symbol) = scalaClassName(cls).isSyntheticFunction - def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.AbstractFunction) - def isTupleClass(cls: Symbol) = isVarArityClass(cls, tpnme.Tuple) - def isProductClass(cls: Symbol) = isVarArityClass(cls, tpnme.Product) + def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, str.AbstractFunction) + def isTupleClass(cls: Symbol) = isVarArityClass(cls, str.Tuple) + def isProductClass(cls: Symbol) = isVarArityClass(cls, str.Product) /** Returns the erased class of the function class `cls` * - FunctionN for N > 22 becomes FunctionXXL @@ -933,23 +932,6 @@ class Definitions { // ----- Initialization --------------------------------------------------- - /** Give the scala package a scope where a FunctionN trait is automatically - * added when someone looks for it. - */ - private def makeScalaSpecial()(implicit ctx: Context) = { - val oldInfo = ScalaPackageClass.classInfo - val oldDecls = oldInfo.decls - val newDecls = new MutableScope(oldDecls) { - override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { - val res = super.lookupEntry(name) - if (res == null && name.isTypeName && name.isSyntheticFunction) - newScopeEntry(newFunctionNTrait(name.asTypeName)) - else res - } - } - ScalaPackageClass.info = oldInfo.derivedClassInfo(decls = newDecls) - } - /** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */ lazy val syntheticScalaClasses = List( AnyClass, @@ -977,8 +959,6 @@ class Definitions { def init()(implicit ctx: Context) = { this.ctx = ctx if (!_isInitialized) { - makeScalaSpecial() - // force initialization of every symbol that is synthesized or hijacked by the compiler val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses() diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 7341b96af..fd42bde36 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -4,8 +4,9 @@ package core import SymDenotations.{ SymDenotation, ClassDenotation, NoDenotation } import Contexts.{Context, ContextBase} -import Names.{Name, PreName} -import Names.TypeName +import Names._ +import NameOps._ +import NameKinds._ import StdNames._ import Symbols.NoSymbol import Symbols._ @@ -1171,27 +1172,42 @@ object Denotations { * if generateStubs is set, generates stubs for missing top-level symbols */ def staticRef(path: Name, generateStubs: Boolean = true)(implicit ctx: Context): Denotation = { - def recur(path: Name, len: Int): Denotation = { - val point = path.lastIndexOf('.', len - 1) - val owner = - if (point > 0) recur(path.toTermName, point).disambiguate(_.info.isParameterless) - else if (path.isTermName) defn.RootClass.denot - else defn.EmptyPackageClass.denot + def select(prefix: Denotation, selector: Name): Denotation = { + val owner = prefix.disambiguate(_.info.isParameterless) if (owner.exists) { - val name = path slice (point + 1, len) - val result = owner.info.member(name) - if (result ne NoDenotation) result + val result = owner.info.member(selector) + if (result.exists) result else { val alt = - if (generateStubs) missingHook(owner.symbol.moduleClass, name) + if (generateStubs) missingHook(owner.symbol.moduleClass, selector) else NoSymbol - if (alt.exists) alt.denot - else MissingRef(owner, name) + if (alt.exists) alt.denot else MissingRef(owner, selector) } } else owner } - recur(path, path.length) + def recur(path: Name, wrap: TermName => Name = identity): Denotation = path match { + case path: TypeName => + recur(path.toTermName, n => n.toTypeName) + case ModuleClassName(underlying) => + recur(underlying, n => wrap(ModuleClassName(n))) + case QualifiedName(prefix, selector) => + select(recur(prefix), wrap(selector)) + case qn @ AnyQualifiedName(prefix, _) => + recur(prefix, n => wrap(qn.info.mkString(n).toTermName)) + case path: SimpleTermName => + def recurSimple(len: Int, wrap: TermName => Name): Denotation = { + val point = path.lastIndexOf('.', len - 1) + val selector = wrap(path.slice(point + 1, len).asTermName) + val prefix = + if (point > 0) recurSimple(point, identity) + else if (selector.isTermName) defn.RootClass.denot + else defn.EmptyPackageClass.denot + select(prefix, selector) + } + recurSimple(path.length, wrap) + } + recur(path) } /** If we are looking for a non-existing term name in a package, diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 29f1078a2..84072cd50 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -272,9 +272,6 @@ object Flags { */ final val Synthetic = commonFlag(18, "<synthetic>") - /** Symbol's name is expanded */ - final val ExpandedName = commonFlag(19, "<expandedname>") - /** A covariant type variable / an outer accessor */ final val CovariantOrOuter = commonFlag(20, "") final val Covariant = typeFlag(20, "<covariant>") @@ -308,19 +305,18 @@ object Flags { final val CaseAccessor = termFlag(25, "<caseaccessor>") /** A binding for a type parameter of a base class or trait. - * TODO: Replace with combination of isType, ExpandedName, and Override? */ final val BaseTypeArg = typeFlag(25, "<basetypearg>") final val CaseAccessorOrBaseTypeArg = CaseAccessor.toCommonFlags /** A super accessor */ - final val SuperAccessor = termFlag(26, "<superaccessor>") + final val Scala2SuperAccessor = termFlag(26, "<superaccessor>") /** An unpickled Scala 2.x class */ final val Scala2x = typeFlag(26, "<scala-2.x>") - final val SuperAccessorOrScala2x = SuperAccessor.toCommonFlags + final val SuperAccessorOrScala2x = Scala2x.toCommonFlags /** A method that has default params */ final val DefaultParameterized = termFlag(27, "<defaultparam>") @@ -409,9 +405,6 @@ object Flags { final val Scala2ExistentialCommon = commonFlag(55, "<existential>") final val Scala2Existential = Scala2ExistentialCommon.toTypeFlags - /** An overloaded symbol (Scala 2.x only) */ - final val Scala2Overloaded = termFlag(56, "<overloaded>") - /** A module variable (Scala 2.x only) */ final val Scala2ModuleVar = termFlag(57, "<modulevar>") @@ -424,6 +417,13 @@ object Flags { /** A method that is known to have inherited default parameters */ final val InheritedDefaultParams = termFlag(60, "<inherited-default-param>") + /** Translation of Scala2's EXPANDEDNAME flag. This flag is never stored in + * symbols, is only used locally when reading the flags of a Scala2 symbol. + * It's therefore safe to share the code with `InheritedDefaultParams` because + * the latter is never present in Scala2 unpickle info. + */ + final val Scala2ExpandedName = InheritedDefaultParams.toCommonFlags + /** A method that is known to have no default parameters */ final val NoDefaultParams = termFlag(61, "<no-default-param>") @@ -452,7 +452,7 @@ object Flags { final val FromStartFlags = Module | Package | Deferred | MethodOrHKCommon | Param | ParamAccessor | Scala2ExistentialCommon | Mutable.toCommonFlags | InSuperCall | Touched | JavaStatic | - CovariantOrOuter | ContravariantOrLabel | ExpandedName | CaseAccessorOrBaseTypeArg | + CovariantOrOuter | ContravariantOrLabel | CaseAccessorOrBaseTypeArg | Fresh | Frozen | Erroneous | ImplicitCommon | Permanent | Synthetic | SuperAccessorOrScala2x | Inline @@ -475,7 +475,7 @@ object Flags { /** Flags that are passed from a type parameter of a class to a refinement symbol * that sets the type parameter */ - final val RetainedTypeArgFlags = VarianceFlags | ExpandedName | Protected | Local + final val RetainedTypeArgFlags = VarianceFlags | Protected | Local /** Modules always have these flags set */ final val ModuleCreationFlags = ModuleVal | Lazy | Final | Stable @@ -502,7 +502,7 @@ object Flags { */ final val RetainedModuleValAndClassFlags: FlagSet = AccessFlags | Package | Case | - Synthetic | ExpandedName | JavaDefined | JavaStatic | Artifact | + Synthetic | JavaDefined | JavaStatic | Artifact | Erroneous | Lifted | MixedIn | Specialized /** Flags that can apply to a module val */ @@ -550,9 +550,6 @@ object Flags { /** A private accessor */ final val PrivateAccessor = allOf(Private, Accessor) - /** A type parameter with synthesized name */ - final val ExpandedTypeParam = allOf(ExpandedName, TypeParam) - /** An inline method */ final val InlineMethod = allOf(Inline, Method) @@ -578,7 +575,7 @@ object Flags { final val FinalOrInline = Final | Inline /** If symbol of a type alias has these flags, prefer the alias */ - final val AliasPreferred = TypeParam | BaseTypeArg | ExpandedName + final val AliasPreferred = TypeParam | BaseTypeArg /** A covariant type parameter instance */ final val LocalCovariant = allOf(Local, Covariant) diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala new file mode 100644 index 000000000..0f08e4701 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -0,0 +1,317 @@ +package dotty.tools +package dotc +package core + +import Names._ +import NameOps._ +import StdNames._ +import util.DotClass +import tasty.TastyFormat._ +import Decorators._ +import Contexts.Context +import collection.mutable + +object NameKinds { + + // These are sharable since all NameKinds are created eagerly at the start of the program + // before any concurrent threads are forked. for this to work, NameKinds should never + // be created lazily or in modules that start running after compilers are forked. + @sharable private val simpleNameKinds = new mutable.HashMap[Int, ClassifiedNameKind] + @sharable private val qualifiedNameKinds = new mutable.HashMap[Int, QualifiedNameKind] + @sharable private val uniqueNameKinds = new mutable.HashMap[String, UniqueNameKind] + + abstract class NameInfo extends DotClass { + def kind: NameKind + def mkString(underlying: TermName): String + def map(f: SimpleTermName => SimpleTermName): NameInfo = this + } + + abstract class NameKind(val tag: Int) extends DotClass { self => + type ThisInfo <: Info + class Info extends NameInfo { this: ThisInfo => + def kind = self + def mkString(underlying: TermName) = self.mkString(underlying, this) + override def toString = infoString + } + def definesNewName = false + def unmangle(name: SimpleTermName): TermName = name + def mkString(underlying: TermName, info: ThisInfo): String + def infoString: String + } + + object SimpleTermNameKind extends NameKind(UTF8) { self => + type ThisInfo = Info + val info = new Info + def mkString(underlying: TermName, info: ThisInfo) = unsupported("mkString") + def infoString = unsupported("infoString") + } + + abstract class 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) + case _ => None + } + simpleNameKinds(tag) = this + } + + 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 = + if (name.startsWith(prefix)) apply(name.drop(prefix.length).asSimpleName) + else name + } + + class SuffixNameKind(tag: Int, suffix: String, optInfoString: String = "") + extends ClassifiedNameKind(tag, if (optInfoString.isEmpty) s"Suffix $suffix" else optInfoString) { + def mkString(underlying: TermName, info: ThisInfo) = underlying.toString ++ suffix + override def unmangle(name: SimpleTermName): TermName = + if (name.endsWith(suffix)) apply(name.take(name.length - suffix.length).asSimpleName) + else name + } + + trait QualifiedInfo extends NameInfo { + val name: SimpleTermName + } + + 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)) + override def toString = s"$infoString $name" + } + def apply(qual: TermName, name: SimpleTermName): TermName = + qual.derived(new QualInfo(name)) + + /** Overloaded version used only for ExpandedName and TraitSetterName. + * Needed because the suffix of an expanded name may itself be expanded. + * For example, look at javap of scala.App.initCode + */ + def apply(qual: TermName, name: TermName): TermName = name rewrite { + case name: SimpleTermName => apply(qual, name) + case AnyQualifiedName(_, _) => apply(qual, name.toSimpleName) + } + + def unapply(name: DerivedTermName): Option[(TermName, SimpleTermName)] = name match { + case DerivedTermName(qual, info: this.QualInfo) => Some((qual, info.name)) + case _ => None + } + + override def definesNewName = true + + def mkString(underlying: TermName, info: ThisInfo) = + s"$underlying$separator${info.name}" + def infoString = s"Qualified $separator" + + qualifiedNameKinds(tag) = this + } + + object AnyQualifiedName { + def unapply(name: DerivedTermName): Option[(TermName, SimpleTermName)] = name match { + case DerivedTermName(qual, info: QualifiedInfo) => + Some((name.underlying, info.name)) + case _ => None + } + } + + trait NumberedInfo extends NameInfo { + def num: Int + } + + 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 { + override def toString = s"$infoString $num" + } + def apply(qual: TermName, num: Int) = + qual.derived(new NumberedInfo(num)) + def unapply(name: DerivedTermName): Option[(TermName, Int)] = name match { + case DerivedTermName(underlying, info: this.NumberedInfo) => Some((underlying, info.num)) + case _ => None + } + protected def skipSeparatorAndNum(name: SimpleTermName, separator: String): Int = { + var i = name.length + while (i > 0 && name(i - 1).isDigit) i -= 1 + if (i > separator.length && i < name.length && + name.slice(i - separator.length, i).toString == separator) i + else -1 + } + } + + object AnyNumberedName { + def unapply(name: DerivedTermName): Option[(TermName, Int)] = name match { + case DerivedTermName(qual, info: NumberedInfo) => Some((qual, info.num)) + case _ => None + } + } + + case class UniqueNameKind(val separator: String) + extends NumberedNameKind(UNIQUE, s"Unique $separator") { + override def definesNewName = true + def mkString(underlying: TermName, info: ThisInfo) = { + val safePrefix = str.sanitize(underlying.toString + separator) + safePrefix + info.num + } + + def fresh(prefix: TermName = EmptyTermName)(implicit ctx: Context): TermName = + ctx.freshNames.newName(prefix, this) + + uniqueNameKinds(separator) = this + } + + object AnyUniqueName { + def unapply(name: DerivedTermName): Option[(TermName, String, Int)] = name match { + case DerivedTermName(qual, info: NumberedInfo) => + info.kind match { + case unique: UniqueNameKind => Some((qual, unique.separator, info.num)) + case _ => None + } + case _ => None + } + } + + val QualifiedName = new QualifiedNameKind(QUALIFIED, ".") + val FlatName = new QualifiedNameKind(FLATTENED, "$") + val ExpandPrefixName = new QualifiedNameKind(EXPANDPREFIX, "$") + + val ExpandedName = new QualifiedNameKind(EXPANDED, str.EXPAND_SEPARATOR) { + private val FalseSuper = termName("$$super") + private val FalseSuperLength = FalseSuper.length + + override def unmangle(name: SimpleTermName): TermName = { + var i = name.lastIndexOfSlice(str.EXPAND_SEPARATOR) + if (i < 0) name + else { + // Hack to make super accessors from traits work. They would otherwise fail because of #765 + // The problem is that in `x$$super$$plus` the expansion prefix needs to be `x` + // instead of `x$$super`. + if (i > FalseSuperLength && name.slice(i - FalseSuperLength, i) == FalseSuper) + i -= FalseSuper.length + + apply(name.take(i).asTermName, name.drop(i + str.EXPAND_SEPARATOR.length).asSimpleName) + } + } + } + + val TraitSetterName = new QualifiedNameKind(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR) + + val UniqueName = new UniqueNameKind("$") { + override def mkString(underlying: TermName, info: ThisInfo) = + if (underlying.isEmpty) "$" + info.num + "$" else super.mkString(underlying, info) + } + + val InlineAccessorName = new UniqueNameKind("$_inlineAccessor_$") + val TempResultName = new UniqueNameKind("ev$") + val EvidenceParamName = new UniqueNameKind("evidence$") + val DepParamName = new UniqueNameKind("<param>") + val LazyImplicitName = new UniqueNameKind("$_lazy_implicit_$") + val LazyLocalName = new UniqueNameKind("$lzy") + val LazyLocalInitName = new UniqueNameKind("$lzyINIT") + val LazyFieldOffsetName = new UniqueNameKind("$OFFSET") + val LazyBitMapName = new UniqueNameKind(nme.BITMAP_PREFIX.toString) + val NonLocalReturnKeyName = new UniqueNameKind("nonLocalReturnKey") + val WildcardParamName = new UniqueNameKind("_$") + val TailLabelName = new UniqueNameKind("tailLabel") + val ExceptionBinderName = new UniqueNameKind("ex") + val SkolemName = new UniqueNameKind("?") + val LiftedTreeName = new UniqueNameKind("liftedTree") + + val UniqueExtMethName = new UniqueNameKind("$extension") { + override def unmangle(name: SimpleTermName): TermName = { + val i = skipSeparatorAndNum(name, separator) + if (i > 0) { + val index = name.drop(i).toString.toInt + var original = name.take(i - separator.length).asTermName + apply(original, index) + } + else name + } + } + + val PatMatStdBinderName = new UniqueNameKind("x") + val PatMatPiName = new UniqueNameKind("pi") // FIXME: explain what this is + val PatMatPName = new UniqueNameKind("p") // FIXME: explain what this is + val PatMatOName = new UniqueNameKind("o") // FIXME: explain what this is + val PatMatCaseName = new UniqueNameKind("case") + val PatMatMatchFailName = new UniqueNameKind("matchFail") + val PatMatSelectorName = new UniqueNameKind("selector") + + object DefaultGetterName extends NumberedNameKind(DEFAULTGETTER, "DefaultGetter") { + def mkString(underlying: TermName, info: ThisInfo) = { + val prefix = if (underlying.isConstructorName) nme.DEFAULT_GETTER_INIT else underlying + prefix.toString + str.DEFAULT_GETTER + (info.num + 1) + } + // TODO: Reduce code duplication with UniqueExtMethName + override def unmangle(name: SimpleTermName): 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 + apply(original, index) + } + else name + } + } + + object VariantName extends NumberedNameKind(VARIANT, "Variant") { + val varianceToPrefix = Map(-1 -> '-', 0 -> '=', 1 -> '+') + def mkString(underlying: TermName, info: ThisInfo) = { + varianceToPrefix(info.num).toString + underlying + } + } + + /** Names of the form N_<outer>. Emitted by inliner, replaced by outer path + * in ExplicitOuter. + */ + object OuterSelectName extends NumberedNameKind(OUTERSELECT, "OuterSelect") { + def mkString(underlying: TermName, info: ThisInfo) = { + assert(underlying.isEmpty) + info.num + "_<outer>" + } + } + + val SuperAccessorName = new PrefixNameKind(SUPERACCESSOR, "super$") + val InitializerName = new PrefixNameKind(INITIALIZER, "initial$") + val ShadowedName = new PrefixNameKind(SHADOWED, "(shadowed)") + val ProtectedAccessorName = new PrefixNameKind(PROTECTEDACCESSOR, "protected$") + val ProtectedSetterName = new PrefixNameKind(PROTECTEDSETTER, "protected$set") // dubious encoding, kept for Scala2 compatibility + val AvoidClashName = new SuffixNameKind(AVOIDCLASH, "$_avoid_name_clash_$") + val DirectName = new SuffixNameKind(DIRECT, "$direct") + val FieldName = new SuffixNameKind(FIELD, "$$local") + val ExtMethName = new SuffixNameKind(EXTMETH, "$extension") + val ModuleVarName = new SuffixNameKind(OBJECTVAR, "$module") + val ModuleClassName = new SuffixNameKind(OBJECTCLASS, "$", optInfoString = "ModuleClass") + + object SignedName extends NameKind(63) { + + /** @param parts resultSig followed by paramsSig */ + case class SignedInfo(sig: Signature) extends Info { + override def toString = s"$infoString $sig" + } + type ThisInfo = SignedInfo + + def apply(qual: TermName, sig: Signature) = + qual.derived(new SignedInfo(sig)) + def unapply(name: DerivedTermName): Option[(TermName, Signature)] = name match { + case DerivedTermName(underlying, info: SignedInfo) => Some((underlying, info.sig)) + case _ => None + } + + def mkString(underlying: TermName, info: ThisInfo): String = unsupported("mkString") + def infoString: String = "Signed" + } + + 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 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 240ad359b..915bd52ab 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -4,11 +4,12 @@ package core import java.security.MessageDigest import scala.annotation.switch import scala.io.Codec -import Names._, StdNames._, Contexts._, Symbols._, Flags._ +import Names._, StdNames._, Contexts._, Symbols._, Flags._, NameKinds._ import Decorators.PreNamedString import util.{Chars, NameTransformer} import Chars.isOperatorPart import Definitions._ +import config.Config object NameOps { @@ -48,212 +49,97 @@ object NameOps { } } - class PrefixNameExtractor(pre: TermName) { - def apply(name: TermName): TermName = pre ++ name - def unapply(name: TermName): Option[TermName] = - if (name startsWith pre) Some(name.drop(pre.length).asTermName) else None - } - - object SuperAccessorName extends PrefixNameExtractor(nme.SUPER_PREFIX) - object InitializerName extends PrefixNameExtractor(nme.INITIALIZER_PREFIX) - implicit class NameDecorator[N <: Name](val name: N) extends AnyVal { import nme._ - def likeTyped(n: PreName): N = + def testSimple(f: SimpleTermName => Boolean): Boolean = name match { + case name: SimpleTermName => f(name) + case name: TypeName => name.toTermName.testSimple(f) + case _ => false + } + + def likeSpaced(n: PreName): N = (if (name.isTermName) n.toTermName else n.toTypeName).asInstanceOf[N] def isConstructorName = name == CONSTRUCTOR || name == TRAIT_CONSTRUCTOR def isStaticConstructorName = name == STATIC_CONSTRUCTOR - def isExceptionResultName = name startsWith EXCEPTION_RESULT_PREFIX - def isImplClassName = name endsWith IMPL_CLASS_SUFFIX - def isLocalDummyName = name startsWith LOCALDUMMY_PREFIX - def isLoopHeaderLabel = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX) - def isProtectedAccessorName = name startsWith PROTECTED_PREFIX - def isReplWrapperName = name containsSlice INTERPRETER_IMPORT_WRAPPER - def isTraitSetterName = name containsSlice TRAIT_SETTER_SEPARATOR - def isSetterName = name endsWith SETTER_SUFFIX - def isSingletonName = name endsWith SINGLETON_SUFFIX - def isModuleClassName = name endsWith MODULE_SUFFIX - def isAvoidClashName = name endsWith AVOID_CLASH_SUFFIX - def isImportName = name startsWith IMPORT - def isFieldName = name endsWith LOCAL_SUFFIX - def isShadowedName = name.length > 0 && name.head == '(' && name.startsWith(nme.SHADOWED) - def isDefaultGetterName = name.isTermName && name.asTermName.defaultGetterIndex >= 0 - def isScala2LocalSuffix = name.endsWith(" ") - def isModuleVarName(name: Name): Boolean = - name.stripAnonNumberSuffix endsWith MODULE_VAR_SUFFIX - def isSelectorName = name.startsWith(" ") && name.tail.forall(_.isDigit) - def isLazyLocal = name.endsWith(nme.LAZY_LOCAL) - def isOuterSelect = name.endsWith(nme.OUTER_SELECT) - def isInlineAccessor = name.startsWith(nme.INLINE_ACCESSOR_PREFIX) + def isLocalDummyName = name startsWith str.LOCALDUMMY_PREFIX + def isReplWrapperName = name.toString contains str.INTERPRETER_IMPORT_WRAPPER + def isSetterName = name endsWith str.SETTER_SUFFIX + def isScala2LocalSuffix = testSimple(_.endsWith(" ")) + def isSelectorName = testSimple(n => n.startsWith("_") && n.drop(1).forall(_.isDigit)) /** Is name a variable name? */ - def isVariableName: Boolean = name.length > 0 && { - val first = name.head - (((first.isLower && first.isLetter) || first == '_') - && (name != false_) - && (name != true_) - && (name != null_)) + def isVariableName: Boolean = testSimple { n => + n.length > 0 && { + val first = n.head + (((first.isLower && first.isLetter) || first == '_') + && (n != false_) + && (n != true_) + && (n != null_)) + } } def isOpAssignmentName: Boolean = name match { case raw.NE | raw.LE | raw.GE | EMPTY => false - case _ => + case name: SimpleTermName => name.length > 0 && name.last == '=' && name.head != '=' && isOperatorPart(name.head) - } - - /** If the name ends with $nn where nn are - * all digits, strip the $ and the digits. - * Otherwise return the argument. - */ - def stripAnonNumberSuffix: Name = { - var pos = name.length - while (pos > 0 && name(pos - 1).isDigit) - pos -= 1 - - if (pos > 0 && pos < name.length && name(pos - 1) == '$') - name take (pos - 1) - else - name + case _ => + false } /** Convert this module name to corresponding module class name */ - def moduleClassName: TypeName = (name ++ tpnme.MODULE_SUFFIX).toTypeName + def moduleClassName: TypeName = name.derived(ModuleClassName).toTypeName /** Convert this module class name to corresponding source module name */ - def sourceModuleName: TermName = stripModuleClassSuffix.toTermName - - /** If name ends in module class suffix, drop it */ - def stripModuleClassSuffix: Name = - if (isModuleClassName) name dropRight MODULE_SUFFIX.length else name - - /** Append a suffix so that this name does not clash with another name in the same scope */ - def avoidClashName: TermName = (name ++ AVOID_CLASH_SUFFIX).toTermName + def sourceModuleName: TermName = name.toTermName.exclude(ModuleClassName) - /** If name ends in "avoid clash" suffix, drop it */ - def stripAvoidClashSuffix: Name = - if (isAvoidClashName) name dropRight AVOID_CLASH_SUFFIX.length else name + /** If name ends in module class suffix, drop it. This + * method needs to work on mangled as well as unmangled names because + * it is also called from the backend. + */ + def stripModuleClassSuffix: N = likeSpaced { + val semName = + if (name.isSimple && name.endsWith("$")) name.unmangleClassName else name + semName.exclude(ModuleClassName) + } /** If flags is a ModuleClass but not a Package, add module class suffix */ - def adjustIfModuleClass(flags: Flags.FlagSet): N = { + def adjustIfModuleClass(flags: Flags.FlagSet): N = likeSpaced { if (flags is (ModuleClass, butNot = Package)) name.asTypeName.moduleClassName - else stripAvoidClashSuffix - }.asInstanceOf[N] - - /** The superaccessor for method with given name */ - def superName: TermName = (nme.SUPER_PREFIX ++ name).toTermName - - /** The expanded name of `name` relative to given class `base`. - */ - def expandedName(base: Symbol, separator: Name)(implicit ctx: Context): N = - expandedName(if (base is Flags.ExpandedName) base.name else base.fullNameSeparated("$"), separator) - - def expandedName(base: Symbol)(implicit ctx: Context): N = expandedName(base, nme.EXPAND_SEPARATOR) - - /** The expanded name of `name` relative to `basename` with given `separator` - */ - def expandedName(prefix: Name, separator: Name = nme.EXPAND_SEPARATOR): N = - name.fromName(prefix ++ separator ++ name).asInstanceOf[N] - - def expandedName(prefix: Name): N = expandedName(prefix, nme.EXPAND_SEPARATOR) - - /** Revert the expanded name. Note: This currently gives incorrect results - * if the normal name contains `nme.EXPAND_SEPARATOR`, i.e. two consecutive '$' - * signs. This can happen for instance if a super accessor is paired with - * an encoded name, e.g. super$$plus$eq. See #765. - */ - def unexpandedName: N = { - var idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) - - // Hack to make super accessors from traits work. They would otherwise fail because of #765 - // TODO: drop this once we have more robust name handling - if (idx > FalseSuperLength && name.slice(idx - FalseSuperLength, idx) == FalseSuper) - idx -= FalseSuper.length - - if (idx < 0) name else (name drop (idx + nme.EXPAND_SEPARATOR.length)).asInstanceOf[N] + else name.toTermName.exclude(AvoidClashName) } - def expandedPrefix: N = { - val idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) - assert(idx >= 0) - name.take(idx).asInstanceOf[N] + def expandedName(base: Symbol, kind: QualifiedNameKind = ExpandedName)(implicit ctx: Context): N = { + val prefix = + if (base.name.is(ExpandedName)) base.name else base.fullNameSeparated(ExpandPrefixName) + likeSpaced { kind(prefix.toTermName, name.toTermName) } } - def shadowedName: N = likeTyped(nme.SHADOWED ++ name) - - def revertShadowed: N = likeTyped(name.drop(nme.SHADOWED.length)) - - def implClassName: N = likeTyped(name ++ tpnme.IMPL_CLASS_SUFFIX) + /** Revert the expanded name. */ + def unexpandedName: N = likeSpaced { + name.rewrite { case ExpandedName(_, unexp) => unexp } + } - def errorName: N = likeTyped(name ++ nme.ERROR) + def implClassName: N = likeSpaced(name ++ tpnme.IMPL_CLASS_SUFFIX) - def directName: N = likeTyped(name ++ DIRECT_SUFFIX) + def errorName: N = likeSpaced(name ++ nme.ERROR) - def freshened(implicit ctx: Context): N = - likeTyped( - if (name.isModuleClassName) name.stripModuleClassSuffix.freshened.moduleClassName - else likeTyped(ctx.freshName(name ++ NameTransformer.NAME_JOIN_STRING))) /** Name with variance prefix: `+` for covariant, `-` for contravariant */ def withVariance(v: Int): N = - if (hasVariance) dropVariance.withVariance(v) - else v match { - case -1 => likeTyped('-' +: name) - case 1 => likeTyped('+' +: name) - case 0 => name - } - - /** Does name have a `+`/`-` variance prefix? */ - def hasVariance: Boolean = - name.nonEmpty && name.head == '+' || name.head == '-' - - /** Drop variance prefix if name has one */ - def dropVariance: N = if (hasVariance) likeTyped(name.tail) else name + likeSpaced { VariantName(name.exclude(VariantName).toTermName, v) } /** The variance as implied by the variance prefix, or 0 if there is * no variance prefix. */ - def variance = name.head match { - case '-' => -1 - case '+' => 1 - case _ => 0 - } + def variance = name.collect { case VariantName(_, n) => n }.getOrElse(0) - /** Translate a name into a list of simple TypeNames and TermNames. - * In all segments before the last, type/term is determined by whether - * the following separator char is '.' or '#'. The last segment - * is of the same type as the original name. - * - * Examples: - * - * package foo { - * object Lorax { object Wog ; class Wog } - * class Lorax { object Zax ; class Zax } - * } - * - * f("foo.Lorax".toTermName) == List("foo": Term, "Lorax": Term) // object Lorax - * f("foo.Lorax".toTypeName) == List("foo": Term, "Lorax": Type) // class Lorax - * f("Lorax.Wog".toTermName) == List("Lorax": Term, "Wog": Term) // object Wog - * f("Lorax.Wog".toTypeName) == List("Lorax": Term, "Wog": Type) // class Wog - * f("Lorax#Zax".toTermName) == List("Lorax": Type, "Zax": Term) // object Zax - * f("Lorax#Zax".toTypeName) == List("Lorax": Type, "Zax": Type) // class Zax - * - * Note that in actual scala syntax you cannot refer to object Zax without an - * instance of Lorax, so Lorax#Zax could only mean the type. One might think - * that Lorax#Zax.type would work, but this is not accepted by the parser. - * For the purposes of referencing that object, the syntax is allowed. - */ - def segments: List[Name] = { - def mkName(name: Name, follow: Char): Name = - if (follow == '.') name.toTermName else name.toTypeName - - name.indexWhere(ch => ch == '.' || ch == '#') match { - case -1 => - if (name.isEmpty) scala.Nil else name :: scala.Nil - case idx => - mkName(name take idx, name(idx)) :: (name drop (idx + 1)).segments + def freshened(implicit ctx: Context): N = likeSpaced { + name.toTermName match { + case ModuleClassName(original) => ModuleClassName(original.freshened) + case name => UniqueName.fresh(name) } } @@ -263,7 +149,7 @@ object NameOps { * - (-1) otherwise */ def functionArity: Int = - functionArityFor(tpnme.Function) max functionArityFor(tpnme.ImplicitFunction) + functionArityFor(str.Function) max functionArityFor(str.ImplicitFunction) /** Is a function name * - FunctionN for N >= 0 @@ -276,7 +162,7 @@ object NameOps { * - ImplicitFunctionN for N >= 0 * - false otherwise */ - def isImplicitFunction: Boolean = functionArityFor(tpnme.ImplicitFunction) >= 0 + def isImplicitFunction: Boolean = functionArityFor(str.ImplicitFunction) >= 0 /** Is a synthetic function name * - FunctionN for N > 22 @@ -284,24 +170,18 @@ object NameOps { * - false otherwise */ def isSyntheticFunction: Boolean = { - functionArityFor(tpnme.Function) > MaxImplementedFunctionArity || - functionArityFor(tpnme.ImplicitFunction) >= 0 + functionArityFor(str.Function) > MaxImplementedFunctionArity || + functionArityFor(str.ImplicitFunction) >= 0 } /** Parsed function arity for function with some specific prefix */ - private def functionArityFor(prefix: Name): Int = { + private def functionArityFor(prefix: String): Int = { if (name.startsWith(prefix)) try name.toString.substring(prefix.length).toInt catch { case _: NumberFormatException => -1 } else -1 } - /** The number of hops specified in an outer-select name */ - def outerSelectHops: Int = { - require(isOuterSelect) - name.dropRight(nme.OUTER_SELECT.length).toString.toInt - } - /** The name of the generic runtime operation corresponding to an array operation */ def genericArrayOp: TermName = name match { case nme.apply => nme.array_apply @@ -338,100 +218,61 @@ object NameOps { val methodTags: Seq[Name] = (methodTargs zip methodTarsNames).sortBy(_._2).map(x => typeToTag(x._1)) val classTags: Seq[Name] = (classTargs zip classTargsNames).sortBy(_._2).map(x => typeToTag(x._1)) - name.fromName(name ++ nme.specializedTypeNames.prefix ++ + name.likeSpaced(name ++ nme.specializedTypeNames.prefix ++ methodTags.fold(nme.EMPTY)(_ ++ _) ++ nme.specializedTypeNames.separator ++ classTags.fold(nme.EMPTY)(_ ++ _) ++ nme.specializedTypeNames.suffix) } /** If name length exceeds allowable limit, replace part of it by hash */ def compactified(implicit ctx: Context): TermName = termName(compactify(name.toString)) - } - // needed??? - private val Boxed = Map[TypeName, TypeName]( - tpnme.Boolean -> jtpnme.BoxedBoolean, - tpnme.Byte -> jtpnme.BoxedByte, - tpnme.Char -> jtpnme.BoxedCharacter, - tpnme.Short -> jtpnme.BoxedShort, - tpnme.Int -> jtpnme.BoxedInteger, - tpnme.Long -> jtpnme.BoxedLong, - tpnme.Float -> jtpnme.BoxedFloat, - tpnme.Double -> jtpnme.BoxedDouble) + def unmangleClassName: N = name.toTermName match { + case name: SimpleTermName + if name.endsWith(str.MODULE_SUFFIX) && !nme.falseModuleClassNames.contains(name) => + likeSpaced(name.dropRight(str.MODULE_SUFFIX.length).moduleClassName) + case _ => name + } + + def unmangle(kind: NameKind): N = likeSpaced { + name rewrite { + case unmangled: SimpleTermName => + kind.unmangle(unmangled) + case ExpandedName(prefix, last) => + kind.unmangle(last) rewrite { + case kernel: SimpleTermName => + ExpandedName(prefix, kernel) + } + } + } + + def unmangle(kinds: List[NameKind]): N = { + val unmangled = (name /: kinds)(_.unmangle(_)) + if (unmangled eq name) name else unmangled.unmangle(kinds) + } + } implicit class TermNameDecorator(val name: TermName) extends AnyVal { import nme._ - def setterName: TermName = - if (name.isFieldName) name.fieldToGetter.setterName - else name ++ SETTER_SUFFIX + def setterName: TermName = name.exclude(FieldName) ++ str.SETTER_SUFFIX def getterName: TermName = - if (name.isFieldName) fieldToGetter - else setterToGetter + name.exclude(FieldName).mapLast(n => + if (n.endsWith(str.SETTER_SUFFIX)) n.take(n.length - str.SETTER_SUFFIX.length).asSimpleName + else n) def fieldName: TermName = if (name.isSetterName) { - if (name.isTraitSetterName) { - // has form <$-separated-trait-name>$_setter_$ `name`_$eq - val start = name.indexOfSlice(TRAIT_SETTER_SEPARATOR) + TRAIT_SETTER_SEPARATOR.length - val end = name.indexOfSlice(SETTER_SUFFIX) - name.slice(start, end) ++ LOCAL_SUFFIX - } else getterName.fieldName + if (name.is(TraitSetterName)) { + val TraitSetterName(_, original) = name + original.fieldName + } + else getterName.fieldName } - else name ++ LOCAL_SUFFIX - - private def setterToGetter: TermName = { - assert(name.endsWith(SETTER_SUFFIX), name + " is referenced as a setter but has wrong name format") - name.take(name.length - SETTER_SUFFIX.length).asTermName - } - - def fieldToGetter: TermName = { - assert(name.isFieldName) - name.take(name.length - LOCAL_SUFFIX.length).asTermName - } - - /** Nominally, name$default$N, encoded for <init> - * @param Post the parameters position. - * @note Default getter name suffixes start at 1, so `pos` has to be adjusted by +1 - */ - def defaultGetterName(pos: Int): TermName = { - val prefix = if (name.isConstructorName) DEFAULT_GETTER_INIT else name - prefix ++ DEFAULT_GETTER ++ (pos + 1).toString - } - - /** Nominally, name from name$default$N, CONSTRUCTOR for <init> */ - def defaultGetterToMethod: TermName = { - val p = name.indexOfSlice(DEFAULT_GETTER) - if (p >= 0) { - val q = name.take(p).asTermName - // i.e., if (q.decoded == CONSTRUCTOR.toString) CONSTRUCTOR else q - if (q == DEFAULT_GETTER_INIT) CONSTRUCTOR else q - } else name - } - - /** If this is a default getter, its index (starting from 0), else -1 */ - def defaultGetterIndex: Int = { - var i = name.length - while (i > 0 && name(i - 1).isDigit) i -= 1 - if (i > 0 && i < name.length && name.take(i).endsWith(DEFAULT_GETTER)) - name.drop(i).toString.toInt - 1 - else - -1 - } + else FieldName(name) def stripScala2LocalSuffix: TermName = - if (name.isScala2LocalSuffix) name.init.asTermName else name - - /** The name of an accessor for protected symbols. */ - def protectedAccessorName: TermName = - PROTECTED_PREFIX ++ name.unexpandedName - - /** The name of a setter for protected symbols. Used for inherited Java fields. */ - def protectedSetterName: TermName = - PROTECTED_SET_PREFIX ++ name.unexpandedName - - def moduleVarName: TermName = - name ++ MODULE_VAR_SUFFIX + if (name.isScala2LocalSuffix) name.asSimpleName.dropRight(1) else name /** The name unary_x for a prefix operator x */ def toUnaryName: TermName = name match { @@ -441,65 +282,5 @@ object NameOps { case raw.BANG => UNARY_! case _ => name } - - /** The name of a method which stands in for a primitive operation - * during structural type dispatch. - */ - def primitiveInfixMethodName: TermName = name match { - case OR => takeOr - case XOR => takeXor - case AND => takeAnd - case EQ => testEqual - case NE => testNotEqual - case ADD => add - case SUB => subtract - case MUL => multiply - case DIV => divide - case MOD => takeModulo - case LSL => shiftSignedLeft - case LSR => shiftLogicalRight - case ASR => shiftSignedRight - case LT => testLessThan - case LE => testLessOrEqualThan - case GE => testGreaterOrEqualThan - case GT => testGreaterThan - case ZOR => takeConditionalOr - case ZAND => takeConditionalAnd - case _ => NO_NAME - } - - /** Postfix/prefix, really. - */ - def primitivePostfixMethodName: TermName = name match { - case UNARY_! => takeNot - case UNARY_+ => positive - case UNARY_- => negate - case UNARY_~ => complement - case `toByte` => toByte - case `toShort` => toShort - case `toChar` => toCharacter - case `toInt` => toInteger - case `toLong` => toLong - case `toFloat` => toFloat - case `toDouble` => toDouble - case _ => NO_NAME - } - - def primitiveMethodName: TermName = - primitiveInfixMethodName match { - case NO_NAME => primitivePostfixMethodName - case name => name - } - - def lazyLocalName = name ++ nme.LAZY_LOCAL - def nonLazyName = { - assert(name.isLazyLocal) - name.dropRight(nme.LAZY_LOCAL.length) - } - - def inlineAccessorName = nme.INLINE_ACCESSOR_PREFIX ++ name ++ "$" } - - private final val FalseSuper = "$$super".toTermName - private val FalseSuperLength = FalseSuper.length } diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 11f0b55a8..a72a02844 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -10,13 +10,16 @@ import Decorators._ import Contexts.Context import collection.IndexedSeqOptimized import collection.generic.CanBuildFrom -import collection.mutable.{ Builder, StringBuilder } +import collection.mutable.{ Builder, StringBuilder, AnyRefMap } import collection.immutable.WrappedString import collection.generic.CanBuildFrom -import util.DotClass +import util.{DotClass, SimpleMap} +import java.util.HashMap + //import annotation.volatile object Names { + import NameKinds._ /** A common class for things that can be turned into names. * Instances are both names and strings, the latter via a decorator. @@ -37,20 +40,11 @@ object Names { * 3. Names are intended to be encoded strings. @see dotc.util.NameTransformer. * The encoding will be applied when converting a string to a name. */ - abstract class Name extends DotClass - with PreName - with collection.immutable.Seq[Char] - with IndexedSeqOptimized[Char, Name] { + abstract class Name extends DotClass with PreName { /** A type for names of the same kind as this name */ type ThisName <: Name - /** The start index in the character array */ - val start: Int - - /** The length of the names */ - override val length: Int - /** Is this name a type name? */ def isTypeName: Boolean @@ -69,120 +63,244 @@ object Names { /** This name downcasted to a term name */ def asTermName: TermName - /** Create a new name of same kind as this one, in the given - * basis, with `len` characters taken from `cs` starting at `offset`. - */ - def fromChars(cs: Array[Char], offset: Int, len: Int): ThisName + def isSimple: Boolean + def asSimpleName: SimpleTermName + def toSimpleName: SimpleTermName + def mangled: Name - /** Create new name of same kind as this name and with same - * characters as given `name`. - */ - def fromName(name: Name): ThisName = fromChars(chrs, name.start, name.length) + def rewrite(f: PartialFunction[Name, Name]): ThisName + def collect[T](f: PartialFunction[Name, T]): Option[T] + def mapLast(f: SimpleTermName => SimpleTermName): ThisName + def mapParts(f: SimpleTermName => SimpleTermName): ThisName - /** Create new name of same kind as this name with characters from - * the given string + /** A name in the same (term or type) namespace as this name and + * with same characters as given `name`. */ - def fromString(str: String): ThisName = { - val cs = str.toCharArray - fromChars(cs, 0, cs.length) - } + def likeSpaced(name: Name): ThisName - override def toString = - if (length == 0) "" else new String(chrs, start, length) + def derived(info: NameInfo): ThisName + def derived(kind: ClassifiedNameKind): ThisName = derived(kind.info) + def exclude(kind: NameKind): ThisName + def is(kind: NameKind): Boolean + def debugString: String def toText(printer: Printer): Text = printer.toText(this) - /** Write to UTF8 representation of this name to given character array. - * Start copying to index `to`. Return index of next free byte in array. - * Array must have enough remaining space for all bytes - * (i.e. maximally 3*length bytes). - */ - final def copyUTF8(bs: Array[Byte], offset: Int): Int = { - val bytes = Codec.toUTF8(chrs, start, length) - scala.compat.Platform.arraycopy(bytes, 0, bs, offset, bytes.length) - offset + bytes.length - } - /** Replace \$op_name's by corresponding operator symbols. */ - def decode: Name = - if (contains('$')) fromString(NameTransformer.decode(toString)) - else this + def decode: Name /** Replace operator symbols by corresponding \$op_name's. */ - def encode: Name = - if (dontEncode(toTermName)) this else NameTransformer.encode(this) + def encode: Name + + def firstPart: SimpleTermName + def lastPart: SimpleTermName /** A more efficient version of concatenation */ def ++ (other: Name): ThisName = ++ (other.toString) + def ++ (other: String): ThisName = mapLast(n => termName(n.toString + other)) + def replace(from: Char, to: Char): ThisName = mapParts(_.replace(from, to)) + + def isEmpty: Boolean + + def startsWith(str: String): Boolean = firstPart.startsWith(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] + } - def ++ (other: String): ThisName = { - val s = toString + other - fromChars(s.toCharArray, 0, s.length) + abstract class TermName extends Name { + type ThisName = TermName + def isTypeName = false + def isTermName = true + def toTermName = this + def asTypeName = throw new ClassCastException(this + " is not a type name") + def asTermName = this + + @sharable // because it is only modified in the synchronized block of toTypeName. + @volatile private[this] var _typeName: TypeName = null + + def toTypeName: TypeName = { + if (_typeName == null) + synchronized { + if (_typeName == null) + _typeName = new TypeName(this) + } + _typeName } - def replace(from: Char, to: Char): ThisName = { - val cs = new Array[Char](length) - Array.copy(chrs, start, cs, 0, length) - for (i <- 0 until length) { - if (cs(i) == from) cs(i) = to + def likeSpaced(name: Name): TermName = name.toTermName + + def info: NameInfo = SimpleTermNameKind.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 => + derivedNames(info) + case derivedNames: HashMap[NameInfo, DerivedTermName] @unchecked => + derivedNames.get(info) + } + + private def putDerived(info: NameInfo, name: DerivedTermName): name.type = { + derivedNames match { + case derivedNames: SimpleMap[NameInfo, DerivedTermName] @unchecked => + if (derivedNames.size < 4) + this.derivedNames = derivedNames.updated(info, name) + else { + val newMap = new HashMap[NameInfo, DerivedTermName] + derivedNames.foreachBinding(newMap.put(_, _)) + newMap.put(info, name) + this.derivedNames = newMap + } + case derivedNames: HashMap[NameInfo, DerivedTermName] @unchecked => + derivedNames.put(info, name) + } + name + } + + private def add(info: NameInfo): TermName = synchronized { + getDerived(info) match { + case null => putDerived(info, new DerivedTermName(this, info)) + case derivedName => derivedName + } + } + + private def rewrap(underlying: TermName) = + if (underlying eq this.underlying) this else underlying.add(info) + + /** Return derived name with given `info` and the current + * name as underlying name. + */ + def derived(info: NameInfo): TermName = { + val thisKind = this.info.kind + val thatKind = info.kind + if (thisKind.tag < thatKind.tag || thatKind.definesNewName) add(info) + else if (thisKind.tag > thatKind.tag) rewrap(underlying.derived(info)) + else { + assert(info == this.info) + this } - fromChars(cs, 0, length) } + 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 = { + val thisKind = this.info.kind + thisKind == kind || + !thisKind.definesNewName && thisKind.tag > kind.tag && underlying.is(kind) + } + } + + class SimpleTermName(val start: Int, val length: Int, @sharable private[Names] var next: SimpleTermName) extends TermName { + // `next` is @sharable because it is only modified in the synchronized block of termName. + + def apply(n: Int) = chrs(start + n) + + def exists(p: Char => Boolean): Boolean = { + var i = 0 + while (i < length && !p(chrs(start + i))) i += 1 + i < length + } + + def forall(p: Char => Boolean) = !exists(!p(_)) + def contains(ch: Char): Boolean = { var i = 0 while (i < length && chrs(start + i) != ch) i += 1 i < length } - def firstChar = chrs(start) + 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 + } - // ----- Collections integration ------------------------------------- + def lastIndexOf(ch: Char, start: Int = length - 1): Int = { + var i = start + while (i >= 0 && apply(i) != ch) i -= 1 + i + } - override protected[this] def thisCollection: WrappedString = new WrappedString(repr.toString) - override protected[this] def toCollection(repr: Name): WrappedString = new WrappedString(repr.toString) + def lastIndexOfSlice(str: String): Int = toString.lastIndexOfSlice(str) - override protected[this] def newBuilder: Builder[Char, Name] = unsupported("newBuilder") + 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) + } - override def apply(index: Int): Char = chrs(start + index) + def slice(from: Int, until: Int): SimpleTermName = { + assert(0 <= from && from <= until && until <= length) + termName(chrs, start + from, until - from) + } - override def slice(from: Int, until: Int): ThisName = - fromChars(chrs, start + from, until - from) + def drop(n: Int) = slice(n, length) + def take(n: Int) = slice(0, n) + def dropRight(n: Int) = slice(0, length - n) + def takeRight(n: Int) = slice(length - n, length) - override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] + def head = apply(0) + def last = apply(length - 1) - override def seq = toCollection(this) - } + def isSimple = true + def asSimpleName = this + def toSimpleName = this + def mangled = this - class TermName(val start: Int, val length: Int, @sharable private[Names] var next: TermName) extends Name { - // `next` is @sharable because it is only modified in the synchronized block of termName. - type ThisName = TermName - def isTypeName = false - def isTermName = true + 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) - @sharable // because it is only modified in the synchronized block of toTypeName. - @volatile private[this] var _typeName: TypeName = null + def encode: SimpleTermName = + if (dontEncode(toTermName)) this else NameTransformer.encode(this) - def toTypeName: TypeName = { - if (_typeName == null) - synchronized { - if (_typeName == null) - _typeName = new TypeName(start, length, this) - } - _typeName - } - def toTermName = this - def asTypeName = throw new ClassCastException(this + " is not a type name") - def asTermName = this + /** Replace \$op_name's by corresponding operator symbols. */ + def decode: SimpleTermName = + if (contains('$')) termName(NameTransformer.decode(toString)) else this + + def firstPart = this + def lastPart = this override def hashCode: Int = start - override protected[this] def newBuilder: Builder[Char, Name] = termNameBuilder + override def toString = + if (length == 0) "" else new String(chrs, start, length) - def fromChars(cs: Array[Char], offset: Int, len: Int): TermName = termName(cs, offset, len) + def debugString: String = toString } - class TypeName(val start: Int, val length: Int, val toTermName: TermName) extends Name { + class TypeName(val toTermName: TermName) extends Name { + + def isEmpty = toTermName.isEmpty + + def encode = toTermName.encode.toTypeName + def decode = toTermName.decode.toTypeName + def firstPart = toTermName.firstPart + def lastPart = toTermName.lastPart + type ThisName = TypeName def isTypeName = true def isTermName = false @@ -190,12 +308,77 @@ object Names { def asTypeName = this def asTermName = throw new ClassCastException(this + " is not a term name") - override def hashCode: Int = -start + def isSimple = toTermName.isSimple + def asSimpleName = toTermName.asSimpleName + def toSimpleName = toTermName.toSimpleName + def mangled = toTermName.toSimpleName.toTypeName - override protected[this] def newBuilder: Builder[Char, Name] = - termNameBuilder.mapResult(_.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 - def fromChars(cs: Array[Char], offset: Int, len: Int): TypeName = typeName(cs, offset, len) + def likeSpaced(name: Name): TypeName = name.toTypeName + + def derived(info: NameInfo): TypeName = toTermName.derived(info).toTypeName + def exclude(kind: NameKind): TypeName = toTermName.exclude(kind).toTypeName + def is(kind: NameKind) = toTermName.is(kind) + + override def toString = toTermName.toString + override def debugString = toTermName.debugString + "/T" + } + + /** 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) + 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") + + private[this] var simpleName: SimpleTermName = null + def toSimpleName = { + if (simpleName == null) simpleName = termName(toString) + simpleName + } + def mangled = toSimpleName + + 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] = + if (f.isDefinedAt(this)) Some(f(this)) + else info match { + case qual: QualifiedInfo => None + case _ => underlying.collect(f) + } + + def mapLast(f: SimpleTermName => SimpleTermName): ThisName = + info match { + case qual: QualifiedInfo => underlying.derived(qual.map(f)) + case _ => underlying.mapLast(f).derived(info) + } + + def mapParts(f: SimpleTermName => SimpleTermName): ThisName = + info match { + case qual: QualifiedInfo => underlying.mapParts(f).derived(qual.map(f)) + case _ => underlying.mapParts(f).derived(info) + } } // Nametable @@ -214,7 +397,7 @@ object Names { /** Hashtable for finding term names quickly. */ @sharable // because it's only mutated in synchronized block of termName - private var table = new Array[TermName](InitialHashSize) + private var table = new Array[SimpleTermName](InitialHashSize) /** The number of defined names. */ @sharable // because it's only mutated in synchronized block of termName @@ -242,7 +425,7 @@ object Names { /** Create a term name from the characters in cs[offset..offset+len-1]. * Assume they are already encoded. */ - def termName(cs: Array[Char], offset: Int, len: Int): TermName = synchronized { + def termName(cs: Array[Char], offset: Int, len: Int): SimpleTermName = synchronized { util.Stats.record("termName") val h = hashValue(cs, offset, len) & (table.size - 1) @@ -266,7 +449,7 @@ object Names { } /** Rehash chain of names */ - def rehash(name: TermName): Unit = + def rehash(name: SimpleTermName): Unit = if (name != null) { val oldNext = name.next val h = hashValue(chrs, name.start, name.length) & (table.size - 1) @@ -280,7 +463,7 @@ object Names { size += 1 if (size.toDouble / table.size > fillFactor) { val oldTable = table - table = new Array[TermName](table.size * 2) + table = new Array[SimpleTermName](table.size * 2) for (i <- 0 until oldTable.size) rehash(oldTable(i)) } } @@ -292,7 +475,7 @@ object Names { return name name = name.next } - name = new TermName(nc, len, next) + name = new SimpleTermName(nc, len, next) enterChars() table(h) = name incTableSize() @@ -308,7 +491,7 @@ object Names { /** Create a term name from the UTF8 encoded bytes in bs[offset..offset+len-1]. * Assume they are already encoded. */ - def termName(bs: Array[Byte], offset: Int, len: Int): TermName = { + def termName(bs: Array[Byte], offset: Int, len: Int): SimpleTermName = { val chars = Codec.fromUTF8(bs, offset, len) termName(chars, 0, chars.length) } @@ -320,53 +503,75 @@ object Names { termName(bs, offset, len).toTypeName /** Create a term name from a string, without encoding operators */ - def termName(s: String): TermName = termName(s.toCharArray, 0, s.length) + def termName(s: String): SimpleTermName = termName(s.toCharArray, 0, s.length) /** Create a type name from a string, without encoding operators */ def typeName(s: String): TypeName = typeName(s.toCharArray, 0, s.length) - /** The term name represented by the empty string */ - val EmptyTermName = new TermName(-1, 0, null) + table(0) = new SimpleTermName(-1, 0, null) - table(0) = EmptyTermName + /** The term name represented by the empty string */ + val EmptyTermName: TermName = table(0) /** The type name represented by the empty string */ val EmptyTypeName = EmptyTermName.toTypeName // can't move CONSTRUCTOR/EMPTY_PACKAGE to `nme` because of bootstrap failures in `encode`. - val CONSTRUCTOR = termName("<init>") - val STATIC_CONSTRUCTOR = termName("<clinit>") - val EMPTY_PACKAGE = termName("<empty>") - - val dontEncode = Set(CONSTRUCTOR, EMPTY_PACKAGE) + val CONSTRUCTOR: TermName = termName("<init>") + val STATIC_CONSTRUCTOR: TermName = termName("<clinit>") + val EMPTY_PACKAGE: TermName = termName("<empty>") + val REFINEMENT: TermName = termName("<refinement>") - def termNameBuilder: Builder[Char, TermName] = - StringBuilder.newBuilder.mapResult(termName) - - implicit val nameCanBuildFrom: CanBuildFrom[Name, Char, Name] = new CanBuildFrom[Name, Char, Name] { - def apply(from: Name): Builder[Char, Name] = - StringBuilder.newBuilder.mapResult(s => from.fromChars(s.toCharArray, 0, s.length)) - def apply(): Builder[Char, Name] = termNameBuilder - } + 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 + else x match { + case x: QualifiedInfo => + y match { + case y: QualifiedInfo => + compareSimpleNames(x.name, y.name) + } + case x: NumberedInfo => + y match { + case y: NumberedInfo => + x.num - y.num + } + case _ => + assert(x == y) + 0 + } + private def compareSimpleNames(x: SimpleTermName, y: SimpleTermName): Int = { + val until = x.length min y.length + var i = 0 + while (i < until && x(i) == y(i)) i = i + 1 + if (i < until) { + if (x(i) < y(i)) -1 + else /*(x(i) > y(i))*/ 1 + } else { + x.length - y.length + } + } + private def compareTermNames(x: TermName, y: TermName): Int = x match { + case x: SimpleTermName => + y match { + case y: SimpleTermName => compareSimpleNames(x, y) + case _ => -1 + } + case DerivedTermName(xPre, xInfo) => + y match { + case DerivedTermName(yPre, yInfo) => + val s = compareInfos(xInfo, yInfo) + if (s == 0) compareTermNames(xPre, yPre) else s + case _ => 1 + } + } def compare(x: Name, y: Name): Int = { if (x.isTermName && y.isTypeName) 1 else if (x.isTypeName && y.isTermName) -1 else if (x eq y) 0 - else { - val until = x.length min y.length - var i = 0 - - while (i < until && x(i) == y(i)) i = i + 1 - - if (i < until) { - if (x(i) < y(i)) -1 - else /*(x(i) > y(i))*/ 1 - } else { - x.length - y.length - } - } + else compareTermNames(x.toTermName, y.toTermName) } } } diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala index 6090079e5..205798474 100644 --- a/compiler/src/dotty/tools/dotc/core/Scopes.scala +++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala @@ -32,7 +32,7 @@ object Scopes { * This value must be a power of two, so that the index of an element can * be computed as element.hashCode & (hashTable.length - 1) */ - private final val MinHash = 8 + final val MinHashedScopeSize = 8 /** The maximal permissible number of recursions when creating * a hashtable @@ -60,7 +60,7 @@ object Scopes { * or to delete them. These methods are provided by subclass * MutableScope. */ - abstract class Scope extends DotClass with printing.Showable with Iterable[Symbol] { + abstract class Scope extends DotClass with printing.Showable { /** The last scope-entry from which all others are reachable via `prev` */ private[dotc] def lastEntry: ScopeEntry @@ -76,18 +76,37 @@ object Scopes { /** The symbols in this scope in the order they were entered; * inherited from outer ones first. */ - def toList: List[Symbol] + def toList(implicit ctx: Context): List[Symbol] /** Return all symbols as an iterator in the order they were entered in this scope. */ - def iterator: Iterator[Symbol] = toList.iterator + def iterator(implicit ctx: Context): Iterator[Symbol] = toList.iterator + + /** Is the scope empty? */ + def isEmpty: Boolean = lastEntry eq null + + def foreach[U](p: Symbol => U)(implicit ctx: Context): Unit = toList foreach p + + def filter(p: Symbol => Boolean)(implicit ctx: Context): List[Symbol] = { + ensureComplete() + var syms: List[Symbol] = Nil + var e = lastEntry + while ((e ne null) && e.owner == this) { + val sym = e.sym + if (p(sym)) syms = sym :: syms + e = e.prev + } + syms + } + + def find(p: Symbol => Boolean)(implicit ctx: Context): Symbol = filter(p) match { + case sym :: _ => sym + case _ => NoSymbol + } /** Returns a new mutable scope with the same content as this one. */ def cloneScope(implicit ctx: Context): MutableScope - /** Is the scope empty? */ - override def isEmpty: Boolean = lastEntry eq null - /** Lookup a symbol entry matching given name. */ def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry @@ -144,6 +163,12 @@ object Scopes { final def toText(printer: Printer): Text = printer.toText(this) def checkConsistent()(implicit ctx: Context) = () + + /** Ensure that all elements of this scope have been entered. + * Overridden by SymbolLoaders.PackageLoader#PackageScope, where it + * makes sure that all names with `$`'s have been added. + */ + protected def ensureComplete()(implicit ctx: Context): Unit = () } /** A subclass of Scope that defines methods for entering and @@ -155,9 +180,10 @@ object Scopes { class MutableScope protected[Scopes](initElems: ScopeEntry, initSize: Int, val nestingLevel: Int = 0) extends Scope { + /** Scope shares elements with `base` */ protected[Scopes] def this(base: Scope)(implicit ctx: Context) = { this(base.lastEntry, base.size, base.nestingLevel + 1) - ensureCapacity(MinHash)(ctx) // WTH? it seems the implicit is not in scope for a secondary constructor call. + ensureCapacity(MinHashedScopeSize)(ctx) // WTH? it seems the implicit is not in scope for a secondary constructor call. } def this() = this(null, 0, 0) @@ -178,6 +204,8 @@ object Scopes { */ private var elemsCache: List[Symbol] = null + protected def newScopeLikeThis() = new MutableScope() + /** Clone scope, taking care not to force the denotations of any symbols in the scope. */ def cloneScope(implicit ctx: Context): MutableScope = { @@ -187,7 +215,7 @@ object Scopes { entries += e e = e.prev } - val scope = newScope + val scope = newScopeLikeThis() for (i <- entries.length - 1 to 0 by -1) { val e = entries(i) scope.newScopeEntry(e.name, e.sym) @@ -197,7 +225,7 @@ object Scopes { /** create and enter a scope entry with given name and symbol */ protected def newScopeEntry(name: Name, sym: Symbol)(implicit ctx: Context): ScopeEntry = { - ensureCapacity(if (hashTable ne null) hashTable.length else MinHash) + ensureCapacity(if (hashTable ne null) hashTable.length else MinHashedScopeSize) val e = new ScopeEntry(name, sym, this) e.prev = lastEntry lastEntry = e @@ -338,8 +366,9 @@ object Scopes { /** Returns all symbols as a list in the order they were entered in this scope. * Does _not_ include the elements of inherited scopes. */ - override final def toList: List[Symbol] = { + override final def toList(implicit ctx: Context): List[Symbol] = { if (elemsCache eq null) { + ensureComplete() elemsCache = Nil var e = lastEntry while ((e ne null) && e.owner == this) { @@ -351,6 +380,7 @@ object Scopes { } override def implicitDecls(implicit ctx: Context): List[TermRef] = { + ensureComplete() var irefs = new mutable.ListBuffer[TermRef] var e = lastEntry while (e ne null) { @@ -365,25 +395,13 @@ object Scopes { /** Vanilla scope - symbols are stored in declaration order. */ - final def sorted: List[Symbol] = toList - - override def foreach[U](p: Symbol => U): Unit = toList foreach p - - override def filter(p: Symbol => Boolean): List[Symbol] = { - var syms: List[Symbol] = Nil - var e = lastEntry - while ((e ne null) && e.owner == this) { - val sym = e.sym - if (p(sym)) syms = sym :: syms - e = e.prev - } - syms - } + final def sorted(implicit ctx: Context): List[Symbol] = toList override def openForMutations: MutableScope = this /** Check that all symbols in this scope are in their correct hashtable buckets. */ override def checkConsistent()(implicit ctx: Context) = { + ensureComplete() var e = lastEntry while (e != null) { var e1 = lookupEntry(e.name) @@ -407,9 +425,6 @@ object Scopes { scope } - /** Create new scope for the members of package `pkg` */ - def newPackageScope(pkgClass: Symbol): MutableScope = newScope - /** Transform scope of members of `owner` using operation `op` * This is overridden by the reflective compiler to avoid creating new scopes for packages */ @@ -425,7 +440,7 @@ object Scopes { override private[dotc] def lastEntry = null override def size = 0 override def nestingLevel = 0 - override def toList = Nil + override def toList(implicit ctx: Context) = Nil override def cloneScope(implicit ctx: Context): MutableScope = unsupported("cloneScope") override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = null override def lookupNextEntry(entry: ScopeEntry)(implicit ctx: Context): ScopeEntry = null diff --git a/compiler/src/dotty/tools/dotc/core/Signature.scala b/compiler/src/dotty/tools/dotc/core/Signature.scala index fcd1e2376..4699cecf2 100644 --- a/compiler/src/dotty/tools/dotc/core/Signature.scala +++ b/compiler/src/dotty/tools/dotc/core/Signature.scala @@ -34,6 +34,14 @@ import scala.annotation.tailrec case class Signature(paramsSig: List[TypeName], resSig: TypeName) { import Signature._ +/* FIXME does not compile under dotty, we get a missing param error + def checkUnqual(name: TypeName) = name mapParts { part => + assert(!part.contains('.'), name) + part + } + paramsSig.foreach(checkUnqual) + checkUnqual(resSig) +*/ /** Two names are consistent if they are the same or one of them is tpnme.Uninstantiated */ private def consistent(name1: TypeName, name2: TypeName) = name1 == name2 || name1 == tpnme.Uninstantiated || name2 == tpnme.Uninstantiated diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index e7928fd09..92befdacb 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -15,6 +15,34 @@ object StdNames { /** Base strings from which synthetic names are derived. */ + object str { + final val SETTER_SUFFIX = "_$eq" + final val EXPAND_SEPARATOR = "$$" + final val TRAIT_SETTER_SEPARATOR = "$_setter_$" + final val SUPER_PREFIX = "super$" + final val INITIALIZER_PREFIX = "initial$" + final val SHADOWED_PREFIX = "(shadowed)" + final val AVOID_CLASH_SUFFIX = "$_avoid_name_clash_$" + final val MODULE_SUFFIX = NameTransformer.MODULE_SUFFIX_STRING + final val DEFAULT_GETTER = "$default$" + final val LOCALDUMMY_PREFIX = "<local " // owner of local blocks + final val ANON_CLASS = "$anon" + final val ANON_FUN = "$anonfun" + + final val INTERPRETER_IMPORT_WRAPPER = "$iw" + final val INTERPRETER_LINE_PREFIX = "line" + final val INTERPRETER_VAR_PREFIX = "res" + final val INTERPRETER_WRAPPER_SUFFIX = "$object" + + final val Function = "Function" + final val ImplicitFunction = "ImplicitFunction" + final val AbstractFunction = "AbstractFunction" + final val Tuple = "Tuple" + final val Product = "Product" + + def sanitize(str: String) = str.replaceAll("""[<>]""", """\$""") + } + abstract class DefinedNames[N <: Name] { protected implicit def fromString(s: String): N protected def fromName(name: Name): N = fromString(name.toString) @@ -84,44 +112,30 @@ object StdNames { final val HASHkw: N = kw("#") final val ATkw: N = kw("@") - val ANON_CLASS: N = "$anon" - val ANON_FUN: N = "$anonfun" - val BITMAP_PREFIX: N = "bitmap$" + val ANON_CLASS: N = str.ANON_CLASS + val ANON_FUN: N = str.ANON_FUN + val BITMAP_PREFIX: N = "bitmap$" // @darkdimius: $bitmap? Also, the next 4 names are unused. val BITMAP_NORMAL: N = BITMAP_PREFIX // initialization bitmap for public/protected lazy vals val BITMAP_TRANSIENT: N = BITMAP_PREFIX + "trans$" // initialization bitmap for transient lazy vals val BITMAP_CHECKINIT: N = BITMAP_PREFIX + "init$" // initialization bitmap for checkinit values val BITMAP_CHECKINIT_TRANSIENT: N = BITMAP_PREFIX + "inittrans$" // initialization bitmap for transient checkinit values - val DEFAULT_GETTER: N = "$default$" - val DEFAULT_GETTER_INIT: N = NameTransformer.encode("<init>") + val DEFAULT_GETTER: N = str.DEFAULT_GETTER + val DEFAULT_GETTER_INIT: N = "$lessinit$greater" val DO_WHILE_PREFIX: N = "doWhile$" + val DOLLAR_VALUES: N = "$values" + val DOLLAR_NEW: N = "$new" val EMPTY: N = "" val EMPTY_PACKAGE: N = Names.EMPTY_PACKAGE.toString - val EVIDENCE_PARAM_PREFIX: N = "evidence$" - val DEP_PARAM_PREFIX = "<param>" val EXCEPTION_RESULT_PREFIX: N = "exceptionResult" - val EXPAND_SEPARATOR: N = "$$" + val EXPAND_SEPARATOR: N = str.EXPAND_SEPARATOR val IMPL_CLASS_SUFFIX: N = "$class" val IMPORT: N = "<import>" - val INLINE_ACCESSOR_PREFIX = "$inlineAccessor$" - val INTERPRETER_IMPORT_WRAPPER: N = "$iw" - val INTERPRETER_LINE_PREFIX: N = "line" - val INTERPRETER_VAR_PREFIX: N = "res" - val INTERPRETER_WRAPPER_SUFFIX: N = "$object" - val LOCALDUMMY_PREFIX: N = "<local " // owner of local blocks val MODULE_SUFFIX: N = NameTransformer.MODULE_SUFFIX_STRING - val AVOID_CLASH_SUFFIX: N = "$_avoid_name_clash_$" - val MODULE_VAR_SUFFIX: N = "$module" val NAME_JOIN: N = NameTransformer.NAME_JOIN_STRING - val USCORE_PARAM_PREFIX: N = "_$" val OPS_PACKAGE: N = "<special-ops>" val OVERLOADED: N = "<overloaded>" val PACKAGE: N = "package" - val PACKAGE_CLS: N = "package$" - val PROTECTED_PREFIX: N = "protected$" - val PROTECTED_SET_PREFIX: N = PROTECTED_PREFIX + "set" val ROOT: N = "<root>" - val SHADOWED: N = "(shadowed)" // tag to be used until we have proper name kinds - val SINGLETON_SUFFIX: N = ".type" val SPECIALIZED_SUFFIX: N = "$sp" val SUPER_PREFIX: N = "super$" val WHILE_PREFIX: N = "while$" @@ -129,11 +143,7 @@ object StdNames { val INITIALIZER_PREFIX: N = "initial$" val COMPANION_MODULE_METHOD: N = "companion$module" val COMPANION_CLASS_METHOD: N = "companion$class" - val TRAIT_SETTER_SEPARATOR: N = "$_setter_$" - val DIRECT_SUFFIX: N = "$direct" - val LAZY_IMPLICIT_PREFIX: N = "$lazy_implicit$" - val DOLLAR_VALUES: N = "$values" - val DOLLAR_NEW: N = "$new" + val TRAIT_SETTER_SEPARATOR: N = str.TRAIT_SETTER_SEPARATOR // value types (and AnyRef) are all used as terms as well // as (at least) arguments to the @specialize annotation. @@ -167,7 +177,6 @@ object StdNames { // fictions we use as both types and terms final val ERROR: N = "<error>" - final val ERRORenc: N = encode("<error>") final val NO_NAME: N = "<none>" // formerly NOSYMBOL final val WILDCARD: N = "_" @@ -181,23 +190,18 @@ object StdNames { final val REIFY_TREECREATOR_PREFIX: N = "$treecreator" final val REIFY_TYPECREATOR_PREFIX: N = "$typecreator" - final val AbstractFunction: N = "AbstractFunction" final val Any: N = "Any" final val AnyVal: N = "AnyVal" final val ExprApi: N = "ExprApi" - final val Function: N = "Function" - final val ImplicitFunction: N = "ImplicitFunction" final val Mirror: N = "Mirror" final val Nothing: N = "Nothing" final val Null: N = "Null" final val Object: N = "Object" final val PartialFunction: N = "PartialFunction" final val PrefixType: N = "PrefixType" - final val Product: N = "Product" final val Serializable: N = "Serializable" final val Singleton: N = "Singleton" final val Throwable: N = "Throwable" - final val Tuple: N = "Tuple" final val ClassfileAnnotation: N = "ClassfileAnnotation" final val ClassManifest: N = "ClassManifest" @@ -241,11 +245,8 @@ object StdNames { val EVT2U: N = "evt2u$" val EQEQ_LOCAL_VAR: N = "eqEqTemp$" val FAKE_LOCAL_THIS: N = "this$" - val LAZY_LOCAL: N = "$lzy" - val LAZY_LOCAL_INIT: N = "$lzyINIT" val LAZY_FIELD_OFFSET: N = "OFFSET$" val LAZY_SLOW_SUFFIX: N = "$lzycompute" - val LOCAL_SUFFIX: N = "$$local" val UNIVERSE_BUILD_PREFIX: N = "$u.build." val UNIVERSE_BUILD: N = "$u.build" val UNIVERSE_PREFIX: N = "$u." @@ -259,13 +260,10 @@ object StdNames { val REIFY_SYMDEF_PREFIX: N = "symdef$" val MODULE_INSTANCE_FIELD: N = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$" val OUTER: N = "$outer" - val OUTER_LOCAL: N = "$outer " - val OUTER_SELECT: N = "_<outer>" // emitted by inliner, replaced by outer path in explicitouter val REFINE_CLASS: N = "<refinement>" val ROOTPKG: N = "_root_" val SELECTOR_DUMMY: N = "<unapply-selector>" val SELF: N = "$this" - val SETTER_SUFFIX: N = encode("_=") val SKOLEM: N = "<skolem>" val SPECIALIZED_INSTANCE: N = "specInstance$" val THIS: N = "_$this" @@ -440,7 +438,6 @@ object StdNames { val lang: N = "lang" val length: N = "length" val lengthCompare: N = "lengthCompare" - val liftedTree: N = "liftedTree" val `macro` : N = "macro" val macroThis : N = "_this" val macroContext : N = "c" @@ -458,7 +455,6 @@ object StdNames { val ne: N = "ne" val newFreeTerm: N = "newFreeTerm" val newFreeType: N = "newFreeType" - val newNestedSymbol: N = "newNestedSymbol" val newScopeWith: N = "newScopeWith" val next: N = "next" val nmeNewTermName: N = "newTermName" @@ -541,6 +537,11 @@ object StdNames { val synthSwitch: N = "$synthSwitch" val _scope: N = "$scope" + val nothingClass: N = "Nothing$" + val nullClass: N = "Null$" + + val falseModuleClassNames = Set(nothingClass, nullClass, nothingRuntimeClass, nullRuntimeClass) + // unencoded operators object raw { final val AMP : N = "&" @@ -661,22 +662,6 @@ object StdNames { val isBoxedNumberOrBoolean: N = "isBoxedNumberOrBoolean" val isBoxedNumber: N = "isBoxedNumber" - - val reflPolyCacheName: N = "reflPoly$Cache" - val reflClassCacheName: N = "reflClass$Cache" - val reflParamsCacheName: N = "reflParams$Cache" - val reflMethodCacheName: N = "reflMethod$Cache" - val reflMethodName: N = "reflMethod$Method" - - private val reflectionCacheNames = Set[N]( - reflPolyCacheName, - reflClassCacheName, - reflParamsCacheName, - reflMethodCacheName, - reflMethodName - ) - - def isReflectionCacheName(name: Name) = reflectionCacheNames exists (name startsWith _) } class ScalaTermNames extends ScalaNames[TermName] { @@ -723,7 +708,7 @@ object StdNames { } def localDummyName(clazz: Symbol)(implicit ctx: Context): TermName = - LOCALDUMMY_PREFIX ++ clazz.name ++ ">" + termName(str.LOCALDUMMY_PREFIX + clazz.name + ">") def newBitmapName(bitmapPrefix: TermName, n: Int): TermName = bitmapPrefix ++ n.toString diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 6d1a006ed..1e0beb5f3 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -4,7 +4,7 @@ package core import Periods._, Contexts._, Symbols._, Denotations._, Names._, NameOps._, Annotations._ import Types._, Flags._, Decorators._, DenotTransformers._, StdNames._, Scopes._, Comments._ -import NameOps._ +import NameOps._, NameKinds._ import Scopes.Scope import collection.mutable import collection.immutable.BitSet @@ -107,7 +107,7 @@ object SymDenotations { class SymDenotation private[SymDenotations] ( symbol: Symbol, ownerIfExists: Symbol, - final val name: Name, + initName: Name, initFlags: FlagSet, initInfo: Type, initPrivateWithin: Symbol = NoSymbol) extends SingleDenotation(symbol) { @@ -125,11 +125,18 @@ object SymDenotations { // ------ Getting and setting fields ----------------------------- + private[this] var myName = initName private[this] var myFlags: FlagSet = adaptFlags(initFlags) private[this] var myInfo: Type = initInfo private[this] var myPrivateWithin: Symbol = initPrivateWithin private[this] var myAnnotations: List[Annotation] = Nil + /** The name of the symbol */ + def name = myName + + /** Update the name; only called when unpickling top-level classes */ + def name_=(n: Name) = myName = n + /** The owner of the symbol; overridden in NoDenotation */ def owner: Symbol = ownerIfExists @@ -252,7 +259,7 @@ object SymDenotations { */ def effectiveName(implicit ctx: Context) = if (this is ModuleClass) name.stripModuleClassSuffix - else name.stripAvoidClashSuffix + else name.exclude(AvoidClashName) /** The privateWithin boundary, NoSymbol if no boundary is given. */ @@ -367,7 +374,7 @@ object SymDenotations { /** The expanded name of this denotation. */ final def expandedName(implicit ctx: Context) = - if (is(ExpandedName) || isConstructor) name + if (name.is(ExpandedName) || isConstructor) name else { def legalize(name: Name): Name = // JVM method names may not contain `<' or `>' characters if (is(Method)) name.replace('<', '(').replace('>', ')') else name @@ -377,49 +384,50 @@ object SymDenotations { // might have been moved from different origins into the same class /** The name with which the denoting symbol was created */ - final def originalName(implicit ctx: Context) = { - val d = initial - if (d is ExpandedName) d.name.unexpandedName else d.name // !!!DEBUG, was: effectiveName - } + final def originalName(implicit ctx: Context) = + initial.effectiveName /** The encoded full path name of this denotation, where outer names and inner names * are separated by `separator` strings. * Never translates expansions of operators back to operator symbol. - * Drops package objects. Represents terms in the owner chain by a simple `~`. + * Drops package objects. Represents each term in the owner chain by a simple `~`. * (Note: scalac uses nothing to represent terms, which can cause name clashes * between same-named definitions in different enclosing methods. Before this commit * we used `$' but this can cause ambiguities with the class separator '$'). * A separator "" means "flat name"; the real separator in this case is "$" and * enclosing packages do not form part of the name. */ - def fullNameSeparated(separator: String)(implicit ctx: Context): Name = { - var sep = separator - var stopAtPackage = false - if (sep.isEmpty) { - sep = "$" - stopAtPackage = true - } + def fullNameSeparated(kind: QualifiedNameKind)(implicit ctx: Context): Name = if (symbol == NoSymbol || owner == NoSymbol || owner.isEffectiveRoot || - stopAtPackage && owner.is(PackageClass)) name + kind == FlatName && owner.is(PackageClass)) name else { + var filler = "" var encl = owner while (!encl.isClass && !encl.isPackageObject) { encl = encl.owner - sep += "~" + 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) = + kind(prefix.toTermName, if (filler.isEmpty) n else termName(filler + n)) + val fn = name rewrite { + case name: SimpleTermName => qualify(name) + case name @ AnyQualifiedName(_, _) => qualify(name.toSimpleName) } - if (owner.is(ModuleClass, butNot = Package) && sep == "$") sep = "" // duplicate scalac's behavior: don't write a double '$$' for module class members. - val fn = encl.fullNameSeparated(separator) ++ sep ++ name if (isType) fn.toTypeName else fn.toTermName } - } + /** The encoded flat name of this denotation, where joined names are separated by `separator` characters. */ - def flatName(implicit ctx: Context): Name = fullNameSeparated("") + def flatName(implicit ctx: Context): Name = fullNameSeparated(FlatName) /** `fullName` where `.' is the separator character */ - def fullName(implicit ctx: Context): Name = fullNameSeparated(".") + def fullName(implicit ctx: Context): Name = fullNameSeparated(QualifiedName) // ----- Tests ------------------------------------------------- @@ -460,13 +468,13 @@ object SymDenotations { /** Is this symbol an anonymous class? */ final def isAnonymousClass(implicit ctx: Context): Boolean = - isClass && (initial.name startsWith tpnme.ANON_CLASS) + isClass && (initial.name startsWith str.ANON_CLASS) final def isAnonymousFunction(implicit ctx: Context) = - this.symbol.is(Method) && (initial.name startsWith nme.ANON_FUN) + this.symbol.is(Method) && (initial.name startsWith str.ANON_FUN) final def isAnonymousModuleVal(implicit ctx: Context) = - this.symbol.is(ModuleVal) && (initial.name startsWith nme.ANON_CLASS) + this.symbol.is(ModuleVal) && (initial.name startsWith str.ANON_CLASS) /** Is this a companion class method or companion object method? * These methods are generated by Symbols#synthesizeCompanionMethod @@ -505,8 +513,10 @@ object SymDenotations { /** Is this symbol a package object or its module class? */ def isPackageObject(implicit ctx: Context): Boolean = { - val poName = if (isType) nme.PACKAGE_CLS else nme.PACKAGE - (name.toTermName == poName) && (owner is Package) && (this is Module) + val nameMatches = + if (isType) name == tpnme.PACKAGE.moduleClassName + else name == nme.PACKAGE + nameMatches && (owner is Package) && (this is Module) } /** Is this symbol an abstract type? */ @@ -922,14 +932,15 @@ object SymDenotations { * and which is also defined in the same scope and compilation unit. * NoSymbol if this class does not exist. */ - final def companionClass(implicit ctx: Context): Symbol = { - val companionMethod = info.decls.denotsNamed(nme.COMPANION_CLASS_METHOD, selectPrivate).first - - if (companionMethod.exists) - companionMethod.info.resultType.classSymbol - else - NoSymbol - } + final def companionClass(implicit ctx: Context): Symbol = + if (is(Package)) NoSymbol + else { + val companionMethod = info.decls.denotsNamed(nme.COMPANION_CLASS_METHOD, selectPrivate).first + if (companionMethod.exists) + companionMethod.info.resultType.classSymbol + else + NoSymbol + } final def scalacLinkedClass(implicit ctx: Context): Symbol = if (this is ModuleClass) companionNamed(effectiveName.toTypeName) @@ -1198,9 +1209,7 @@ object SymDenotations { /** If denotation is private, remove the Private flag and expand the name if necessary */ def ensureNotPrivate(implicit ctx: Context) = if (is(Private)) - copySymDenotation( - name = expandedName, - initFlags = this.flags &~ Private | ExpandedName) + copySymDenotation(name = expandedName, initFlags = this.flags &~ Private) else this } @@ -1209,18 +1218,19 @@ object SymDenotations { class ClassDenotation private[SymDenotations] ( symbol: Symbol, ownerIfExists: Symbol, - name: Name, + initName: Name, initFlags: FlagSet, initInfo: Type, initPrivateWithin: Symbol, initRunId: RunId) - extends SymDenotation(symbol, ownerIfExists, name, initFlags, initInfo, initPrivateWithin) { + extends SymDenotation(symbol, ownerIfExists, initName, initFlags, initInfo, initPrivateWithin) { import util.LRUCache // ----- denotation fields and accessors ------------------------------ - if (initFlags is (Module, butNot = Package)) assert(name.isModuleClassName, s"module naming inconsistency: $name") + if (initFlags is (Module, butNot = Package)) + assert(name.is(ModuleClassName), s"module naming inconsistency: ${name.debugString}") /** The symbol asserted to have type ClassSymbol */ def classSymbol: ClassSymbol = symbol.asInstanceOf[ClassSymbol] @@ -1530,7 +1540,7 @@ object SymDenotations { !(this is Frozen) || (scope ne this.unforcedDecls) || sym.hasAnnotation(defn.ScalaStaticAnnot) || - sym.name.isInlineAccessor || + sym.name.is(InlineAccessorName) || isUsecase, i"trying to enter $sym in $this, frozen = ${this is Frozen}") scope.enter(sym) @@ -1752,13 +1762,13 @@ object SymDenotations { } } - private[this] var fullNameCache: SimpleMap[String, Name] = SimpleMap.Empty - override final def fullNameSeparated(separator: String)(implicit ctx: Context): Name = { - val cached = fullNameCache(separator) + private[this] var fullNameCache: SimpleMap[QualifiedNameKind, Name] = SimpleMap.Empty + override final def fullNameSeparated(kind: QualifiedNameKind)(implicit ctx: Context): Name = { + val cached = fullNameCache(kind) if (cached != null) cached else { - val fn = super.fullNameSeparated(separator) - fullNameCache = fullNameCache.updated(separator, fn) + val fn = super.fullNameSeparated(kind) + fullNameCache = fullNameCache.updated(kind, fn) fn } } @@ -1770,8 +1780,8 @@ object SymDenotations { def constrNamed(cname: TermName) = info.decls.denotsNamed(cname).last.symbol // denotsNamed returns Symbols in reverse order of occurrence if (this.is(ImplClass)) constrNamed(nme.TRAIT_CONSTRUCTOR) // ignore normal constructor - else - constrNamed(nme.CONSTRUCTOR).orElse(constrNamed(nme.TRAIT_CONSTRUCTOR)) + else if (this.is(Package)) NoSymbol + else constrNamed(nme.CONSTRUCTOR).orElse(constrNamed(nme.TRAIT_CONSTRUCTOR)) } /** The parameter accessors of this class. Term and type accessors, diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 79f8a6a45..e4d2d446f 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -14,6 +14,7 @@ import Contexts._, Symbols._, Flags._, SymDenotations._, Types._, Scopes._, util import StdNames._, NameOps._ import Decorators.{PreNamedString, StringInterpolators} import classfile.ClassfileParser +import util.Stats import scala.util.control.NonFatal object SymbolLoaders { @@ -148,23 +149,79 @@ class SymbolLoaders { override def sourceModule(implicit ctx: Context) = _sourceModule def description = "package loader " + classpath.name - private[core] val currentDecls: MutableScope = newScope + private var enterFlatClasses: Option[Context => Unit] = None + + Stats.record("package scopes") + + /** The scope of a package. This is different from a normal scope + * in three aspects: + * + * 1. Names of scope entries are kept in mangled form. + * 2. Some function types in the `scala` package are synthesized. + */ + final class PackageScope extends MutableScope { + override def newScopeEntry(name: Name, sym: Symbol)(implicit ctx: Context): ScopeEntry = + super.newScopeEntry(name.mangled, sym) + + override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { + val mangled = name.mangled + val e = super.lookupEntry(mangled) + if (e != null) e + else if (_sourceModule.initialDenot.name == nme.scala_ && _sourceModule == defn.ScalaPackageVal && + name.isTypeName && name.isSyntheticFunction) + newScopeEntry(defn.newFunctionNTrait(name.asTypeName)) + else if (isFlatName(mangled.toSimpleName) && enterFlatClasses.isDefined) { + Stats.record("package scopes with flatnames entered") + enterFlatClasses.get(ctx) + lookupEntry(name) + } + else e + } + + override def ensureComplete()(implicit ctx: Context) = + for (enter <- enterFlatClasses) enter(ctx) + + override def newScopeLikeThis() = new PackageScope + } + + private[core] val currentDecls: MutableScope = new PackageScope() + + def isFlatName(name: SimpleTermName) = name.lastIndexOf('$', name.length - 2) >= 0 + + def isFlatName(classRep: ClassPath#ClassRep) = { + val idx = classRep.name.indexOf('$') + idx >= 0 && idx < classRep.name.length - 1 + } + + def maybeModuleClass(classRep: ClassPath#ClassRep) = classRep.name.last == '$' + + private def enterClasses(root: SymDenotation, flat: Boolean)(implicit ctx: Context) = { + def isAbsent(classRep: ClassPath#ClassRep) = + !root.unforcedDecls.lookup(classRep.name.toTypeName).exists + + if (!root.isRoot) { + for (classRep <- classpath.classes) + if (!maybeModuleClass(classRep) && isFlatName(classRep) == flat && + (!flat || isAbsent(classRep))) // on 2nd enter of flat names, check that the name has not been entered before + initializeFromClassPath(root.symbol, classRep) + for (classRep <- classpath.classes) + if (maybeModuleClass(classRep) && isFlatName(classRep) == flat && + isAbsent(classRep)) + initializeFromClassPath(root.symbol, classRep) + } + } def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = { assert(root is PackageClass, root) - def maybeModuleClass(classRep: ClassPath#ClassRep) = classRep.name.last == '$' val pre = root.owner.thisType root.info = ClassInfo(pre, root.symbol.asClass, Nil, currentDecls, pre select sourceModule) if (!sourceModule.isCompleted) sourceModule.completer.complete(sourceModule) - if (!root.isRoot) { - for (classRep <- classpath.classes) - if (!maybeModuleClass(classRep)) - initializeFromClassPath(root.symbol, classRep) - for (classRep <- classpath.classes) - if (maybeModuleClass(classRep) && !root.unforcedDecls.lookup(classRep.name.toTypeName).exists) - initializeFromClassPath(root.symbol, classRep) + enterFlatClasses = Some { ctx => + enterFlatClasses = None + enterClasses(root, flat = true)(ctx) } + enterClasses(root, flat = false) if (!root.isEmptyPackage) for (pkg <- classpath.packages) enterPackage(root.symbol, pkg) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 95ff1cb75..e0d9aca2b 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -19,6 +19,7 @@ import util.Positions._ import DenotTransformers._ import StdNames._ import NameOps._ +import NameKinds.LazyImplicitName import ast.tpd.Tree import ast.TreeTypeMap import Constants.Constant @@ -260,7 +261,7 @@ trait Symbols { this: Context => /** Create a synthetic lazy implicit value */ def newLazyImplicit(info: Type) = - newSymbol(owner, freshName(nme.LAZY_IMPLICIT_PREFIX).toTermName, Lazy, info) + newSymbol(owner, LazyImplicitName.fresh(), Lazy, info) /** Create a symbol representing a selftype declaration for class `cls`. */ def newSelfSym(cls: ClassSymbol, name: TermName = nme.WILDCARD, selfInfo: Type = NoType): TermSymbol = diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 94b726491..82051b66c 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -11,6 +11,7 @@ import util.Stats._ import util.common._ import Names._ import NameOps._ +import NameKinds._ import Flags._ import StdNames.tpnme import util.Positions.Position @@ -464,11 +465,6 @@ class TypeApplications(val self: Type) extends AnyVal { self case _ => val v = tparam.paramVariance - /* Not neeeded. - if (v > 0 && !(tparam is Local) && !(tparam is ExpandedTypeParam)) TypeBounds.upper(self) - else if (v < 0 && !(tparam is Local) && !(tparam is ExpandedTypeParam)) TypeBounds.lower(self) - else - */ TypeAlias(self, v) } @@ -510,13 +506,14 @@ class TypeApplications(val self: Type) extends AnyVal { */ final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type = ctx.traceIndented(s"btwa ${self.show} wrt $base", core, show = true) { def default = self.baseTypeRef(base).appliedTo(baseArgInfos(base)) + def isExpandedTypeParam(sym: Symbol) = sym.is(TypeParam) && sym.name.is(ExpandedName) self match { case tp: TypeRef => tp.info match { case TypeBounds(_, hi) => hi.baseTypeWithArgs(base) case _ => default } - case tp @ RefinedType(parent, name, _) if !tp.member(name).symbol.is(ExpandedTypeParam) => + case tp @ RefinedType(parent, name, _) if !isExpandedTypeParam(tp.member(name).symbol) => tp.wrapIfMember(parent.baseTypeWithArgs(base)) case tp: TermRef => tp.underlying.baseTypeWithArgs(base) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 4c69c9484..c8c1886cc 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -7,6 +7,7 @@ import Symbols._ import Flags._ import Names._ import StdNames._, NameOps._ +import NameKinds.{ShadowedName, SkolemName} import Scopes._ import Constants._ import Contexts._ @@ -1594,7 +1595,7 @@ object Types { } protected def asMemberOf(prefix: Type, allowPrivate: Boolean)(implicit ctx: Context): Denotation = - if (name.isShadowedName) prefix.nonPrivateMember(name.revertShadowed) + if (name.is(ShadowedName)) prefix.nonPrivateMember(name.exclude(ShadowedName)) else if (!allowPrivate) prefix.nonPrivateMember(name) else prefix.member(name) @@ -1730,7 +1731,7 @@ object Types { * the public name. */ def shadowed(implicit ctx: Context): NamedType = - NamedType(prefix, name.shadowedName) + NamedType(prefix, name.derived(ShadowedName)) override def equals(that: Any) = that match { case that: NamedType => @@ -1804,7 +1805,7 @@ object Types { fixDenot(TermRef.withSig(prefix, name, sig), prefix) override def shadowed(implicit ctx: Context): NamedType = - fixDenot(TermRef.withSig(prefix, name.shadowedName, sig), prefix) + fixDenot(TermRef.withSig(prefix, name.derived(ShadowedName), sig), prefix) override def equals(that: Any) = that match { case that: TermRefWithSignature => @@ -3000,9 +3001,9 @@ object Types { override def hashCode: Int = identityHash override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] - private var myRepr: String = null - def repr(implicit ctx: Context) = { - if (myRepr == null) myRepr = ctx.freshName("?") + private var myRepr: Name = null + def repr(implicit ctx: Context): Name = { + if (myRepr == null) myRepr = SkolemName.fresh() myRepr } diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index da875c906..27afa4d09 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -5,6 +5,7 @@ package classfile import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._, Decorators._ import SymDenotations._, unpickleScala2.Scala2Unpickler._, Constants._, Annotations._, util.Positions._ +import NameKinds.{ModuleClassName, DefaultGetterName} import ast.tpd._ import java.io.{ File, IOException } import java.lang.Integer.toHexString @@ -25,6 +26,8 @@ class ClassfileParser( classRoot: ClassDenotation, moduleRoot: ClassDenotation)(ictx: Context) { + //println(s"parsing ${classRoot.name.debugString} ${moduleRoot.name.debugString}") + import ClassfileConstants._ import ClassfileParser._ @@ -36,7 +39,7 @@ class ClassfileParser( protected val staticScope: MutableScope = newScope // the scope of all static definitions protected var pool: ConstantPool = _ // the classfile's constant pool - protected var currentClassName: Name = _ // JVM name of the current class + protected var currentClassName: SimpleTermName = _ // JVM name of the current class protected var classTParams = Map[Name,Symbol]() classRoot.info = (new NoCompleter).withDecls(instanceScope) @@ -44,8 +47,8 @@ class ClassfileParser( private def currentIsTopLevel(implicit ctx: Context) = classRoot.owner is Flags.PackageClass - private def mismatchError(c: Symbol) = - throw new IOException(s"class file '${in.file}' has location not matching its contents: contains $c") + private def mismatchError(className: SimpleTermName) = + throw new IOException(s"class file '${in.file}' has location not matching its contents: contains class $className") def run()(implicit ctx: Context): Option[Embedded] = try { ctx.debuglog("[class] >> " + classRoot.fullName) @@ -89,10 +92,8 @@ class ClassfileParser( val nameIdx = in.nextChar currentClassName = pool.getClassName(nameIdx) - if (currentIsTopLevel) { - val c = pool.getClassSymbol(nameIdx) - if (c != classRoot.symbol) mismatchError(c) - } + if (currentIsTopLevel && currentClassName != classRoot.fullName.toSimpleName) + mismatchError(currentClassName) addEnclosingTParams() @@ -239,21 +240,21 @@ class ClassfileParser( final def objToAny(tp: Type)(implicit ctx: Context) = if (tp.isDirectRef(defn.ObjectClass) && !ctx.phase.erasedTypes) defn.AnyType else tp - private def sigToType(sig: TermName, owner: Symbol = null)(implicit ctx: Context): Type = { + private def sigToType(sig: SimpleTermName, owner: Symbol = null)(implicit ctx: Context): Type = { var index = 0 val end = sig.length def accept(ch: Char): Unit = { assert(sig(index) == ch, (sig(index), ch)) index += 1 } - def subName(isDelimiter: Char => Boolean): TermName = { + def subName(isDelimiter: Char => Boolean): SimpleTermName = { val start = index while (!isDelimiter(sig(index))) { index += 1 } sig.slice(start, index) } // Warning: sigToType contains nested completers which might be forced in a later run! // So local methods need their own ctx parameters. - def sig2type(tparams: immutable.Map[Name,Symbol], skiptvs: Boolean)(implicit ctx: Context): Type = { + def sig2type(tparams: immutable.Map[Name, Symbol], skiptvs: Boolean)(implicit ctx: Context): Type = { val tag = sig(index); index += 1 (tag: @switch) match { case BYTE_TAG => defn.ByteType @@ -590,7 +591,7 @@ class ClassfileParser( def addDefaultGetter(attr: Symbol, n: Int) = ctx.newSymbol( owner = moduleRoot.symbol, - name = nme.CONSTRUCTOR.defaultGetterName(n), + name = DefaultGetterName(nme.CONSTRUCTOR, n), flags = attr.flags & Flags.AccessFlags, info = defn.NothingType).entered @@ -647,7 +648,10 @@ class ClassfileParser( * and implicitly current class' superclasses. */ private def enterOwnInnerClasses()(implicit ctx: Context): Unit = { - def className(name: Name): Name = name.drop(name.lastIndexOf('.') + 1) + def className(name: Name): Name = { + val name1 = name.toSimpleName + name1.drop(name1.lastIndexOf('.') + 1) + } def enterClassAndModule(entry: InnerClassEntry, file: AbstractFile, jflags: Int) = { ctx.base.loaders.enterClassAndModule( @@ -883,7 +887,7 @@ class ClassfileParser( private val len = in.nextChar private val starts = new Array[Int](len) private val values = new Array[AnyRef](len) - private val internalized = new Array[TermName](len) + private val internalized = new Array[SimpleTermName](len) { var i = 1 while (i < starts.length) { @@ -910,12 +914,12 @@ class ClassfileParser( } /** Return the name found at given index. */ - def getName(index: Int): TermName = { + def getName(index: Int): SimpleTermName = { if (index <= 0 || len <= index) errorBadIndex(index) values(index) match { - case name: TermName => name + case name: SimpleTermName => name case null => val start = starts(index) if (in.buf(start).toInt != CONSTANT_UTF8) errorBadTag(start) @@ -926,7 +930,7 @@ class ClassfileParser( } /** Return the name found at given index in the constant pool, with '/' replaced by '.'. */ - def getExternalName(index: Int): TermName = { + def getExternalName(index: Int): SimpleTermName = { if (index <= 0 || len <= index) errorBadIndex(index) @@ -943,9 +947,9 @@ class ClassfileParser( val start = starts(index) if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start) val name = getExternalName(in.getChar(start + 1)) - if (name.isModuleClassName && (name ne nme.nothingRuntimeClass) && (name ne nme.nullRuntimeClass)) + if (name.endsWith("$") && (name ne nme.nothingRuntimeClass) && (name ne nme.nullRuntimeClass)) // Null$ and Nothing$ ARE classes - c = ctx.requiredModule(name.sourceModuleName) + c = ctx.requiredModule(name.dropRight(1)) else c = classNameToSymbol(name) values(index) = c } @@ -955,7 +959,7 @@ class ClassfileParser( /** Return the external name of the class info structure found at 'index'. * Use 'getClassSymbol' if the class is sure to be a top-level class. */ - def getClassName(index: Int): TermName = { + def getClassName(index: Int): SimpleTermName = { val start = starts(index) if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start) getExternalName(in.getChar(start + 1)) @@ -995,7 +999,7 @@ class ClassfileParser( val start = starts(index) if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start) val name = getExternalName(in.getChar(start + 1)) - if (name(0) == ARRAY_TAG) { + if (name.firstPart(0) == ARRAY_TAG) { c = sigToType(name) values(index) = c } else { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala index 2c93819d5..28916a781 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala @@ -19,12 +19,12 @@ object DottyUnpickler { class TreeSectionUnpickler(posUnpickler: Option[PositionUnpickler]) extends SectionUnpickler[TreeUnpickler]("ASTs") { - def unpickle(reader: TastyReader, tastyName: TastyName.Table) = - new TreeUnpickler(reader, tastyName, posUnpickler) + def unpickle(reader: TastyReader, nameAtRef: NameTable) = + new TreeUnpickler(reader, nameAtRef, posUnpickler) } class PositionsSectionUnpickler extends SectionUnpickler[PositionUnpickler]("Positions") { - def unpickle(reader: TastyReader, tastyName: TastyName.Table) = + def unpickle(reader: TastyReader, nameAtRef: NameTable) = new PositionUnpickler(reader) } } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala index 3ff7298ce..270d6be56 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala @@ -4,84 +4,83 @@ package core package tasty import collection.mutable -import Names.{Name, chrs} -import Decorators._, NameOps._ +import Names.{Name, chrs, SimpleTermName, DerivedTermName} +import NameOps.NameDecorator +import NameKinds._ +import Decorators._ import TastyBuffer._ import scala.io.Codec -import TastyName._ import TastyFormat._ class NameBuffer extends TastyBuffer(10000) { import NameBuffer._ - private val nameRefs = new mutable.LinkedHashMap[TastyName, NameRef] + private val nameRefs = new mutable.LinkedHashMap[Name, NameRef] - def nameIndex(name: TastyName): NameRef = nameRefs.get(name) match { - case Some(ref) => - ref - case None => - val ref = NameRef(nameRefs.size) - nameRefs(name) = ref - ref - } def nameIndex(name: Name): NameRef = { - val tname = - if (name.isShadowedName) Shadowed(nameIndex(name.revertShadowed)) - else Simple(name.toTermName) - nameIndex(tname) - } - - def nameIndex(str: String): NameRef = nameIndex(str.toTermName) - - def fullNameIndex(name: Name): NameRef = { - val pos = name.lastIndexOf('.') - if (pos > 0) - nameIndex(Qualified(fullNameIndex(name.take(pos)), nameIndex(name.drop(pos + 1)))) - else - nameIndex(name) + val name1 = name.toTermName + nameRefs.get(name1) match { + case Some(ref) => + ref + case None => + name1 match { + case SignedName(original, Signature(params, result)) => + nameIndex(original); nameIndex(result); params.foreach(nameIndex) + case AnyQualifiedName(prefix, name) => + nameIndex(prefix); nameIndex(name) + case AnyUniqueName(original, separator, num) => + nameIndex(separator.toTermName) + if (!original.isEmpty) nameIndex(original) + case DerivedTermName(original, _) => + nameIndex(original) + case _ => + } + val ref = NameRef(nameRefs.size) + nameRefs(name1) = ref + ref + } } private def withLength(op: => Unit, lengthWidth: Int = 1): Unit = { val lengthAddr = currentAddr for (i <- 0 until lengthWidth) writeByte(0) op - val length = currentAddr.index - lengthAddr.index - 1 + val length = currentAddr.index - lengthAddr.index - lengthWidth putNat(lengthAddr, length, lengthWidth) } - def writeNameRef(ref: NameRef) = writeNat(ref.index) + def writeNameRef(ref: NameRef): Unit = writeNat(ref.index) + def writeNameRef(name: Name): Unit = writeNameRef(nameRefs(name.toTermName)) - def pickleName(name: TastyName): Unit = name match { - case Simple(name) => - val bytes = - if (name.length == 0) new Array[Byte](0) - else Codec.toUTF8(chrs, name.start, name.length) - writeByte(UTF8) - writeNat(bytes.length) - writeBytes(bytes, bytes.length) - case Qualified(qualified, selector) => - writeByte(QUALIFIED) - withLength { writeNameRef(qualified); writeNameRef(selector) } - case Signed(original, params, result) => - writeByte(SIGNED) - withLength( + def pickleNameContents(name: Name): Unit = { + val tag = name.toTermName.info.kind.tag + writeByte(tag) + name.toTermName match { + case name: SimpleTermName => + val bytes = + if (name.length == 0) new Array[Byte](0) + else Codec.toUTF8(chrs, name.start, name.length) + writeNat(bytes.length) + writeBytes(bytes, bytes.length) + case AnyQualifiedName(prefix, name) => + withLength { writeNameRef(prefix); writeNameRef(name) } + case AnyUniqueName(original, separator, num) => + withLength { + writeNameRef(separator.toTermName) + 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 Expanded(prefix, original) => - writeByte(EXPANDED) - withLength { writeNameRef(prefix); writeNameRef(original) } - case ModuleClass(module) => - writeByte(OBJECTCLASS) - withLength { writeNameRef(module) } - case SuperAccessor(accessed) => - writeByte(SUPERACCESSOR) - withLength { writeNameRef(accessed) } - case DefaultGetter(method, paramNumber) => - writeByte(DEFAULTGETTER) - withLength { writeNameRef(method); writeNat(paramNumber) } - case Shadowed(original) => - writeByte(SHADOWED) - withLength { writeNameRef(original) } + case DerivedTermName(original, _) => + withLength { writeNameRef(original) } + } } override def assemble(): Unit = { @@ -89,7 +88,7 @@ class NameBuffer extends TastyBuffer(10000) { for ((name, ref) <- nameRefs) { assert(ref.index == i) i += 1 - pickleName(name) + pickleNameContents(name) } } } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyBuffer.scala index 13bc95028..40782f534 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyBuffer.scala @@ -26,6 +26,9 @@ object TastyBuffer { * the value of 4 gives a maximal array size of 256M. */ final val AddrWidth = 4 + + /** An address referring to a serialized name */ + case class NameRef(index: Int) extends AnyVal } import TastyBuffer._ diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 8b2255e94..f03e279c6 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -33,11 +33,11 @@ Macro-format: QUALIFIED Length qualified_NameRef selector_NameRef SIGNED Length original_NameRef resultSig_NameRef paramSig_NameRef* EXPANDED Length original_NameRef + UNIQUE Length separator_NameRef num_Nat original_NameRef? OBJECTCLASS Length module_NameRef SUPERACCESSOR Length accessed_NameRef DEFAULTGETTER Length method_NameRef paramNumber_Nat SHADOWED Length original_NameRef - MANGLED Length mangle_NameRef name_NameRef ... NameRef = Nat // ordinal number of name in name table, starting from 1. @@ -222,12 +222,30 @@ object TastyFormat { final val UTF8 = 1 final val QUALIFIED = 2 - final val SIGNED = 3 + final val FLATTENED = 3 final val EXPANDED = 4 - final val OBJECTCLASS = 5 - final val SUPERACCESSOR = 6 - final val DEFAULTGETTER = 7 - final val SHADOWED = 8 + final val EXPANDPREFIX = 5 + final val TRAITSETTER = 6 + final val UNIQUE = 10 + final val DEFAULTGETTER = 11 + final val VARIANT = 12 + final val OUTERSELECT = 13 + + final val SUPERACCESSOR = 20 + final val PROTECTEDACCESSOR = 21 + final val PROTECTEDSETTER = 22 + final val INITIALIZER = 23 + final val SHADOWED = 24 + final val AVOIDCLASH = 30 + final val DIRECT = 31 + final val FIELD = 32 + final val SETTER = 33 + final val EXTMETH = 34 + final val OBJECTVAR = 39 + final val OBJECTCLASS = 40 + + final val SIGNED = 63 + final val firstInternalTag = 64 // AST tags @@ -411,11 +429,14 @@ object TastyFormat { def nameTagToString(tag: Int): String = tag match { case UTF8 => "UTF8" case QUALIFIED => "QUALIFIED" - case SIGNED => "SIGNED" + case FLATTENED => "FLATTENED" case EXPANDED => "EXPANDED" + case SIGNED => "SIGNED" case OBJECTCLASS => "OBJECTCLASS" case SUPERACCESSOR => "SUPERACCESSOR" case DEFAULTGETTER => "DEFAULTGETTER" + case SHADOWED => "SHADOWED" + case VARIANT => "VARIANT" } def astTagToString(tag: Int): String = tag match { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala deleted file mode 100644 index 26807115c..000000000 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala +++ /dev/null @@ -1,30 +0,0 @@ -package dotty.tools -package dotc -package core -package tasty - -import core.Names.TermName -import collection.mutable - -abstract class TastyName - -object TastyName { - - case class NameRef(index: Int) extends AnyVal - - case class Simple(name: TermName) extends TastyName - case class Qualified(qualified: NameRef, selector: NameRef) extends TastyName - case class Signed(original: NameRef, params: List[NameRef], result: NameRef) extends TastyName - case class Expanded(prefix: NameRef, original: NameRef) extends TastyName - case class ModuleClass(module: NameRef) extends TastyName - case class SuperAccessor(accessed: NameRef) extends TastyName - case class DefaultGetter(method: NameRef, num: Int) extends TastyName - case class Shadowed(original: NameRef) extends TastyName - - class Table extends (NameRef => TastyName) { - private val names = new mutable.ArrayBuffer[TastyName] - def add(name: TastyName) = names += name - def apply(ref: NameRef) = names(ref.index) - def contents: Iterable[TastyName] = names - } -} diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala index c844d522e..cc2e4dd58 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala @@ -9,10 +9,11 @@ import TastyBuffer._ import java.util.UUID import core.Symbols.Symbol import ast.tpd +import Decorators._ class TastyPickler { - private val sections = new mutable.ArrayBuffer[(TastyName.NameRef, TastyBuffer)] + private val sections = new mutable.ArrayBuffer[(NameRef, TastyBuffer)] val uuid = UUID.randomUUID() private val headerBuffer = { @@ -28,7 +29,7 @@ class TastyPickler { val nameBuffer = new NameBuffer def newSection(name: String, buf: TastyBuffer) = - sections += ((nameBuffer.nameIndex(name), buf)) + sections += ((nameBuffer.nameIndex(name.toTermName), buf)) def assembleParts(): Array[Byte] = { def lengthWithLength(buf: TastyBuffer) = { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala index ce3722ff1..a5c870881 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala @@ -4,34 +4,24 @@ package tasty import Contexts._, Decorators._ import printing.Texts._ -import TastyName._ +import Names.Name import StdNames._ import TastyUnpickler._ -import TastyBuffer.Addr +import TastyBuffer.{Addr, NameRef} import util.Positions.{Position, offsetToInt} import collection.mutable class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) { val unpickler = new TastyUnpickler(bytes) - import unpickler.{tastyName, unpickle} + import unpickler.{nameAtRef, unpickle} - def nameToString(name: TastyName): String = name match { - case Simple(name) => name.toString - case Qualified(qual, name) => nameRefToString(qual) + "." + nameRefToString(name) - case Signed(original, params, result) => - i"${nameRefToString(original)}@${params.map(nameRefToString)}%,%:${nameRefToString(result)}" - case Expanded(prefix, original) => s"$prefix${nme.EXPAND_SEPARATOR}$original" - case ModuleClass(original) => nameRefToString(original) + "/MODULECLASS" - case SuperAccessor(accessed) => nameRefToString(accessed) + "/SUPERACCESSOR" - case DefaultGetter(meth, num) => nameRefToString(meth) + "/DEFAULTGETTER" + num - case Shadowed(original) => nameRefToString(original) + "/SHADOWED" - } + def nameToString(name: Name): String = name.debugString - def nameRefToString(ref: NameRef): String = nameToString(tastyName(ref)) + def nameRefToString(ref: NameRef): String = nameToString(nameAtRef(ref)) def printNames() = - for ((name, idx) <- tastyName.contents.zipWithIndex) { + for ((name, idx) <- nameAtRef.contents.zipWithIndex) { val index = "%4d: ".format(idx) println(index + nameToString(name)) } @@ -46,7 +36,7 @@ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) { class TreeSectionUnpickler extends SectionUnpickler[Unit]("ASTs") { import TastyFormat._ - def unpickle(reader: TastyReader, tastyName: TastyName.Table): Unit = { + def unpickle(reader: TastyReader, tastyName: NameTable): Unit = { import reader._ var indent = 0 def newLine() = { @@ -116,7 +106,7 @@ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) { } class PositionSectionUnpickler extends SectionUnpickler[Unit]("Positions") { - def unpickle(reader: TastyReader, tastyName: TastyName.Table): Unit = { + def unpickle(reader: TastyReader, tastyName: NameTable): Unit = { print(s"${reader.endAddr.index - reader.currentAddr.index}") val positions = new PositionUnpickler(reader).positions println(s" position bytes:") diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyReader.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyReader.scala index e583c4793..af5e78891 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyReader.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyReader.scala @@ -4,7 +4,6 @@ package core package tasty import TastyBuffer._ -import TastyName.NameRef import collection.mutable /** A byte array buffer that can be filled with bytes or natural numbers in TASTY format, diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala index 8a1f58acd..37a3c2e76 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala @@ -4,14 +4,23 @@ package tasty import scala.collection.mutable import TastyFormat._ -import Names.{Name, termName} +import TastyBuffer.NameRef +import Names.{Name, TermName, termName, EmptyTermName} +import NameKinds._ import java.util.UUID object TastyUnpickler { class UnpickleException(msg: String) extends Exception(msg) abstract class SectionUnpickler[R](val name: String) { - def unpickle(reader: TastyReader, tastyName: TastyName.Table): R + def unpickle(reader: TastyReader, nameAtRef: NameTable): R + } + + class NameTable extends (NameRef => TermName) { + private val names = new mutable.ArrayBuffer[TermName] + def add(name: TermName) = names += name + def apply(ref: NameRef) = names(ref.index) + def contents: Iterable[TermName] = names } } @@ -23,18 +32,15 @@ class TastyUnpickler(reader: TastyReader) { def this(bytes: Array[Byte]) = this(new TastyReader(bytes)) private val sectionReader = new mutable.HashMap[String, TastyReader] - val tastyName = new TastyName.Table + val nameAtRef = new NameTable - def check(cond: Boolean, msg: => String) = + private def check(cond: Boolean, msg: => String) = if (!cond) throw new UnpickleException(msg) - def readString(): String = { - val TastyName.Simple(name) = tastyName(readNameRef()) - name.toString - } + private def readName(): TermName = nameAtRef(readNameRef()) + private def readString(): String = readName().toString - def readName(): TastyName = { - import TastyName._ + private def readNameContents(): TermName = { val tag = readByte() val length = readNat() val start = currentAddr @@ -42,24 +48,30 @@ class TastyUnpickler(reader: TastyReader) { val result = tag match { case UTF8 => goto(end) - Simple(termName(bytes, start.index, length)) - case QUALIFIED => - Qualified(readNameRef(), readNameRef()) - case SIGNED => - val original = readNameRef() - val result = readNameRef() - val params = until(end)(readNameRef()) - Signed(original, params, result) - case EXPANDED => - Expanded(readNameRef(), readNameRef()) - case OBJECTCLASS => - ModuleClass(readNameRef()) - case SUPERACCESSOR => - SuperAccessor(readNameRef()) + termName(bytes, start.index, length) + case QUALIFIED | FLATTENED | EXPANDED | EXPANDPREFIX => + qualifiedNameKindOfTag(tag)(readName(), readName().asSimpleName) + case UNIQUE => + val separator = readName().toString + val num = readNat() + val originals = until(end)(readName()) + val original = if (originals.isEmpty) EmptyTermName else originals.head + uniqueNameKindOfSeparator(separator)(original, num) case DEFAULTGETTER => - DefaultGetter(readNameRef(), readNat()) - case SHADOWED => - Shadowed(readNameRef()) + DefaultGetterName(readName(), readNat()) + case VARIANT => + VariantName(readName(), readNat() - 1) + case OUTERSELECT => + OuterSelectName(readName(), readNat()) + case SIGNED => + val original = readName() + val result = readName().toTypeName + val params = until(end)(readName().toTypeName) + var sig = Signature(params, result) + if (sig == Signature.NotAMethod) sig = Signature.NotAMethod + SignedName(original, sig) + case _ => + simpleNameKindOfTag(tag)(readName()) } assert(currentAddr == end, s"bad name $result $start $currentAddr $end") result @@ -77,10 +89,10 @@ class TastyUnpickler(reader: TastyReader) { new UUID(readUncompressedLong(), readUncompressedLong()) } - val uuid = readHeader() + private val uuid = readHeader() locally { - until(readEnd()) { tastyName.add(readName()) } + until(readEnd()) { nameAtRef.add(readNameContents()) } while (!isAtEnd) { val secName = readString() val secEnd = readEnd() @@ -91,5 +103,5 @@ class TastyUnpickler(reader: TastyReader) { def unpickle[R](sec: SectionUnpickler[R]): Option[R] = for (reader <- sectionReader.get(sec.name)) yield - sec.unpickle(reader, tastyName) + sec.unpickle(reader, nameAtRef) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 902d01c21..5d33738c2 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -9,16 +9,18 @@ import TastyFormat._ import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annotations._, StdNames.tpnme, NameOps._ import collection.mutable import typer.Inliner -import NameOps._ +import NameOps._, NameKinds._ import StdNames.nme import TastyBuffer._ import TypeApplications._ +import transform.SymUtils._ +import config.Config class TreePickler(pickler: TastyPickler) { val buf = new TreeBuffer pickler.newSection("ASTs", buf) import buf._ - import pickler.nameBuffer.{nameIndex, fullNameIndex} + import pickler.nameBuffer.nameIndex import ast.tpd._ private val symRefs = new mutable.HashMap[Symbol, Addr] @@ -52,28 +54,8 @@ class TreePickler(pickler: TastyPickler) { } private def pickleName(name: Name): Unit = writeNat(nameIndex(name).index) - private def pickleName(name: TastyName): Unit = writeNat(nameIndex(name).index) - private def pickleNameAndSig(name: Name, sig: Signature) = { - val Signature(params, result) = sig - pickleName(TastyName.Signed(nameIndex(name), params.map(fullNameIndex), fullNameIndex(result))) - } - - private def pickleName(sym: Symbol)(implicit ctx: Context): Unit = { - def encodeSuper(name: Name): TastyName.NameRef = - if (sym is Flags.SuperAccessor) { - val SuperAccessorName(n) = name - nameIndex(TastyName.SuperAccessor(nameIndex(n))) - } - else nameIndex(name) - val nameRef = - if (sym is Flags.ExpandedName) - nameIndex( - TastyName.Expanded( - nameIndex(sym.name.expandedPrefix), - encodeSuper(sym.name.unexpandedName))) - else encodeSuper(sym.name) - writeNat(nameRef.index) - } + private def pickleNameAndSig(name: Name, sig: Signature) = + pickleName(SignedName(name.toTermName, sig)) private def pickleSymRef(sym: Symbol)(implicit ctx: Context) = symRefs.get(sym) match { case Some(label) => @@ -126,7 +108,7 @@ class TreePickler(pickler: TastyPickler) { writeLongInt(java.lang.Double.doubleToRawLongBits(c.doubleValue)) case StringTag => writeByte(STRINGconst) - writeNat(nameIndex(c.stringValue).index) + pickleName(c.stringValue.toTermName) case NullTag => writeByte(NULLconst) case ClazzTag => @@ -160,7 +142,7 @@ class TreePickler(pickler: TastyPickler) { withLength { pickleType(tycon); args.foreach(pickleType(_)) } case ConstantType(value) => pickleConstant(value) - case tpe: TypeRef if tpe.info.isAlias && tpe.symbol.is(Flags.AliasPreferred) => + case tpe: TypeRef if tpe.info.isAlias && tpe.symbol.isAliasPreferred => pickleType(tpe.superType) case tpe: WithFixedSym => val sym = tpe.symbol @@ -178,7 +160,7 @@ class TreePickler(pickler: TastyPickler) { } if (sym.is(Flags.Package)) { writeByte(if (tpe.isType) TYPEREFpkg else TERMREFpkg) - pickleName(qualifiedName(sym)) + pickleName(sym.fullName) } else if (sym is Flags.BindDefinedType) { registerDef(sym) @@ -278,7 +260,7 @@ class TreePickler(pickler: TastyPickler) { def picklePackageRef(pkg: Symbol)(implicit ctx: Context): Unit = { writeByte(TERMREFpkg) - pickleName(qualifiedName(pkg)) + pickleName(pkg.fullName) } def pickleMethodic(tag: Int, tpe: LambdaType)(implicit ctx: Context) = { @@ -312,7 +294,7 @@ class TreePickler(pickler: TastyPickler) { registerDef(sym) writeByte(tag) withLength { - pickleName(sym) + pickleName(sym.name) pickleParams tpt match { case templ: Template => pickleTree(tpt) @@ -370,7 +352,7 @@ class TreePickler(pickler: TastyPickler) { case Select(qual, name) => writeByte(if (name.isTypeName) SELECTtpt else SELECT) val realName = tree.tpe match { - case tp: NamedType if tp.name.isShadowedName => tp.name + case tp: NamedType if tp.name.is(ShadowedName) => tp.name case _ => name } val sig = tree.tpe.signature @@ -575,10 +557,6 @@ class TreePickler(pickler: TastyPickler) { pickleName(id.name) } - def qualifiedName(sym: Symbol)(implicit ctx: Context): TastyName = - if (sym.isRoot || sym.owner.isRoot) TastyName.Simple(sym.name.toTermName) - else TastyName.Qualified(nameIndex(qualifiedName(sym.owner)), nameIndex(sym.name)) - def pickleModifiers(sym: Symbol)(implicit ctx: Context): Unit = { import Flags._ val flags = sym.flags diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index a186d1ce4..2908c541e 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -5,6 +5,7 @@ package tasty import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._ import StdNames._, Denotations._, Flags._, Constants._, Annotations._ +import NameKinds._ import util.Positions._ import ast.{tpd, Trees, untpd} import Trees._ @@ -15,15 +16,15 @@ import scala.collection.mutable.ListBuffer import scala.collection.{ mutable, immutable } import config.Printers.pickling import typer.Checking +import config.Config /** Unpickler for typed trees * @param reader the reader from which to unpickle * @param tastyName the nametable * @param posUNpicklerOpt the unpickler for positions, if it exists */ -class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpicklerOpt: Option[PositionUnpickler]) { +class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpicklerOpt: Option[PositionUnpickler]) { import TastyFormat._ - import TastyName._ import TreeUnpickler._ import tpd._ @@ -74,20 +75,6 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle new TreeReader(reader).readTopLevel()(ctx.addMode(Mode.AllowDependentFunctions)) } - def toTermName(tname: TastyName): TermName = tname match { - case Simple(name) => name - case Qualified(qual, name) => toTermName(qual) ++ "." ++ toTermName(name) - case Signed(original, params, result) => toTermName(original) - case Shadowed(original) => toTermName(original).shadowedName - case Expanded(prefix, original) => toTermName(original).expandedName(toTermName(prefix)) - case ModuleClass(original) => toTermName(original).moduleClassName.toTermName - case SuperAccessor(accessed) => toTermName(accessed).superName - case DefaultGetter(meth, num) => ??? - } - - def toTermName(ref: NameRef): TermName = toTermName(tastyName(ref)) - def toTypeName(ref: NameRef): TypeName = toTermName(ref).toTypeName - class Completer(owner: Symbol, reader: TastyReader) extends LazyType { import reader._ def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { @@ -165,17 +152,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle else tag } - def readName(): TermName = toTermName(readNameRef()) - - def readNameSplitSig()(implicit ctx: Context): Any /* TermName | (TermName, Signature) */ = - tastyName(readNameRef()) match { - case Signed(original, params, result) => - var sig = Signature(params map toTypeName, toTypeName(result)) - if (sig == Signature.NotAMethod) sig = Signature.NotAMethod - (toTermName(original), sig) - case name => - toTermName(name) - } + def readName(): TermName = nameAtRef(readNameRef()) // ------ Reading types ----------------------------------------------------- @@ -305,9 +282,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle val name = readName().toTypeName TypeRef(readType(), name) case TERMREF => - readNameSplitSig() match { - case name: TermName => TermRef.all(readType(), name) - case (name: TermName, sig: Signature) => TermRef.withSig(readType(), name, sig) + readName() match { + case SignedName(name, sig) => TermRef.withSig(readType(), name, sig) + case name => TermRef.all(readType(), name) } case THIS => ThisType.raw(readType().asInstanceOf[TypeRef]) @@ -438,9 +415,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle val start = currentAddr val tag = readByte() val end = readEnd() - val rawName = tastyName(readNameRef()) - var name: Name = toTermName(rawName) + var name: Name = readName() if (tag == TYPEDEF || tag == TYPEPARAM) name = name.toTypeName + val mname = name.mangled skipParams() val ttag = nextUnsharedTag val isAbsType = isAbstractType(ttag) @@ -451,19 +428,15 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle val rhsIsEmpty = noRhs(end) if (!rhsIsEmpty) skipTree() val (givenFlags, annots, privateWithin) = readModifiers(end) - def nameFlags(tname: TastyName): FlagSet = tname match { - case TastyName.Expanded(_, original) => ExpandedName | nameFlags(tastyName(original)) - case TastyName.SuperAccessor(_) => Flags.SuperAccessor - case _ => EmptyFlags - } pickling.println(i"creating symbol $name at $start with flags $givenFlags") - val flags = normalizeFlags(tag, givenFlags | nameFlags(rawName), name, isAbsType, rhsIsEmpty) + val flags = normalizeFlags(tag, givenFlags, name, isAbsType, rhsIsEmpty) def adjustIfModule(completer: LazyType) = if (flags is Module) ctx.adjustModuleCompleter(completer, name) else completer val sym = - roots.find(root => (root.owner eq ctx.owner) && root.name == name) match { + roots.find(root => (root.owner eq ctx.owner) && root.name.mangled == mname) 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 @@ -886,7 +859,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle val localCtx = if (name == nme.CONSTRUCTOR) ctx.addMode(Mode.InSuperCall) else ctx val qual = readTerm()(localCtx) - val unshadowed = if (name.isShadowedName) name.revertShadowed else name + val unshadowed = name.exclude(ShadowedName) untpd.Select(qual, unshadowed).withType(tpf(qual.tpe.widenIfUnstable)) } @@ -905,9 +878,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle case SELECT => def readRest(name: Name, sig: Signature) = completeSelect(name, TermRef.withSig(_, name.asTermName, sig)) - readNameSplitSig match { - case name: Name => readRest(name, Signature.NotAMethod) - case (name: Name, sig: Signature) => readRest(name, sig) + readName() match { + case SignedName(name, sig) => readRest(name, sig) + case name => readRest(name, Signature.NotAMethod) } case SELECTtpt => val name = readName().toTypeName diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala index 6ee9f1f9e..2a789dca9 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala @@ -224,12 +224,12 @@ object PickleBuffer { DEFAULTPARAM -> (DefaultParameterized, Trait), BRIDGE -> Bridge, ACCESSOR -> Accessor, - SUPERACCESSOR -> SuperAccessor, + SUPERACCESSOR -> Scala2SuperAccessor, PARAMACCESSOR -> ParamAccessor, MODULEVAR -> Scala2ModuleVar, LAZY -> Lazy, MIXEDIN -> (MixedIn, Scala2Existential), - EXPANDEDNAME -> ExpandedName, + EXPANDEDNAME -> Scala2ExpandedName, IMPLCLASS -> (Scala2PreSuper, ImplClass), SPECIALIZED -> Specialized, VBRIDGE -> VBridge, diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index cf99bb022..1db3ebcb0 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -9,6 +9,7 @@ import java.lang.Double.longBitsToDouble import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._ import StdNames._, Denotations._, NameOps._, Flags._, Constants._, Annotations._ +import NameKinds.{Scala2MethodNameKinds, SuperAccessorName, ExpandedName} import dotty.tools.dotc.typer.ProtoTypes.{FunProtoTyped, FunProto} import util.Positions._ import dotty.tools.dotc.ast.{tpd, Trees, untpd}, ast.tpd._ @@ -18,6 +19,7 @@ import printing.Printer import io.AbstractFile import util.common._ import typer.Checking.checkNonCyclic +import transform.SymUtils._ import PickleBuffer._ import PickleFormat._ import Decorators._ @@ -361,7 +363,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas } def slowSearch(name: Name): Symbol = - owner.info.decls.find(_.name == name).getOrElse(NoSymbol) + owner.info.decls.find(_.name == name) def nestedObjectSymbol: Symbol = { // If the owner is overloaded (i.e. a method), it's not possible to select the @@ -420,10 +422,10 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas // symbols that were pickled with Pickler.writeSymInfo val nameref = readNat() - val name0 = at(nameref, readName) + var name = at(nameref, readName) val owner = readSymbolRef() - var flags = unpickleScalaFlags(readLongNat(), name0.isTypeName) + var flags = unpickleScalaFlags(readLongNat(), name.isTypeName) if (flags is DefaultParameter) { // DefaultParameterized flag now on method, not parameter //assert(flags is Param, s"$name0 in $owner") @@ -431,18 +433,33 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas owner.setFlag(DefaultParameterized) } - val name1 = name0.adjustIfModuleClass(flags) - val name = if (name1 == nme.TRAIT_CONSTRUCTOR) nme.CONSTRUCTOR else name1 + name = name.adjustIfModuleClass(flags) + if (flags is Method) { + name = + if (name == nme.TRAIT_CONSTRUCTOR) nme.CONSTRUCTOR + else name.asTermName.unmangle(Scala2MethodNameKinds) + } + if ((flags is Scala2ExpandedName) && name.isSimple) { + name = name.unmangle(ExpandedName) + flags = flags &~ Scala2ExpandedName + } + if (flags is Scala2SuperAccessor) { + name = name.asTermName.unmangle(SuperAccessorName) + flags = flags &~ Scala2SuperAccessor + } - def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass) - def isModuleClassRoot = (name == moduleClassRoot.name) && (owner == moduleClassRoot.owner) && (flags is Module) - def isModuleRoot = (name == moduleClassRoot.name.sourceModuleName) && (owner == moduleClassRoot.owner) && (flags is Module) + val mname = name.mangled + def nameMatches(rootName: Name) = mname == rootName.mangled + def isClassRoot = nameMatches(classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass) + def isModuleClassRoot = nameMatches(moduleClassRoot.name) && (owner == moduleClassRoot.owner) && (flags is Module) + def isModuleRoot = nameMatches(moduleClassRoot.name.sourceModuleName) && (owner == moduleClassRoot.owner) && (flags is Module) //if (isClassRoot) println(s"classRoot of $classRoot found at $readIndex, flags = $flags") // !!! DEBUG //if (isModuleRoot) println(s"moduleRoot of $moduleRoot found at $readIndex, flags = $flags") // !!! DEBUG //if (isModuleClassRoot) println(s"moduleClassRoot of $moduleClassRoot found at $readIndex, flags = $flags") // !!! DEBUG def completeRoot(denot: ClassDenotation, completer: LazyType): Symbol = { + denot.name = name denot.setFlag(flags) denot.resetFlag(Touched) // allow one more completion denot.info = completer @@ -470,7 +487,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas var flags1 = flags if (flags is TypeParam) { name1 = name1.expandedName(owner) - flags1 |= owner.typeParamCreationFlags | ExpandedName + flags1 |= owner.typeParamCreationFlags } ctx.newSymbol(owner, name1, flags1, localMemberUnpickler, coord = start) case CLASSsym => @@ -546,9 +563,9 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas else tp1 if (denot.isConstructor) addConstructorTypeParams(denot) if (atEnd) { - assert(!(denot is SuperAccessor), denot) + assert(!denot.isSuperAccessor, denot) } else { - assert(denot is (SuperAccessor | ParamAccessor), denot) + assert(denot.is(ParamAccessor) || denot.isSuperAccessor, denot) def disambiguate(alt: Symbol) = { // !!! DEBUG ctx.debugTraceIndented(s"disambiguating ${denot.info} =:= ${denot.owner.thisType.memberInfo(alt)} ${denot.owner}") { denot.info matches denot.owner.thisType.memberInfo(alt) @@ -1022,7 +1039,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas val rhs = readTreeRef() val params = until(end, readIdentRef) val ldef = DefDef(symbol.asTerm, rhs) - def isCaseLabel(sym: Symbol) = sym.name.startsWith(nme.CASEkw) + def isCaseLabel(sym: Symbol) = sym.name.startsWith(nme.CASEkw.toString) if (isCaseLabel(symbol)) ldef else Block(ldef :: Nil, Apply(Ident(symbol.termRef), Nil)) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 3e3673e5e..3112be659 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -12,6 +12,7 @@ import core._ import Flags._ import Contexts._ import Names._ +import NameKinds.WildcardParamName import ast.{Positioned, Trees, untpd} import ast.Trees._ import Decorators._ @@ -20,7 +21,6 @@ import util.Positions._ import Constants._ import ScriptParsers._ import Comments._ - import scala.annotation.{tailrec, switch} import util.DotClass import rewrite.Rewrites.patch @@ -1168,7 +1168,7 @@ object Parsers { def bindingName(): TermName = if (in.token == USCORE) { in.nextToken() - ctx.freshName(nme.USCORE_PARAM_PREFIX).toTermName + WildcardParamName.fresh() } else ident() @@ -1224,7 +1224,7 @@ object Parsers { path(thisOK = true) case USCORE => val start = in.skipToken() - val pname = ctx.freshName(nme.USCORE_PARAM_PREFIX).toTermName + val pname = WildcardParamName.fresh() val param = ValDef(pname, TypeTree(), EmptyTree).withFlags(SyntheticTermParam) .withPos(Position(start)) placeholderParams = param :: placeholderParams @@ -1705,7 +1705,7 @@ object Parsers { if (isConcreteOwner || in.token != USCORE) ident().toTypeName else { in.nextToken() - ctx.freshName(nme.USCORE_PARAM_PREFIX).toTypeName + WildcardParamName.fresh().toTypeName } val hkparams = typeParamClauseOpt(ParamOwner.TypeParam) val bounds = diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index ff5019dc9..b0fa8d760 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -37,7 +37,7 @@ object Scanners { var lastOffset: Offset = 0 /** the name of an identifier */ - var name: TermName = null + var name: SimpleTermName = null /** the string value of a literal */ var strVal: String = null @@ -98,7 +98,7 @@ object Scanners { /** Clear buffer and set name and token */ def finishNamed(idtoken: Token = IDENTIFIER, target: TokenData = this): Unit = { - target.name = flushBuf(litBuf).toTermName + target.name = termName(flushBuf(litBuf)) target.token = idtoken if (idtoken == IDENTIFIER) { val idx = target.name.start diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala index d2ea9240c..770b826fd 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala @@ -129,7 +129,7 @@ abstract class TokensCommon { final val lastParen = RBRACE def buildKeywordArray(keywords: TokenSet) = { - def start(tok: Token) = tokenString(tok).toTermName.start + def start(tok: Token) = tokenString(tok).toTermName.asSimpleName.start def sourceKeywords = keywords.toList.filter { (kw: Token) => val ts = tokenString(kw) (ts != null) && !ts.contains(' ') diff --git a/compiler/src/dotty/tools/dotc/parsing/package.scala b/compiler/src/dotty/tools/dotc/parsing/package.scala index 8b113ed96..cdb30d0be 100644 --- a/compiler/src/dotty/tools/dotc/parsing/package.scala +++ b/compiler/src/dotty/tools/dotc/parsing/package.scala @@ -10,7 +10,7 @@ package object parsing { def precedence(operator: Name): Int = if (operator eq nme.ERROR) -1 else { - val firstCh = operator(0) + val firstCh = operator.firstPart.head if (isScalaLetter(firstCh)) 1 else if (operator.isOpAssignmentName) 0 else firstCh match { diff --git a/compiler/src/dotty/tools/dotc/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala index aa25880c2..b35a07027 100644 --- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala +++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala @@ -139,7 +139,7 @@ object Formatting { seen.record(super.ParamRefNameString(param), param) override def toTextRef(tp: SingletonType): Text = tp match { - case tp: SkolemType => seen.record(tp.repr, tp) + case tp: SkolemType => seen.record(tp.repr.toString, tp) case _ => super.toTextRef(tp) } } diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index c762bbeaf..375edc3cb 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -97,11 +97,7 @@ class PlainPrinter(_ctx: Context) extends Printer { || (sym.name == nme.PACKAGE) // package ) - def nameString(name: Name): String = name.toString + { - if (ctx.settings.debugNames.value) - if (name.isTypeName) "/T" else "/V" - else "" - } + def nameString(name: Name): String = name.toString def toText(name: Name): Text = Str(nameString(name)) @@ -135,8 +131,7 @@ class PlainPrinter(_ctx: Context) extends Printer { toTextRHS(tp) case tp: TermRef if !tp.denotationIsCurrent && !homogenizedView || // always print underlying when testing picklers - tp.symbol.is(Module) || - tp.symbol.name.isImportName => + tp.symbol.is(Module) || tp.symbol.name == nme.IMPORT => toTextRef(tp) ~ ".type" case tp: TermRef if tp.denot.isOverloaded => "<overloaded " ~ toTextRef(tp) ~ ">" @@ -268,7 +263,7 @@ class PlainPrinter(_ctx: Context) extends Printer { if (idx >= 0) selfRecName(idx + 1) else "{...}.this" // TODO move underlying type to an addendum, e.g. ... z3 ... where z3: ... case tp: SkolemType => - if (homogenizedView) toText(tp.info) else tp.repr + if (homogenizedView) toText(tp.info) else toText(tp.repr) } } diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 0b683d90c..c3f36cc46 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -13,6 +13,7 @@ import Trees._ import TypeApplications._ import Decorators._ import config.Config +import transform.SymUtils._ import scala.annotation.switch import language.implicitConversions @@ -58,11 +59,12 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { protected val PrintableFlags = (SourceModifierFlags | Label | Module | Local).toCommonFlags - override def nameString(name: Name): String = name.decode.toString + override def nameString(name: Name): String = + if (ctx.settings.debugNames.value) name.debugString else name.decode.toString override protected def simpleNameString(sym: Symbol): String = { val name = if (ctx.property(XprintMode).isEmpty) sym.originalName else sym.name - nameString(if (sym is ExpandedTypeParam) name.asTypeName.unexpandedName else name) + nameString(if (sym.is(TypeParam)) name.asTypeName.unexpandedName else name) } override def fullNameString(sym: Symbol): String = @@ -130,7 +132,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (defn.isTupleClass(cls)) return toTextTuple(args) return (toTextLocal(tycon) ~ "[" ~ Text(args map argText, ", ") ~ "]").close case tp: TypeRef => - val hideType = !ctx.settings.debugAlias.value && (tp.symbol is AliasPreferred) + val hideType = !ctx.settings.debugAlias.value && (tp.symbol.isAliasPreferred) if (hideType && !ctx.phase.erasedTypes && !tp.symbol.isCompleting) { tp.info match { case TypeAlias(alias) => return toText(alias) @@ -154,8 +156,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { // one version of the annotation tree that has the correct positions). withoutPos(super.toText(tp)) case tp: SelectionProto => - return "?{ " ~ toText(tp.name) ~ (" " provided !tp.name.decode.last.isLetterOrDigit) ~ - ": " ~ toText(tp.memberProto) ~ " }" + return "?{ " ~ toText(tp.name) ~ + (" " provided !tp.name.toSimpleName.decode.last.isLetterOrDigit) ~ + ": " ~ toText(tp.memberProto) ~ " }" case tp: ViewProto => return toText(tp.argType) ~ " ?=>? " ~ toText(tp.resultType) case tp @ FunProto(args, resultType, _) => diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 87837fd82..20cd08426 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -237,7 +237,7 @@ object messages { val msg = { import core.Flags._ val maxDist = 3 - val decls = site.decls.flatMap { sym => + val decls = site.decls.toList.flatMap { sym => if (sym.flagsUNSAFE.is(Synthetic | PrivateOrLocal) || sym.isConstructor) Nil else List((sym.name.show, sym)) } diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index 8d704f9a2..5488d1979 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -5,8 +5,10 @@ import ast.{Trees, tpd} import core._, core.Decorators._ import Annotations._, Contexts._, Flags._, Phases._, Trees._, Types._, Symbols._ import Names._, NameOps._, StdNames._ +import NameKinds.DefaultGetterName import typer.Inliner import typer.ErrorReporting.cyclicErrorMsg +import transform.SymUtils._ import dotty.tools.io.Path import java.io.PrintWriter @@ -212,7 +214,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder // and can therefore be ignored. def alwaysPresent(s: Symbol) = s.isCompanionMethod || (csym.is(ModuleClass) && s.isConstructor) - val decls = cinfo.decls.filterNot(alwaysPresent).toList + val decls = cinfo.decls.filter(!alwaysPresent(_)).toList val apiDecls = apiDefinitions(decls) val declSet = decls.toSet @@ -222,7 +224,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder // We cannot filter out `LegacyApp` because it contains the main method, // see the comment about main class discovery in `computeType`. .filter(bc => !bc.is(Scala2x) || bc.eq(LegacyAppClass)) - .flatMap(_.classInfo.decls.filterNot(s => s.is(Private) || declSet.contains(s))) + .flatMap(_.classInfo.decls.filter(s => !(s.is(Private) || declSet.contains(s)))) // Inherited members need to be computed lazily because a class might contain // itself as an inherited member, like in `class A { class B extends A }`, // this works because of `classLikeCache` @@ -299,7 +301,8 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder sym.owner.companionModule // default getters for class constructors are found in the companion object else sym.owner - (0 until pnames.length).map(i => qual.info.member(sym.name.defaultGetterName(start + i)).exists) + (0 until pnames.length).map(i => + qual.info.member(DefaultGetterName(sym.name, start + i)).exists) } else (0 until pnames.length).map(Function.const(false)) val params = (pnames, ptypes, defaults).zipped.map((pname, ptype, isDefault) => @@ -539,7 +542,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder val abs = sym.is(Abstract) || sym.is(Deferred) || absOver val over = sym.is(Override) || absOver new api.Modifiers(abs, over, sym.is(Final), sym.is(Sealed), - sym.is(Implicit), sym.is(Lazy), sym.is(Macro), sym.is(SuperAccessor)) + sym.is(Implicit), sym.is(Lazy), sym.is(Macro), sym.isSuperAccessor) } def apiAnnotations(s: Symbol): List[api.Annotation] = { diff --git a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala index 9c01aaa9a..f2ffaff5d 100644 --- a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala +++ b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala @@ -14,6 +14,7 @@ import DenotTransformers._ import Annotations._ import StdNames._ import NameOps._ +import NameKinds.{ExpandedName, TraitSetterName} import ast.Trees._ /** This phase augments Scala2 traits with implementation classes and with additional members @@ -66,16 +67,16 @@ class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransform meth.copy( owner = implClass, name = mold.name.asTermName, - flags = Method | JavaStatic | mold.flags & ExpandedName, + flags = Method | JavaStatic, info = fullyParameterizedType(mold.info, mixin)) } def traitSetter(getter: TermSymbol) = getter.copy( name = getter.ensureNotPrivate.name - .expandedName(getter.owner, nme.TRAIT_SETTER_SEPARATOR) + .expandedName(getter.owner, TraitSetterName) .asTermName.setterName, - flags = Method | Accessor | ExpandedName, + flags = Method | Accessor, info = MethodType(getter.info.resultType :: Nil, defn.UnitType)) for (sym <- mixin.info.decls) { @@ -89,9 +90,9 @@ class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransform else if (!sym.is(Deferred) && !sym.setter.exists && !sym.info.resultType.isInstanceOf[ConstantType]) traitSetter(sym.asTerm).enteredAfter(thisTransform) - if ((sym.is(PrivateAccessor, butNot = ExpandedName) && + if ((sym.is(PrivateAccessor) && !sym.name.is(ExpandedName) && (sym.isGetter || sym.isSetter)) // strangely, Scala 2 fields are also methods that have Accessor set. - || sym.is(SuperAccessor)) // scala2 superaccessors are pickled as private, but are compiled as public expanded + || sym.isSuperAccessor) // scala2 superaccessors are pickled as private, but are compiled as public expanded sym.ensureNotPrivate.installAfter(thisTransform) } ctx.log(i"Scala2x trait decls of $mixin = ${mixin.info.decls.toList.map(_.showDcl)}%\n %") diff --git a/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala b/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala index cd05589c3..b9a9544f5 100644 --- a/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala +++ b/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala @@ -12,6 +12,7 @@ import core.SymDenotations._ import core.StdNames.nme import core.Names._ import core.NameOps._ +import core.NameKinds.TempResultName import ast.Trees._ import SymUtils._ import collection.{ mutable, immutable } @@ -138,7 +139,7 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer { thisTransfo val Select(_, nme.elem) = qual recur(qual) case Select(_, nme.elem) if refInfo.boxedRefClasses.contains(lhs.symbol.maybeOwner) => - val tempDef = transformFollowing(SyntheticValDef(ctx.freshName("ev$").toTermName, tree.rhs)) + val tempDef = transformFollowing(SyntheticValDef(TempResultName.fresh(), tree.rhs)) transformFollowing(Block(tempDef :: Nil, cpy.Assign(tree)(lhs, ref(tempDef.symbol)))) case _ => tree diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index d64120085..4cee0d0de 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -11,6 +11,7 @@ import core.Types._ import core.Names._ import core.StdNames._ import core.NameOps._ +import core.NameKinds.ShadowedName import core.Decorators._ import core.Constants._ import core.Definitions._ @@ -363,7 +364,7 @@ object Erasure extends TypeTestsCasts{ def select(qual: Tree, sym: Symbol): Tree = { val name = tree.typeOpt match { - case tp: NamedType if tp.name.isShadowedName => sym.name.shadowedName + case tp: NamedType if tp.name.is(ShadowedName) => sym.name.derived(ShadowedName) case _ => sym.name } untpd.cpy.Select(tree)(qual, sym.name) diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 7b15b7e54..f63cba3f1 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -38,7 +38,7 @@ class ExpandSAMs extends MiniPhaseTransform { thisTransformer => case tpe @ SAMType(_) if isPlatformSam(tpe.classSymbol.asClass) => tree case tpe => - val Seq(samDenot) = tpe.abstractTermMembers.filter(!_.symbol.is(SuperAccessor)) + val Seq(samDenot) = tpe.abstractTermMembers.filter(!_.symbol.isSuperAccessor) cpy.Block(tree)(stats, AnonClass(tpe :: Nil, fn.symbol.asTerm :: Nil, samDenot.symbol.asTerm.name :: Nil)) } diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index a6e643992..7ad7fb348 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -11,6 +11,7 @@ import core.Decorators._ import core.StdNames.nme import core.Names._ import core.NameOps._ +import core.NameKinds.OuterSelectName import ast.Trees._ import SymUtils._ import dotty.tools.dotc.ast.tpd @@ -61,10 +62,11 @@ class ExplicitOuter extends MiniPhaseTransform with InfoTransformer { thisTransf /** Convert a selection of the form `qual.C_<OUTER>` to an outer path from `qual` to `C` */ override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) = - if (tree.name.isOuterSelect) - outer.path(start = tree.qualifier, count = tree.name.outerSelectHops) - .ensureConforms(tree.tpe) - else tree + tree.name match { + case OuterSelectName(_, nhops) => + outer.path(start = tree.qualifier, count = nhops).ensureConforms(tree.tpe) + case _ => tree + } /** First, add outer accessors if a class does not have them yet and it references an outer this. * If the class has outer accessors, implement them. @@ -215,7 +217,7 @@ object ExplicitOuter { def outerAccessor(cls: ClassSymbol)(implicit ctx: Context): Symbol = if (cls.isStatic) NoSymbol // fast return to avoid scanning package decls else cls.info.member(outerAccName(cls)).suchThat(_ is OuterAccessor).symbol orElse - cls.info.decls.find(_ is OuterAccessor).getOrElse(NoSymbol) + cls.info.decls.find(_ is OuterAccessor) /** Class has an outer accessor. Can be called only after phase ExplicitOuter. */ private def hasOuter(cls: ClassSymbol)(implicit ctx: Context): Boolean = diff --git a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala index 64474cecd..61f32edae 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala @@ -16,6 +16,7 @@ import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTrans import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._ import TypeErasure.{ valueErasure, ErasedValueType } import TypeUtils._ +import NameKinds.{ExtMethName, UniqueExtMethName} import util.Positions._ import Decorators._ import SymUtils._ @@ -206,11 +207,11 @@ object ExtensionMethods { val alts = decl.alternatives val index = alts indexOf imeth.denot assert(index >= 0, alts + " does not contain " + imeth) - def altName(index: Int) = (imeth.name + "$extension" + index).toTermName + def altName(index: Int) = UniqueExtMethName(imeth.name.asTermName, index) altName(index) #:: ((0 until alts.length).toStream filter (index != _) map altName) case decl => assert(decl.exists, imeth.name + " not found in " + imeth.owner + "'s decls: " + imeth.owner.info.decls) - Stream((imeth.name + "$extension").toTermName) + Stream(ExtMethName(imeth.name.asTermName)) } } diff --git a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala index 8328e43de..a3cf71ef2 100644 --- a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -19,8 +19,8 @@ import dotty.tools.dotc.core.Denotations.SingleDenotation import scala.collection.mutable import DenotTransformers._ import typer.Checking -import Names.Name import NameOps._ +import NameKinds.{AvoidClashName, OuterSelectName} import StdNames._ @@ -77,7 +77,7 @@ class FirstTransform extends MiniPhaseTransform with InfoTransformer with Annota override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = { tree match { - case Select(qual, name) if !name.isOuterSelect && tree.symbol.exists => + case Select(qual, name) if !name.is(OuterSelectName) && tree.symbol.exists => assert(qual.tpe derivesFrom tree.symbol.owner, i"non member selection of ${tree.symbol.showLocated} from ${qual.tpe} in $tree") case _: TypeTree => case _: Import | _: NamedArg | _: TypTree => @@ -129,7 +129,7 @@ class FirstTransform extends MiniPhaseTransform with InfoTransformer with Annota case _ => false } - val uniqueName = if (nameClash) objName.avoidClashName else objName + val uniqueName = if (nameClash) AvoidClashName(objName) else objName Thicket(stat :: ModuleDef(registerCompanion(uniqueName, stat.symbol), Nil).trees) case stat => stat } diff --git a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala index 2035fb04b..f64006d73 100644 --- a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala @@ -10,6 +10,7 @@ import Contexts._ import Symbols._ import Decorators._ import NameOps._ +import NameKinds._ import StdNames.nme import rewrite.Rewrites.patch import util.Positions.Position @@ -106,7 +107,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { */ def transformSyntheticModule(tree: ValOrDefDef)(implicit ctx: Context) = { val sym = tree.symbol - val holderSymbol = ctx.newSymbol(sym.owner, sym.asTerm.name.lazyLocalName, + val holderSymbol = ctx.newSymbol(sym.owner, LazyLocalName.fresh(sym.asTerm.name), Flags.Synthetic, sym.info.widen.resultType).enteredAfter(this) val field = ValDef(holderSymbol, tree.rhs.changeOwnerAfter(sym, holderSymbol, this)) val getter = DefDef(sym.asTerm, ref(holderSymbol)) @@ -119,8 +120,9 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { */ def transformLocalDef(x: ValOrDefDef)(implicit ctx: Context) = { val valueInitter = x.rhs - val holderName = ctx.freshName(x.name.asTermName.lazyLocalName).toTermName - val initName = ctx.freshName(x.name ++ StdNames.nme.LAZY_LOCAL_INIT).toTermName + val xname = x.name.asTermName + val holderName = LazyLocalName.fresh(xname) + val initName = LazyLocalInitName.fresh(xname) val tpe = x.tpe.widen.resultType.widen val holderType = @@ -211,7 +213,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { val claz = x.symbol.owner.asClass val tpe = x.tpe.widen.resultType.widen assert(!(x.symbol is Flags.Mutable)) - val containerName = ctx.freshName(x.name.asTermName.lazyLocalName).toTermName + val containerName = LazyLocalName.fresh(x.name.asTermName) val containerSymbol = ctx.newSymbol(claz, containerName, x.symbol.flags &~ containerFlagsMask | containerFlags | Flags.Private, tpe, coord = x.symbol.coord @@ -223,7 +225,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { Thicket(containerTree, slowPath) } else { - val flagName = ctx.freshName(x.name ++ StdNames.nme.BITMAP_PREFIX).toTermName + val flagName = LazyBitMapName.fresh(x.name.asTermName) val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags | Flags.Private, defn.BooleanType).enteredAfter(this) val flag = ValDef(flagSymbol, Literal(Constants.Constant(false))) val slowPath = DefDef(x.symbol.asTerm, mkNonThreadSafeDef(ref(containerSymbol), ref(flagSymbol), x.rhs)) @@ -376,7 +378,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { appendOffsetDefs += (claz -> new OffsetInfo(List(offsetTree), ord)) } - val containerName = ctx.freshName(x.name.asTermName.lazyLocalName).toTermName + val containerName = LazyLocalName.fresh(x.name.asTermName) val containerSymbol = ctx.newSymbol(claz, containerName, x.symbol.flags &~ containerFlagsMask | containerFlags, tpe, coord = x.symbol.coord).enteredAfter(this) val containerTree = ValDef(containerSymbol, defaultValue(tpe)) diff --git a/compiler/src/dotty/tools/dotc/transform/LiftTry.scala b/compiler/src/dotty/tools/dotc/transform/LiftTry.scala index d01195614..278868131 100644 --- a/compiler/src/dotty/tools/dotc/transform/LiftTry.scala +++ b/compiler/src/dotty/tools/dotc/transform/LiftTry.scala @@ -8,6 +8,7 @@ import core.Contexts._ import core.Types._ import core.Flags._ import core.Decorators._ +import core.NameKinds.LiftedTreeName import NonLocalReturns._ /** Lifts try's that might be executed on non-empty expression stacks @@ -56,7 +57,7 @@ class LiftTry extends MiniPhase with IdentityDenotTransformer { thisTransform => if (needLift) { ctx.debuglog(i"lifting tree at ${tree.pos}, current owner = ${ctx.owner}") val fn = ctx.newSymbol( - ctx.owner, ctx.freshName("liftedTree").toTermName, Synthetic | Method, + ctx.owner, LiftedTreeName.fresh(), Synthetic | Method, MethodType(Nil, tree.tpe.widenIfUnstable), coord = tree.pos) tree.changeOwnerAfter(ctx.owner, fn, thisTransform) Block(DefDef(fn, tree) :: Nil, ref(fn).appliedToNone) diff --git a/compiler/src/dotty/tools/dotc/transform/Mixin.scala b/compiler/src/dotty/tools/dotc/transform/Mixin.scala index fd4370d3e..546077d27 100644 --- a/compiler/src/dotty/tools/dotc/transform/Mixin.scala +++ b/compiler/src/dotty/tools/dotc/transform/Mixin.scala @@ -13,6 +13,7 @@ import Decorators._ import DenotTransformers._ import StdNames._ import NameOps._ +import NameKinds._ import Phases._ import ast.untpd import ast.Trees._ @@ -219,7 +220,7 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform => ref(mixin.implClass).select(implClassGetter).appliedTo(This(cls)) } - if (isCurrent(getter) || getter.is(ExpandedName)) { + if (isCurrent(getter) || getter.name.is(ExpandedName)) { val rhs = if (was(getter, ParamAccessor)) nextArgument() else if (isScala2x) diff --git a/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala b/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala index b0ee0930d..652320639 100644 --- a/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala +++ b/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala @@ -55,6 +55,7 @@ class MoveStatics extends MiniPhaseTransform with SymTransformer { thisTransform } def move(module: TypeDef, companion: TypeDef): List[Tree] = { + assert(companion ne module) if (!module.symbol.is(Flags.Module)) move(companion, module) else { val allMembers = diff --git a/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala b/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala index 7680e283e..fdee076b4 100644 --- a/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala +++ b/compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala @@ -5,6 +5,7 @@ import core._ import Contexts._, Symbols._, Types._, Flags._, Decorators._, StdNames._, Constants._, Phases._ import TreeTransforms._ import ast.Trees._ +import NameKinds.NonLocalReturnKeyName import collection.mutable object NonLocalReturns { @@ -38,7 +39,7 @@ class NonLocalReturns extends MiniPhaseTransform { thisTransformer => private def nonLocalReturnKey(meth: Symbol)(implicit ctx: Context) = nonLocalReturnKeys.getOrElseUpdate(meth, ctx.newSymbol( - meth, ctx.freshName("nonLocalReturnKey").toTermName, Synthetic, defn.ObjectType, coord = meth.pos)) + meth, NonLocalReturnKeyName.fresh(), Synthetic, defn.ObjectType, coord = meth.pos)) /** Generate a non-local return throw with given return expression from given method. * I.e. for the method's non-local return key, generate: diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index dbc7666f7..d87412d93 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -11,6 +11,7 @@ import core.Symbols._ import core.Types._ import core.Constants._ import core.StdNames._ +import core.NameKinds._ import dotty.tools.dotc.ast.{untpd, TreeTypeMap, tpd} import dotty.tools.dotc.core import dotty.tools.dotc.core.DenotTransformers.DenotTransformer @@ -70,16 +71,14 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { class OptimizingMatchTranslator extends MatchOptimizer/*(val typer: analyzer.Typer)*/ with MatchTranslator trait CodegenCore { - private var ctr = 0 // left for debugging // assert(owner ne null); assert(owner ne NoSymbol) - def freshSym(pos: Position, tp: Type = NoType, prefix: String = "x", owner: Symbol = ctx.owner) = { - ctr += 1 - ctx.newSymbol(owner, ctx.freshName(prefix + ctr).toTermName, Flags.Synthetic | Flags.Case, tp, coord = pos) + def freshSym(pos: Position, tp: Type = NoType, unique: UniqueNameKind = PatMatStdBinderName, owner: Symbol = ctx.owner) = { + ctx.newSymbol(owner, unique.fresh(), Flags.Synthetic | Flags.Case, tp, coord = pos) } - def newSynthCaseLabel(name: String, tpe: Type, owner: Symbol = ctx.owner) = - ctx.newSymbol(owner, ctx.freshName(name).toTermName, Flags.Label | Flags.Synthetic | Flags.Method, tpe).asTerm + def newSynthCaseLabel(unique: UniqueNameKind, tpe: Type, owner: Symbol = ctx.owner) = + ctx.newSymbol(owner, unique.fresh(), Flags.Label | Flags.Synthetic | Flags.Method, tpe).asTerm //NoSymbol.newLabel(freshName(name), NoPosition) setFlag treeInfo.SYNTH_CASE_FLAGS // codegen relevant to the structure of the translation (how extractors are combined) @@ -189,7 +188,8 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { //NoSymbol.newValueParameter(newTermName("x"), NoPosition, newFlags = SYNTHETIC) setInfo restpe.withoutAnnotations - val caseSyms: List[TermSymbol] = cases.scanLeft(ctx.owner.asTerm)((curOwner, nextTree) => newSynthCaseLabel(ctx.freshName("case"), MethodType(Nil, restpe), curOwner)).tail + val caseSyms: List[TermSymbol] = cases.scanLeft(ctx.owner.asTerm)((curOwner, nextTree) => + newSynthCaseLabel(PatMatCaseName, MethodType(Nil, restpe), curOwner)).tail // must compute catchAll after caseLabels (side-effects nextCase) // catchAll.isEmpty iff no synthetic default case needed (the (last) user-defined case is a default) @@ -197,7 +197,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { val catchAllDef = matchFailGen.map { _(scrutSym) } .getOrElse(Throw(New(defn.MatchErrorType, List(ref(scrutSym))))) - val matchFail = newSynthCaseLabel(ctx.freshName("matchFail"), MethodType(Nil, restpe)) + val matchFail = newSynthCaseLabel(PatMatMatchFailName, MethodType(Nil, restpe)) val catchAllDefBody = DefDef(matchFail, catchAllDef) val nextCases = (caseSyms.tail ::: List(matchFail)).map(ref(_).ensureApplied) @@ -249,7 +249,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { val isEmptyDenot = extractorMember(prev.tpe, nme.isEmpty) assert(getDenot.exists && isEmptyDenot.exists, i"${prev.tpe}") - val tmpSym = freshSym(prev.pos, prev.tpe, "o") + val tmpSym = freshSym(prev.pos, prev.tpe, PatMatOName) val prevValue = ref(tmpSym).select(getDenot.symbol).ensureApplied Block( @@ -1056,9 +1056,9 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { } def newBoundTree(tree: Tree, pt: Type): BoundTree = tree match { - case SymbolBound(sym, Typed(subpat, tpe)) => BoundTree(freshSym(tree.pos, pt, prefix = "pi"), tree) + case SymbolBound(sym, Typed(subpat, tpe)) => BoundTree(freshSym(tree.pos, pt, PatMatPiName), tree) case SymbolBound(sym, expr) => BoundTree(sym, expr) - case _ => BoundTree(freshSym(tree.pos, pt, prefix = "p"), tree) + case _ => BoundTree(freshSym(tree.pos, pt, PatMatPName), tree) } final case class BoundTree(binder: Symbol, tree: Tree) { @@ -1204,7 +1204,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { val selectorTp = sel.tpe.widen.deAnonymize/*withoutAnnotations*/ - val selectorSym = freshSym(sel.pos, selectorTp, "selector") + val selectorSym = freshSym(sel.pos, selectorTp, PatMatSelectorName) val (nonSyntheticCases, defaultOverride) = cases match { case init :+ last if isSyntheticDefaultCase(last) => (init, Some(((scrut: Symbol) => last.body))) diff --git a/compiler/src/dotty/tools/dotc/transform/PrimitiveForwarders.scala b/compiler/src/dotty/tools/dotc/transform/PrimitiveForwarders.scala index d752ce8e7..7c51ba593 100644 --- a/compiler/src/dotty/tools/dotc/transform/PrimitiveForwarders.scala +++ b/compiler/src/dotty/tools/dotc/transform/PrimitiveForwarders.scala @@ -43,7 +43,7 @@ class PrimitiveForwarders extends MiniPhaseTransform with IdentityDenotTransform import ops._ def methodPrimitiveForwarders: List[Tree] = - for (meth <- mixins.flatMap(_.info.decls.flatMap(needsPrimitiveForwarderTo)).distinct) + for (meth <- mixins.flatMap(_.info.decls.toList.flatMap(needsPrimitiveForwarderTo)).distinct) yield polyDefDef(implementation(meth.asTerm), forwarder(meth)) cpy.Template(impl)(body = methodPrimitiveForwarders ::: impl.body) diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala index 3a301167d..e7936e8d9 100644 --- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -13,11 +13,13 @@ import Decorators._ import DenotTransformers._ import StdNames._ import NameOps._ +import NameKinds._ import ast.Trees._ 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. @@ -58,7 +60,7 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th import ops._ def superAccessors(mixin: ClassSymbol): List[Tree] = - for (superAcc <- mixin.info.decls.filter(_ is SuperAccessor).toList) + for (superAcc <- mixin.info.decls.filter(_.isSuperAccessor).toList) yield polyDefDef(implementation(superAcc.asTerm), forwarder(rebindSuper(cls, superAcc))) def methodOverrides(mixin: ClassSymbol): List[Tree] = @@ -72,7 +74,7 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = { val meth = ddef.symbol.asTerm - if (meth.is(SuperAccessor, butNot = Deferred)) { + if (meth.isSuperAccessor && !meth.is(Deferred)) { assert(ddef.rhs.isEmpty) val cls = meth.owner.asClass val ops = new MixinOps(cls, thisTransform) @@ -94,13 +96,7 @@ object ResolveSuper { def rebindSuper(base: Symbol, acc: Symbol)(implicit ctx: Context): Symbol = { var bcs = base.info.baseClasses.dropWhile(acc.owner != _).tail var sym: Symbol = NoSymbol - val unexpandedAccName = - if (acc.is(ExpandedName)) // Cannot use unexpandedName because of #765. t2183.scala would fail if we did. - acc.name - .drop(acc.name.indexOfSlice(nme.EXPAND_SEPARATOR ++ nme.SUPER_PREFIX)) - .drop(nme.EXPAND_SEPARATOR.length) - else acc.name - val SuperAccessorName(memberName) = unexpandedAccName: Name // dotty deviation: ": Name" needed otherwise pattern type is neither a subtype nor a supertype of selector type + val SuperAccessorName(memberName) = acc.name.unexpandedName // dotty deviation: ": Name" needed otherwise pattern type is neither a subtype nor a supertype of selector type ctx.debuglog(i"starting rebindsuper from $base of ${acc.showLocated}: ${acc.info} in $bcs, name = $memberName") while (bcs.nonEmpty && sym == NoSymbol) { val other = bcs.head.info.nonPrivateDecl(memberName) diff --git a/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala b/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala index 1a530b95c..2fea19847 100644 --- a/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala +++ b/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala @@ -11,6 +11,7 @@ import core.Decorators._ import core.StdNames.nme import core.Names._ import core.NameOps._ +import core.NameKinds.DirectName import ast.Trees._ import ast.tpd import collection.mutable @@ -91,7 +92,7 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr /** A new `m$direct` method to accompany the given method `m` */ private def newDirectMethod(sym: Symbol)(implicit ctx: Context): Symbol = { val direct = sym.copy( - name = sym.name.directName, + name = DirectName(sym.name.asTermName).asInstanceOf[sym.ThisName], flags = sym.flags | Synthetic, info = directInfo(sym.info)) if (direct.allOverriddenSymbols.isEmpty) direct.resetFlag(Override) @@ -103,7 +104,7 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr */ private def directMethod(sym: Symbol)(implicit ctx: Context): Symbol = if (sym.owner.isClass) { - val direct = sym.owner.info.member(sym.name.directName) + val direct = sym.owner.info.member(DirectName(sym.name.asTermName)) .suchThat(_.info matches directInfo(sym.info)).symbol if (direct.maybeOwner == sym.owner) direct else newDirectMethod(sym).enteredAfter(thisTransform) @@ -121,7 +122,7 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr case TypeApply(fn, args) => cpy.TypeApply(tree)(directQual(fn), args) case Block(stats, expr) => cpy.Block(tree)(stats, directQual(expr)) case tree: RefTree => - cpy.Ref(tree)(tree.name.directName) + cpy.Ref(tree)(DirectName(tree.name.asTermName)) .withType(directMethod(tree.symbol).termRef) } directQual(tree.qualifier) diff --git a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index 728c1696b..84a32f93b 100644 --- a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -11,6 +11,7 @@ import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTrans import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._ import util.Positions._ import Decorators._ +import NameKinds.{ProtectedAccessorName, ProtectedSetterName, OuterSelectName, SuperAccessorName} import Symbols._, TypeUtils._ /** This class performs the following functions: @@ -71,7 +72,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { val Select(qual, name) = sel val sym = sel.symbol val clazz = qual.symbol.asClass - var superName = name.superName + var superName = SuperAccessorName(name.asTermName) if (clazz is Trait) superName = superName.expandedName(clazz) val superInfo = sel.tpe.widenSingleton.ensureMethodic @@ -79,9 +80,9 @@ class SuperAccessors(thisTransformer: DenotTransformer) { .suchThat(_.signature == superInfo.signature).symbol .orElse { ctx.debuglog(s"add super acc ${sym.showLocated} to $clazz") - val deferredOrPrivate = if (clazz is Trait) Deferred | ExpandedName else Private + val deferredOrPrivate = if (clazz is Trait) Deferred else Private val acc = ctx.newSymbol( - clazz, superName, SuperAccessor | Artifact | Method | deferredOrPrivate, + clazz, superName, Artifact | Method | deferredOrPrivate, superInfo, coord = sym.coord).enteredAfter(thisTransformer) // Diagnostic for SI-7091 if (!accDefs.contains(clazz)) @@ -151,7 +152,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { */ private def ensureProtectedAccessOK(sel: Select, targs: List[Tree])(implicit ctx: Context) = { val sym = sel.symbol - if (sym.isTerm && !sel.name.isOuterSelect && needsProtectedAccessor(sym, sel.pos)) { + if (sym.isTerm && !sel.name.is(OuterSelectName) && needsProtectedAccessor(sym, sel.pos)) { ctx.debuglog("Adding protected accessor for " + sel) protectedAccessorCall(sel, targs) } else sel @@ -168,7 +169,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { assert(clazz.exists, sym) ctx.debuglog("Decided for host class: " + clazz) - val accName = sym.name.protectedAccessorName + val accName = ProtectedAccessorName(sym.name) // if the result type depends on the this type of an enclosing class, the accessor // has to take an object of exactly this type, otherwise it's more general @@ -206,7 +207,8 @@ class SuperAccessors(thisTransformer: DenotTransformer) { } def isProtectedAccessor(tree: Tree)(implicit ctx: Context): Boolean = tree match { - case Apply(TypeApply(Select(_, name), _), qual :: Nil) => name.isProtectedAccessorName + case Apply(TypeApply(Select(_, name), _), qual :: Nil) => + name.is(ProtectedAccessorName) || name.is(ProtectedSetterName) case _ => false } @@ -221,7 +223,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { assert(clazz.exists, sym) ctx.debuglog("Decided for host class: " + clazz) - val accName = sym.name.protectedAccessorName + val accName = ProtectedAccessorName(sym.name) // if the result type depends on the this type of an enclosing class, the accessor // has to take an object of exactly this type, otherwise it's more general @@ -265,7 +267,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { assert(clazz.exists, field) ctx.debuglog("Decided for host class: " + clazz) - val accName = field.name.protectedSetterName + val accName = ProtectedSetterName(field.name) val accType = MethodType(clazz.classInfo.selfType :: field.info :: Nil, defn.UnitType) val protectedAccessor = clazz.info.decl(accName).symbol orElse { val newAcc = ctx.newSymbol( diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index 105f54d3a..4c07ca4c8 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -10,6 +10,7 @@ import Decorators._ import Names._ import StdNames._ import NameOps._ +import NameKinds._ import Flags._ import Annotations._ @@ -51,6 +52,11 @@ class SymUtils(val self: Symbol) extends AnyVal { def isAnyOverride(implicit ctx: Context) = self.is(Override) || self.is(AbsOverride) // careful: AbsOverride is a term only flag. combining with Override would catch only terms. + def isAliasPreferred(implicit ctx: Context) = + self.is(AliasPreferred) || self.name.is(ExpandedName) + + def isSuperAccessor(implicit ctx: Context) = self.name.is(SuperAccessorName) + /** If this is a constructor, its owner: otherwise this. */ final def skipConstructor(implicit ctx: Context): Symbol = if (self.isConstructor) self.owner else self diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index 8a695bf22..10c18e165 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -1,16 +1,17 @@ -package dotty.tools.dotc.transform - -import dotty.tools.dotc.ast.Trees._ -import dotty.tools.dotc.ast.{TreeTypeMap, tpd} -import dotty.tools.dotc.core.Contexts.Context -import dotty.tools.dotc.core.Decorators._ -import dotty.tools.dotc.core.DenotTransformers.DenotTransformer -import dotty.tools.dotc.core.Denotations.SingleDenotation -import dotty.tools.dotc.core.Symbols._ -import dotty.tools.dotc.core.Types._ -import dotty.tools.dotc.core._ -import dotty.tools.dotc.transform.TailRec._ -import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo} +package dotty.tools.dotc +package transform + +import ast.Trees._ +import ast.{TreeTypeMap, tpd} +import core._ +import Contexts.Context +import Decorators._ +import DenotTransformers.DenotTransformer +import Denotations.SingleDenotation +import Symbols._ +import Types._ +import NameKinds.TailLabelName +import TreeTransforms.{MiniPhaseTransform, TransformerInfo} /** * A Tail Rec Transformer @@ -62,6 +63,7 @@ import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, Transforme * </p> */ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParameterization { thisTransform => + import TailRec._ import dotty.tools.dotc.ast.tpd._ @@ -70,7 +72,6 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete override def phaseName: String = "tailrec" override def treeTransformPhase = thisTransform // TODO Make sure tailrec runs at next phase. - final val labelPrefix = "tailLabel" final val labelFlags = Flags.Synthetic | Flags.Label /** Symbols of methods that have @tailrec annotatios inside */ @@ -87,12 +88,12 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete tree } - private def mkLabel(method: Symbol, abstractOverClass: Boolean)(implicit c: Context): TermSymbol = { - val name = c.freshName(labelPrefix) + private def mkLabel(method: Symbol, abstractOverClass: Boolean)(implicit ctx: Context): TermSymbol = { + val name = TailLabelName.fresh() if (method.owner.isClass) - c.newSymbol(method, name.toTermName, labelFlags, fullyParameterizedType(method.info, method.enclosingClass.asClass, abstractOverClass, liftThisType = false)) - else c.newSymbol(method, name.toTermName, labelFlags, method.info) + ctx.newSymbol(method, name.toTermName, labelFlags, fullyParameterizedType(method.info, method.enclosingClass.asClass, abstractOverClass, liftThisType = false)) + else ctx.newSymbol(method, name.toTermName, labelFlags, method.info) } override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index ebb5b605b..eb7773ef3 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -13,6 +13,7 @@ import core.Flags._ import core.Constants._ import core.StdNames._ import core.NameOps._ +import core.NameKinds.OuterSelectName import core.Decorators._ import core.TypeErasure.isErasedType import core.Phases.Phase @@ -50,10 +51,10 @@ class TreeChecker extends Phase with SymTransformer { private val seenModuleVals = collection.mutable.HashMap[String, Symbol]() def isValidJVMName(name: Name) = - !name.exists(c => c == '.' || c == ';' || c =='[' || c == '/') + !name.toString.exists(c => c == '.' || c == ';' || c =='[' || c == '/') def isValidJVMMethodName(name: Name) = - !name.exists(c => c == '.' || c == ';' || c =='[' || c == '/' || c == '<' || c == '>') + !name.toString.exists(c => c == '.' || c == ';' || c =='[' || c == '/' || c == '<' || c == '>') def printError(str: String)(implicit ctx: Context) = { ctx.echo(Console.RED + "[error] " + Console.WHITE + str) @@ -339,7 +340,7 @@ class TreeChecker extends Phase with SymTransformer { val sym = tree.symbol if (!tpe.isInstanceOf[WithFixedSym] && sym.exists && !sym.is(Private) && - !tree.name.isOuterSelect // outer selects have effectively fixed symbols + !tree.name.is(OuterSelectName) // outer selects have effectively fixed symbols ) { val qualTpe = tree.qualifier.typeOpt val member = @@ -390,11 +391,11 @@ class TreeChecker extends Phase with SymTransformer { !x.isCompanionMethod && !x.isValueClassConvertMethod - val symbolsNotDefined = cls.classInfo.decls.toSet.filter(isNonMagicalMethod) -- impl.body.map(_.symbol) - constr.symbol + val symbolsNotDefined = cls.classInfo.decls.toList.toSet.filter(isNonMagicalMethod) -- impl.body.map(_.symbol) - constr.symbol assert(symbolsNotDefined.isEmpty, i" $cls tree does not define methods: ${symbolsNotDefined.toList}%, %\n" + - i"expected: ${cls.classInfo.decls.toSet.filter(isNonMagicalMethod).toList}%, %\n" + + i"expected: ${cls.classInfo.decls.toList.toSet.filter(isNonMagicalMethod)}%, %\n" + i"defined: ${impl.body.map(_.symbol)}%, %") super.typedClassDef(cdef, cls) @@ -403,7 +404,8 @@ class TreeChecker extends Phase with SymTransformer { override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = withDefinedSyms(ddef.tparams) { withDefinedSymss(ddef.vparamss) { - if (!sym.isClassConstructor && !(sym.name eq Names.STATIC_CONSTRUCTOR)) assert(isValidJVMMethodName(sym.name), s"${sym.fullName} name is invalid on jvm") + if (!sym.isClassConstructor && !(sym.name eq Names.STATIC_CONSTRUCTOR)) + assert(isValidJVMMethodName(sym.name), s"${sym.name.debugString} name is invalid on jvm") ddef.vparamss.foreach(_.foreach { vparam => assert(vparam.symbol.is(Param), diff --git a/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala b/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala index 9a6ecef51..44d26e7dd 100644 --- a/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala +++ b/compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala @@ -5,6 +5,7 @@ import core.Symbols._ import core.StdNames._ import ast.Trees._ import core.Types._ +import core.NameKinds.ExceptionBinderName import dotty.tools.dotc.core.Decorators._ import dotty.tools.dotc.core.Flags import dotty.tools.dotc.core.Contexts.Context @@ -83,7 +84,7 @@ class TryCatchPatterns extends MiniPhaseTransform { implicit ctx: Context, info: TransformerInfo): Option[CaseDef] = { if (patternMatchCases.isEmpty) None else { - val exName = ctx.freshName("ex").toTermName + val exName = ExceptionBinderName.fresh() val fallbackSelector = ctx.newSymbol(ctx.owner, exName, Flags.Synthetic | Flags.Case, defn.ThrowableType, coord = pos) val sel = Ident(fallbackSelector.termRef).withPos(pos) diff --git a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala index b16d05644..00d491486 100644 --- a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala +++ b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala @@ -8,6 +8,7 @@ import SymDenotations._ import Contexts._ import Flags._ import StdNames._ +import SymUtils._ /** Methods that apply to user-defined value classes */ object ValueClasses { @@ -24,16 +25,13 @@ object ValueClasses { d.isRealMethod && isDerivedValueClass(d.owner) && !d.isConstructor && - !d.is(SuperAccessor) && + !d.isSuperAccessor && !d.is(Macro) - /** The member that of a derived value class that unboxes it. */ + /** The member of a derived value class that unboxes it. */ def valueClassUnbox(d: ClassDenotation)(implicit ctx: Context): Symbol = // (info.decl(nme.unbox)).orElse(...) uncomment once we accept unbox methods - d.classInfo.decls - .find(d => d.isTerm && d.symbol.is(ParamAccessor)) - .map(_.symbol) - .getOrElse(NoSymbol) + d.classInfo.decls.find(_.is(TermParamAccessor)) /** For a value class `d`, this returns the synthetic cast from the underlying type to * ErasedValueType defined in the companion module. This method is added to the module diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 1fcebf4f0..2f2af9868 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -20,6 +20,7 @@ import Trees._ import config.Config import Names._ import StdNames._ +import NameKinds.DefaultGetterName import ProtoTypes._ import EtaExpansion._ import Inferencing._ @@ -345,7 +346,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => } val getterPrefix = if ((meth is Synthetic) && meth.name == nme.apply) nme.CONSTRUCTOR else meth.name - def getterName = getterPrefix.defaultGetterName(n) + def getterName = DefaultGetterName(getterPrefix, n) if (!meth.hasDefaultParams) EmptyTree else if (receiver.isEmpty) { @@ -402,7 +403,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def missingArg(n: Int): Unit = { val pname = methodType.paramNames(n) fail( - if (pname contains '$') s"not enough arguments for $methString" + if (pname.firstPart contains '$') s"not enough arguments for $methString" else s"missing argument for parameter $pname of $methString") } @@ -718,7 +719,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic => val lhs1 = typedExpr(lhs) val liftedDefs = new mutable.ListBuffer[Tree] val lhs2 = untpd.TypedSplice(liftAssigned(liftedDefs, lhs1)) - val assign = untpd.Assign(lhs2, untpd.Apply(untpd.Select(lhs2, name.init), rhss)) + val assign = untpd.Assign(lhs2, + untpd.Apply(untpd.Select(lhs2, name.asSimpleName.dropRight(1)), rhss)) wrapDefs(liftedDefs, typed(assign)) } diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index 5aee0fd54..e5480c98d 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -12,6 +12,7 @@ import Symbols._ import Decorators._ import Names._ import StdNames._ +import NameKinds.UniqueName import Trees._ import Inferencing._ import util.Positions._ @@ -21,10 +22,10 @@ object EtaExpansion { import tpd._ - private def lift(defs: mutable.ListBuffer[Tree], expr: Tree, prefix: String = "")(implicit ctx: Context): Tree = + private def lift(defs: mutable.ListBuffer[Tree], expr: Tree, prefix: TermName = EmptyTermName)(implicit ctx: Context): Tree = if (isPureExpr(expr)) expr else { - val name = ctx.freshName(prefix).toTermName + val name = UniqueName.fresh(prefix) val liftedType = fullyDefinedType(expr.tpe.widen, "lifted expression", expr.pos) val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, liftedType, coord = positionCoord(expr.pos)) defs += ValDef(sym, expr) @@ -48,7 +49,7 @@ object EtaExpansion { } /** Lift a function argument, stripping any NamedArg wrapper */ - def liftArg(defs: mutable.ListBuffer[Tree], arg: Tree, prefix: String = "")(implicit ctx: Context): Tree = + def liftArg(defs: mutable.ListBuffer[Tree], arg: Tree, prefix: TermName = EmptyTermName)(implicit ctx: Context): Tree = arg match { case arg @ NamedArg(name, arg1) => cpy.NamedArg(arg)(name, lift(defs, arg1, prefix)) case arg => lift(defs, arg, prefix) @@ -62,7 +63,7 @@ object EtaExpansion { case mt: MethodType => (args, mt.paramNames, mt.paramInfos).zipped map { (arg, name, tp) => if (tp.isInstanceOf[ExprType]) arg - else liftArg(defs, arg, if (name contains '$') "" else name.toString + "$") + else liftArg(defs, arg, if (name.firstPart contains '$') EmptyTermName else name) } case _ => args map (liftArg(defs, _)) diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index f6d65fbb9..38a139be1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -13,8 +13,9 @@ import Decorators._ import Constants._ import StdNames.nme import Contexts.Context -import Names.{Name, TermName} +import Names.{Name, TermName, EmptyTermName} import NameOps._ +import NameKinds.{InlineAccessorName, OuterSelectName} import SymDenotations.SymDenotation import Annotations._ import transform.ExplicitOuter @@ -49,8 +50,7 @@ object Inliner { sym.is(AccessFlags) || sym.privateWithin.exists /** The name of the next accessor to be generated */ - def accessorName(implicit ctx: Context) = - ctx.freshNames.newName(inlineMethod.name.asTermName.inlineAccessorName.toString) + def accessorName(implicit ctx: Context) = InlineAccessorName.fresh(inlineMethod.name.asTermName) /** A fresh accessor symbol. * @@ -399,9 +399,6 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { // The class that the this-proxy `selfSym` represents def classOf(selfSym: Symbol) = selfSym.info.widen.classSymbol - // The name of the outer selector that computes the rhs of `selfSym` - def outerSelector(n: Int): TermName = n.toString.toTermName ++ nme.OUTER_SELECT - // The total nesting depth of the class represented by `selfSym`. def outerLevel(selfSym: Symbol): Int = classOf(selfSym).ownersIterator.length @@ -419,7 +416,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { if (!lastSelf.exists) prefix else - untpd.Select(ref(lastSelf), outerSelector(lastLevel - level)).withType(selfSym.info) + untpd.Select(ref(lastSelf), OuterSelectName(EmptyTermName, lastLevel - level)).withType(selfSym.info) bindingsBuf += ValDef(selfSym.asTerm, rhs) lastSelf = selfSym lastLevel = level diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index b436b36b0..19b6dfa71 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -6,6 +6,7 @@ import core._ import ast._ import Trees._, Constants._, StdNames._, Scopes._, Denotations._, Comments._ import Contexts._, Symbols._, Types._, SymDenotations._, Names._, NameOps._, Flags._, Decorators._ +import NameKinds.DefaultGetterName import ast.desugar, ast.desugar._ import ProtoTypes._ import util.Positions._ @@ -281,7 +282,7 @@ class Namer { typer: Typer => tree match { case tree: TypeDef if tree.isClassDef => - val name = checkNoConflict(tree.name.encode).asTypeName + val name = checkNoConflict(tree.name.encode).toTypeName val flags = checkFlags(tree.mods.flags &~ Implicit) val cls = recordSym(ctx.newClassSymbol( ctx.owner, name, flags | inSuperCall, @@ -1012,12 +1013,8 @@ class Namer { typer: Typer => * the corresponding parameter where bound parameters are replaced by * Wildcards. */ - def rhsProto = { - val name = sym.asTerm.name - val idx = name.defaultGetterIndex - if (idx < 0) WildcardType - else { - val original = name.defaultGetterToMethod + def rhsProto = sym.asTerm.name collect { + case DefaultGetterName(original, idx) => val meth: Denotation = if (original.isConstructorName && (sym.owner is ModuleClass)) sym.owner.companionClass.info.decl(nme.CONSTRUCTOR) @@ -1035,8 +1032,7 @@ class Namer { typer: Typer => paramProto(defaultAlts.head.info.widen.paramInfoss, idx) else WildcardType - } - } + } getOrElse WildcardType // println(s"final inherited for $sym: ${inherited.toString}") !!! // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}") diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index ab342dc17..398a7a17e 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -5,6 +5,7 @@ package typer import core._ import ast._ import Contexts._, Types._, Flags._, Denotations._, Names._, StdNames._, NameOps._, Symbols._ +import NameKinds.DepParamName import Trees._ import Constants._ import Scopes._ @@ -401,7 +402,7 @@ object ProtoTypes { /** Create a new TypeParamRef that represents a dependent method parameter singleton */ def newDepTypeParamRef(tp: Type)(implicit ctx: Context): TypeParamRef = { - val poly = PolyType(ctx.freshName(nme.DEP_PARAM_PREFIX).toTypeName :: Nil)( + val poly = PolyType(DepParamName.fresh().toTypeName :: Nil)( pt => TypeBounds.upper(AndType(tp, defn.SingletonType)) :: Nil, pt => defn.AnyType) ctx.typeComparer.addToConstraint(poly, Nil) diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index d61f5fa68..4715873e5 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -6,6 +6,7 @@ import core._ import config._ import Symbols._, SymDenotations._, Types._, Contexts._, Decorators._, Flags._, Names._, NameOps._ import StdNames._, Denotations._, Scopes._, Constants.Constant, SymUtils._ +import NameKinds.DefaultGetterName import Annotations._ import util.Positions._ import scala.collection.{ mutable, immutable } @@ -24,12 +25,8 @@ object RefChecks { import reporting.diagnostic.Message import reporting.diagnostic.messages._ - - private def isDefaultGetter(name: Name): Boolean = - name.isTermName && name.asTermName.defaultGetterIndex >= 0 - private val defaultMethodFilter = new NameFilter { - def apply(pre: Type, name: Name)(implicit ctx: Context): Boolean = isDefaultGetter(name) + def apply(pre: Type, name: Name)(implicit ctx: Context): Boolean = name.is(DefaultGetterName) } /** Only one overloaded alternative is allowed to define default arguments */ @@ -45,7 +42,9 @@ object RefChecks { if defaultGetterClass.isClass ) { val defaultGetterNames = defaultGetterClass.asClass.memberNames(defaultMethodFilter) - val defaultMethodNames = defaultGetterNames map (_.asTermName.defaultGetterToMethod) + val defaultMethodNames = defaultGetterNames map { _ rewrite { + case DefaultGetterName(methName, _) => methName + }} for (name <- defaultMethodNames) { val methods = clazz.info.member(name).alternatives.map(_.symbol) @@ -238,7 +237,7 @@ object RefChecks { } } else - isDefaultGetter(member.name) || // default getters are not checked for compatibility + member.name.is(DefaultGetterName) || // default getters are not checked for compatibility memberTp.overrides(otherTp) //Console.println(infoString(member) + " overrides " + infoString(other) + " in " + clazz);//DEBUG @@ -298,7 +297,7 @@ object RefChecks { } else if (other.isEffectivelyFinal) { // (1.2) overrideError(i"cannot override final member ${other.showLocated}") } else if (!other.is(Deferred) && - !isDefaultGetter(other.name) && + !other.name.is(DefaultGetterName) && !member.isAnyOverride) { // (*) Exclusion for default getters, fixes SI-5178. We cannot assign the Override flag to // the default getter: one default getter might sometimes override, sometimes not. Example in comment on ticket. @@ -405,7 +404,7 @@ object RefChecks { def ignoreDeferred(member: SingleDenotation) = member.isType || - member.symbol.is(SuperAccessor) || // not yet synthesized + member.symbol.isSuperAccessor || // not yet synthesized member.symbol.is(JavaDefined) && hasJavaErasedOverriding(member.symbol) // 2. Check that only abstract classes have deferred members diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index ead4ad5cb..ec6fb1770 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -91,8 +91,8 @@ trait TypeAssigner { else parent } - val refinableDecls = info.decls.filterNot( - sym => sym.is(TypeParamAccessor | Private) || sym.isConstructor) + val refinableDecls = info.decls.filter( + sym => !(sym.is(TypeParamAccessor | Private) || sym.isConstructor)) val fullType = (parentType /: refinableDecls)(addRefinement) mapOver(fullType) case TypeBounds(lo, hi) if variance > 0 => diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index a7b8200b5..e6236d122 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -18,6 +18,7 @@ import SymDenotations._ import Annotations._ import Names._ import NameOps._ +import NameKinds._ import Flags._ import Decorators._ import ErrorReporting._ @@ -572,7 +573,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def canAssign(sym: Symbol) = // allow assignments from the primary constructor to class fields sym.is(Mutable, butNot = Accessor) || ctx.owner.isPrimaryConstructor && !sym.is(Method) && sym.owner == ctx.owner.owner || - ctx.owner.name.isTraitSetterName || ctx.owner.isStaticConstructor + ctx.owner.name.is(TraitSetterName) || ctx.owner.isStaticConstructor lhsCore.tpe match { case ref: TermRef if canAssign(ref.symbol) => assignType(cpy.Assign(tree)(lhs1, typed(tree.rhs, ref.info))) diff --git a/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala b/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala index 8892a570e..5dbec3e5a 100644 --- a/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala +++ b/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala @@ -3,9 +3,12 @@ package dotc package util import scala.collection.mutable +import core.Names.TermName +import core.NameKinds.UniqueNameKind +import core.StdNames.str -trait FreshNameCreator { - def newName(prefix: String = ""): String +abstract class FreshNameCreator { + def newName(prefix: TermName, unique: UniqueNameKind): TermName } object FreshNameCreator { @@ -18,11 +21,11 @@ object FreshNameCreator { * that the returned name has never been returned by a previous * call to this function (provided the prefix does not end in a digit). */ - def newName(prefix: String): String = { - val safePrefix = prefix.replaceAll("""[<>]""", """\$""") - counters(safePrefix) += 1 - val counter = counters(safePrefix) - if (prefix.isEmpty) "$" + counter + "$" else safePrefix + counter + def newName(prefix: TermName, unique: UniqueNameKind): TermName = { + val key = str.sanitize(prefix.toString + unique.separator) + counters(key) += 1 + val counter = counters(key) + prefix.derived(unique.NumberedInfo(counter)) } } } diff --git a/compiler/src/dotty/tools/dotc/util/NameTransformer.scala b/compiler/src/dotty/tools/dotc/util/NameTransformer.scala index 330d513fe..52f8e6ec0 100644 --- a/compiler/src/dotty/tools/dotc/util/NameTransformer.scala +++ b/compiler/src/dotty/tools/dotc/util/NameTransformer.scala @@ -60,7 +60,7 @@ object NameTransformer { * @param name the string to encode * @return the string with all recognized opchars replaced with their encoding */ - def encode[N <: Name](name: N): N = { + def encode(name: SimpleTermName): SimpleTermName = { var buf: StringBuilder = null val len = name.length var i = 0 @@ -87,8 +87,7 @@ object NameTransformer { i += 1 } if (buf eq null) name - else if (name.isTermName) buf.toString.toTermName.asInstanceOf[N] - else buf.toString.toTypeName.asInstanceOf[N] + else termName(buf.toString) } /** Replace `\$opname` by corresponding operator symbol. diff --git a/compiler/test/dotc/tests.scala b/compiler/test/dotc/tests.scala index 1c80767ee..af2c88e1a 100644 --- a/compiler/test/dotc/tests.scala +++ b/compiler/test/dotc/tests.scala @@ -203,7 +203,9 @@ class tests extends CompilerTest { private val stdlibFiles: List[String] = StdLibSources.whitelisted - @Test def compileStdLib = compileList("compileStdLib", stdlibFiles, "-migration" :: "-Yno-inline" :: scala2mode) + @Test def compileStdLib = + if (!generatePartestFiles) + compileList("compileStdLib", stdlibFiles, "-migration" :: "-Yno-inline" :: scala2mode) @Test def compileMixed = compileLine( """../tests/pos/B.scala |../scala-scala/src/library/scala/collection/immutable/Seq.scala diff --git a/compiler/test/dotty/tools/DottyTypeStealer.scala b/compiler/test/dotty/tools/DottyTypeStealer.scala index ff6e67e41..727cd9e7d 100644 --- a/compiler/test/dotty/tools/DottyTypeStealer.scala +++ b/compiler/test/dotty/tools/DottyTypeStealer.scala @@ -19,7 +19,7 @@ object DottyTypeStealer extends DottyTest { implicit val ctx = context val findValDef: (List[ValDef], tpd.Tree) => List[ValDef] = (acc , tree) => { tree match { - case t: ValDef if t.name.startsWith(dummyName.toTermName) => t :: acc + case t: ValDef if t.name.startsWith(dummyName) => t :: acc case _ => acc } } diff --git a/compiler/test/dotty/tools/ShowClassTests.scala b/compiler/test/dotty/tools/ShowClassTests.scala index 4aa9e8845..66ae80169 100644 --- a/compiler/test/dotty/tools/ShowClassTests.scala +++ b/compiler/test/dotty/tools/ShowClassTests.scala @@ -65,7 +65,7 @@ class ShowClassTests extends DottyTest { debug_println(s"blacklisted package: $path") else { for ( - sym <- pkg.info.decls if sym.owner == pkg.moduleClass && !(sym.name contains '$') + sym <- pkg.info.decls if sym.owner == pkg.moduleClass && !(sym.name.toString contains '$') ) { debug_println(s"showing $sym in ${pkg.fullName}") if (sym is PackageVal) showPackage(sym.asTerm) diff --git a/compiler/test/dotty/tools/dotc/ParallelTesting.scala b/compiler/test/dotty/tools/dotc/ParallelTesting.scala index 45de03b48..80c56808b 100644 --- a/compiler/test/dotty/tools/dotc/ParallelTesting.scala +++ b/compiler/test/dotty/tools/dotc/ParallelTesting.scala @@ -423,7 +423,8 @@ trait ParallelTesting { self => extends Test(testSources, times, threadLimit, suppressAllOutput) { private def runMain(dir: JFile, testSource: TestSource): Array[String] = { def renderStackTrace(ex: Throwable): String = - ex.getStackTrace + if (ex == null) "" + else ex.getStackTrace .takeWhile(_.getMethodName != "invoke0") .mkString(" ", "\n ", "") |