aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--AUTHORS.md23
-rw-r--r--compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala14
-rw-r--r--compiler/src/dotty/tools/dotc/FromTasty.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Desugar.scala100
-rw-r--r--compiler/src/dotty/tools/dotc/ast/TreeInfo.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Trees.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/ast/tpd.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala149
-rw-r--r--compiler/src/dotty/tools/dotc/classpath/ClassPath.scala60
-rw-r--r--compiler/src/dotty/tools/dotc/classpath/ClassPathFactory.scala83
-rw-r--r--compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala245
-rw-r--r--compiler/src/dotty/tools/dotc/classpath/FileUtils.scala74
-rw-r--r--compiler/src/dotty/tools/dotc/classpath/PackageNameUtils.scala26
-rw-r--r--compiler/src/dotty/tools/dotc/classpath/VirtualDirectoryClassPath.scala52
-rw-r--r--compiler/src/dotty/tools/dotc/classpath/ZipAndJarFileLookupFactory.scala176
-rw-r--r--compiler/src/dotty/tools/dotc/classpath/ZipArchiveFileLookup.scala68
-rw-r--r--compiler/src/dotty/tools/dotc/config/JavaPlatform.scala14
-rw-r--r--compiler/src/dotty/tools/dotc/config/PathResolver.scala21
-rw-r--r--compiler/src/dotty/tools/dotc/config/Printers.scala1
-rw-r--r--compiler/src/dotty/tools/dotc/config/ScalaSettings.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/core/Contexts.scala5
-rw-r--r--compiler/src/dotty/tools/dotc/core/Definitions.scala57
-rw-r--r--compiler/src/dotty/tools/dotc/core/Denotations.scala46
-rw-r--r--compiler/src/dotty/tools/dotc/core/Flags.scala29
-rw-r--r--compiler/src/dotty/tools/dotc/core/NameKinds.scala317
-rw-r--r--compiler/src/dotty/tools/dotc/core/NameOps.scala409
-rw-r--r--compiler/src/dotty/tools/dotc/core/Names.scala455
-rw-r--r--compiler/src/dotty/tools/dotc/core/Scopes.scala73
-rw-r--r--compiler/src/dotty/tools/dotc/core/Signature.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/core/StdNames.scala101
-rw-r--r--compiler/src/dotty/tools/dotc/core/SymDenotations.scala182
-rw-r--r--compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala111
-rw-r--r--compiler/src/dotty/tools/dotc/core/Symbols.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeApplications.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeComparer.scala7
-rw-r--r--compiler/src/dotty/tools/dotc/core/Types.scala41
-rw-r--r--compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala46
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/NameBuffer.scala115
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TastyBuffer.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala35
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TastyName.scala30
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala5
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala26
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TastyReader.scala1
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala72
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala46
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala59
-rw-r--r--compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala41
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Parsers.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Scanners.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Tokens.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/package.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/printing/Formatting.scala14
-rw-r--r--compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala23
-rw-r--r--compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala15
-rw-r--r--compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/repl/ammonite/Protocol.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/transform/CapturedVars.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ElimByName.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/transform/Erasure.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala12
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala5
-rw-r--r--compiler/src/dotty/tools/dotc/transform/FirstTransform.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/transform/LambdaLift.scala12
-rw-r--r--compiler/src/dotty/tools/dotc/transform/LazyVals.scala14
-rw-r--r--compiler/src/dotty/tools/dotc/transform/LiftTry.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/transform/Mixin.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/transform/MoveStatics.scala1
-rw-r--r--compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala28
-rw-r--r--compiler/src/dotty/tools/dotc/transform/PostTyper.scala12
-rw-r--r--compiler/src/dotty/tools/dotc/transform/PrimitiveForwarders.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala14
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala7
-rw-r--r--compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala18
-rw-r--r--compiler/src/dotty/tools/dotc/transform/SymUtils.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/transform/TailRec.scala37
-rw-r--r--compiler/src/dotty/tools/dotc/transform/TreeChecker.scala14
-rw-r--r--compiler/src/dotty/tools/dotc/transform/TryCatchPatterns.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ValueClasses.scala10
-rw-r--r--compiler/src/dotty/tools/dotc/transform/patmat/Space.scala161
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Applications.scala28
-rw-r--r--compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala9
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Inliner.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Namer.scala22
-rw-r--r--compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/typer/RefChecks.scala17
-rw-r--r--compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala24
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala17
-rw-r--r--compiler/src/dotty/tools/dotc/util/NameTransformer.scala5
-rw-r--r--compiler/src/dotty/tools/io/ClassPath.scala425
-rw-r--r--compiler/src/dotty/tools/io/PlainFile.scala170
-rw-r--r--compiler/src/dotty/tools/io/package.scala2
-rw-r--r--compiler/test/dotc/tests.scala4
-rw-r--r--compiler/test/dotty/tools/DottyTypeStealer.scala2
-rw-r--r--compiler/test/dotty/tools/ShowClassTests.scala2
-rw-r--r--compiler/test/dotty/tools/dotc/ParallelTesting.scala3
-rw-r--r--project/build.properties2
-rw-r--r--sbt-bridge/test/xsbt/ScalaCompilerForUnitTesting.scala2
-rw-r--r--tests/neg/i2142.scala28
-rw-r--r--tests/patmat/enum-HList.scala22
-rw-r--r--tests/patmat/enum-Tree.scala29
-rw-r--r--tests/patmat/enumColor.scala12
-rw-r--r--tests/patmat/patmat-indent.check2
-rw-r--r--tests/patmat/patmat-indent.scala2
-rw-r--r--tests/patmat/planets.scala26
-rw-r--r--tests/patmat/t6420.check2
-rw-r--r--tests/patmat/t7285.check2
-rw-r--r--tests/patmat/t7466.check2
-rw-r--r--tests/pos/i2188.scala5
-rw-r--r--tests/pos/i2198.scala6
-rw-r--r--tests/pos/i2200/Hello.scala6
-rw-r--r--tests/pos/i2200/package.scala4
-rw-r--r--tests/pos/i2218.scala9
-rw-r--r--tests/pos/i2219.scala7
-rw-r--r--tests/pos/t7296.scala (renamed from tests/pending/pos/t7296.scala)0
-rw-r--r--tests/run/1938.scala45
-rw-r--r--tests/run/case-class-23.check (renamed from tests/pending/run/case-class-23.check)0
-rw-r--r--tests/run/case-class-23.scala (renamed from tests/pending/run/case-class-23.scala)0
-rw-r--r--tests/run/double-pattern-type.scala40
-rw-r--r--tests/run/enum-Color.scala4
-rw-r--r--tests/run/i2163.scala21
-rw-r--r--tests/run/zero-arity-case-class.scala26
132 files changed, 3296 insertions, 1707 deletions
diff --git a/.gitignore b/.gitignore
index 170cf4823..7508b4932 100644
--- a/.gitignore
+++ b/.gitignore
@@ -55,3 +55,5 @@ testlogs/
local/
compiler/test/debug/Gen.jar
+compiler/before-pickling.txt
+compiler/after-pickling.txt
diff --git a/AUTHORS.md b/AUTHORS.md
index db2f34a56..e197a6c5c 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -1,23 +1,28 @@
-The dotty compiler frontend has been developed since November 2012 by Martin Odersky. It is expected and hoped for
+The dotty compiler frontend has been developed since November 2012 by Martin Odersky. It is expected and hoped for
that the list of contributors to the codebase will grow quickly. Dotty draws inspiration and code from the original
-Scala compiler "nsc", which is developed at [scala/scala](https://github.com/scala/scala).
+Scala compiler "nsc", which is developed at [scala/scala](https://github.com/scala/scala).
The majority of the dotty codebase is new code, with the exception of the components mentioned below. We have for each component tried to come up with a list of the original authors in the [scala/scala](https://github.com/scala/scala) codebase. Apologies if some major authors were omitted by oversight.
`dotty.tools.dotc.ast`
-> The syntax tree handling is mostly new, but some elements, such as the idea of tree copiers and the `TreeInfo` module,
-> were adopted from [scala/scala](https://github.com/scala/scala).
+> The syntax tree handling is mostly new, but some elements, such as the idea of tree copiers and the `TreeInfo` module,
+> were adopted from [scala/scala](https://github.com/scala/scala).
> The original authors of these parts include Martin Odersky, Paul Phillips, Adriaan Moors, and Matthias Zenger.
+`dotty.tools.dotc.classpath`
+
+> The classpath handling is taken mostly as is from [scala/scala](https://github.com/scala/scala).
+> The original authors were Grzegorz Kossakowski, Michał Pociecha, Lukas Rytz, Jason Zaugg and others.
+
`dotty.tools.dotc.config`
-> The configuration components were adapted and extended from [scala/scala](https://github.com/scala/scala).
+> The configuration components were adapted and extended from [scala/scala](https://github.com/scala/scala).
> The original sources were authored by Paul Phillips with contributions from Martin Odersky, Miguel Garcia and others.
-
+
`dotty.tools.dotc.core`
-> The core data structures and operations are mostly new. Some parts (e.g. those dealing with names) were adapted from [scala/scala](https://github.com/scala/scala).
+> The core data structures and operations are mostly new. Some parts (e.g. those dealing with names) were adapted from [scala/scala](https://github.com/scala/scala).
> These were originally authored by Martin Odersky, Adriaan Moors, Jason Zaugg, Paul Phillips, Eugene Burmako and others.
`dotty.tools.dotc.core.pickling`
@@ -41,7 +46,7 @@ The majority of the dotty codebase is new code, with the exception of the compon
> The utilities package is a mix of new and adapted components. The files in [scala/scala](https://github.com/scala/scala) were originally authored by many people,
> including Paul Phillips, Martin Odersky, Sean McDirmid, and others.
-
+
`dotty.tools.io`
> The I/O support library was adapted from current Scala compiler. Original authors were Paul Phillips and others.
@@ -53,7 +58,7 @@ The majority of the dotty codebase is new code, with the exception of the compon
> the needs of dotty. Original authors include: Adrian Moors, Lukas Rytz,
> Grzegorz Kossakowski, Paul Phillips
-`dotty.tools.dotc.sbt and everything in bridge/`
+`dotty.tools.dotc.sbt and everything in sbt-bridge/`
> The sbt compiler phases are based on
> https://github.com/adriaanm/scala/tree/sbt-api-consolidate/src/compiler/scala/tools/sbt
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..013516cd5 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)
@@ -352,8 +353,6 @@ object desugar {
lazy val creatorExpr = New(classTypeRef, constrVparamss nestedMap refOfDef)
// Methods to add to a case class C[..](p1: T1, ..., pN: Tn)(moreParams)
- // def isDefined = true
- // def productArity = N
// def _1 = this.p1
// ...
// def _N = this.pN
@@ -361,17 +360,38 @@ object desugar {
// pN: TN = pN: @uncheckedVariance)(moreParams) =
// new C[...](p1, ..., pN)(moreParams)
//
+ // Above arity 22 we also synthesize:
+ // def productArity = N
+ // def productElement(i: Int): Any = i match { ... }
+ //
// Note: copy default parameters need @uncheckedVariance; see
// neg/t1843-variances.scala for a test case. The test would give
// two errors without @uncheckedVariance, one of them spurious.
- val caseClassMeths =
- if (isCaseClass) {
- def syntheticProperty(name: TermName, rhs: Tree) =
- DefDef(name, Nil, Nil, TypeTree(), rhs).withMods(synthetic)
+ val caseClassMeths = {
+ def syntheticProperty(name: TermName, rhs: Tree) =
+ DefDef(name, Nil, Nil, TypeTree(), rhs).withMods(synthetic)
+ def productArity = syntheticProperty(nme.productArity, Literal(Constant(arity)))
+ def productElement = {
+ val param = makeSyntheticParameter(tpt = ref(defn.IntType))
+ // case N => _${N + 1}
+ val cases = 0.until(arity).map { i =>
+ CaseDef(Literal(Constant(i)), EmptyTree, Select(This(EmptyTypeIdent), nme.selectorName(i)))
+ }
+ val ioob = ref(defn.IndexOutOfBoundsException.typeRef)
+ val error = Throw(New(ioob, List(List(Select(refOfDef(param), nme.toString_)))))
+ // case _ => throw new IndexOutOfBoundsException(i.toString)
+ val defaultCase = CaseDef(untpd.Ident(nme.WILDCARD), EmptyTree, error)
+ val body = Match(refOfDef(param), (cases :+ defaultCase).toList)
+ DefDef(nme.productElement, Nil, List(List(param)), TypeTree(defn.AnyType), body)
+ .withMods(synthetic)
+ }
+ def productElemMeths = {
val caseParams = constrVparamss.head.toArray
- val productElemMeths =
- for (i <- 0 until arity if nme.selectorName(i) `ne` caseParams(i).name)
- yield syntheticProperty(nme.selectorName(i), Select(This(EmptyTypeIdent), caseParams(i).name))
+ for (i <- 0 until arity if nme.selectorName(i) `ne` caseParams(i).name)
+ yield syntheticProperty(nme.selectorName(i), Select(This(EmptyTypeIdent), caseParams(i).name))
+ }
+ def enumTagMeths = if (isEnumCase) enumTagMeth(CaseKind.Class)._1 :: Nil else Nil
+ def copyMeths = {
def isRepeated(tree: Tree): Boolean = tree match {
case PostfixOp(_, Ident(nme.raw.STAR)) => true
case ByNameTypeTree(tree1) => isRepeated(tree1)
@@ -381,38 +401,46 @@ object desugar {
case ValDef(_, tpt, _) => isRepeated(tpt)
case _ => false
})
-
- val copyMeths =
- if (mods.is(Abstract) || hasRepeatedParam) Nil // cannot have default arguments for repeated parameters, hence copy method is not issued
- else {
- def copyDefault(vparam: ValDef) =
- makeAnnotated("scala.annotation.unchecked.uncheckedVariance", refOfDef(vparam))
- val copyFirstParams = derivedVparamss.head.map(vparam =>
- cpy.ValDef(vparam)(rhs = copyDefault(vparam)))
- val copyRestParamss = derivedVparamss.tail.nestedMap(vparam =>
- cpy.ValDef(vparam)(rhs = EmptyTree))
- DefDef(nme.copy, derivedTparams, copyFirstParams :: copyRestParamss, TypeTree(), creatorExpr)
- .withMods(synthetic) :: Nil
- }
-
- val enumTagMeths = if (isEnumCase) enumTagMeth(CaseKind.Class)._1 :: Nil else Nil
- copyMeths ::: enumTagMeths ::: productElemMeths.toList
+ if (mods.is(Abstract) || hasRepeatedParam) Nil // cannot have default arguments for repeated parameters, hence copy method is not issued
+ else {
+ def copyDefault(vparam: ValDef) =
+ makeAnnotated("scala.annotation.unchecked.uncheckedVariance", refOfDef(vparam))
+ val copyFirstParams = derivedVparamss.head.map(vparam =>
+ cpy.ValDef(vparam)(rhs = copyDefault(vparam)))
+ val copyRestParamss = derivedVparamss.tail.nestedMap(vparam =>
+ cpy.ValDef(vparam)(rhs = EmptyTree))
+ DefDef(nme.copy, derivedTparams, copyFirstParams :: copyRestParamss, TypeTree(), creatorExpr)
+ .withMods(synthetic) :: Nil
+ }
}
+
+ // Above MaxTupleArity we extend Product instead of ProductN, in this
+ // case we need to synthesise productElement & productArity.
+ def largeProductMeths =
+ if (arity > Definitions.MaxTupleArity) productElement :: productArity :: Nil
+ else Nil
+
+ if (isCaseClass)
+ largeProductMeths ::: copyMeths ::: enumTagMeths ::: productElemMeths.toList
else Nil
+ }
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)
}
+ def product =
+ if (arity > Definitions.MaxTupleArity) scalaDot(str.Product.toTypeName)
+ else productConstr(arity)
- // Case classes and case objects get a ProductN parent
+ // Case classes and case objects get Product/ProductN parents
var parents1 = parents
if (isEnumCase && parents.isEmpty)
parents1 = enumClassTypeRef :: Nil
- if (mods.is(Case) && arity <= Definitions.MaxTupleArity)
- parents1 = parents1 :+ productConstr(arity) // TODO: This also adds Product0 to caes objects. Do we want that?
+ if (mods.is(Case))
+ parents1 = parents1 :+ product // TODO: This also adds Product0 to case objects. Do we want that?
if (isEnum)
parents1 = parents1 :+ ref(defn.EnumType)
@@ -635,7 +663,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 +838,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 +916,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/classpath/AggregateClassPath.scala b/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala
new file mode 100644
index 000000000..ec3e8fdf4
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package dotty.tools.dotc.classpath
+
+import java.net.URL
+import scala.annotation.tailrec
+import scala.collection.mutable.ArrayBuffer
+import scala.reflect.internal.FatalError
+import scala.reflect.io.AbstractFile
+import dotty.tools.io.ClassPath
+import dotty.tools.io.ClassRepresentation
+
+/**
+ * A classpath unifying multiple class- and sourcepath entries.
+ * The Classpath can obtain entries for classes and sources independently
+ * so it tries to do operations quite optimally - iterating only these collections
+ * which are needed in the given moment and only as far as it's necessary.
+ *
+ * @param aggregates classpath instances containing entries which this class processes
+ */
+case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath {
+ override def findClassFile(className: String): Option[AbstractFile] = {
+ @tailrec
+ def find(aggregates: Seq[ClassPath]): Option[AbstractFile] =
+ if (aggregates.nonEmpty) {
+ val classFile = aggregates.head.findClassFile(className)
+ if (classFile.isDefined) classFile
+ else find(aggregates.tail)
+ } else None
+
+ find(aggregates)
+ }
+
+ override def findClass(className: String): Option[ClassRepresentation] = {
+ @tailrec
+ def findEntry(aggregates: Seq[ClassPath], isSource: Boolean): Option[ClassRepresentation] =
+ if (aggregates.nonEmpty) {
+ val entry = aggregates.head.findClass(className) match {
+ case s @ Some(_: SourceFileEntry) if isSource => s
+ case s @ Some(_: ClassFileEntry) if !isSource => s
+ case _ => None
+ }
+ if (entry.isDefined) entry
+ else findEntry(aggregates.tail, isSource)
+ } else None
+
+ val classEntry = findEntry(aggregates, isSource = false)
+ val sourceEntry = findEntry(aggregates, isSource = true)
+
+ (classEntry, sourceEntry) match {
+ case (Some(c: ClassFileEntry), Some(s: SourceFileEntry)) => Some(ClassAndSourceFilesEntry(c.file, s.file))
+ case (c @ Some(_), _) => c
+ case (_, s) => s
+ }
+ }
+
+ override def asURLs: Seq[URL] = aggregates.flatMap(_.asURLs)
+
+ override def asClassPathStrings: Seq[String] = aggregates.map(_.asClassPathString).distinct
+
+ override def asSourcePathString: String = ClassPath.join(aggregates map (_.asSourcePathString): _*)
+
+ override private[dotty] def packages(inPackage: String): Seq[PackageEntry] = {
+ val aggregatedPackages = aggregates.flatMap(_.packages(inPackage)).distinct
+ aggregatedPackages
+ }
+
+ override private[dotty] def classes(inPackage: String): Seq[ClassFileEntry] =
+ getDistinctEntries(_.classes(inPackage))
+
+ override private[dotty] def sources(inPackage: String): Seq[SourceFileEntry] =
+ getDistinctEntries(_.sources(inPackage))
+
+ override private[dotty] def list(inPackage: String): ClassPathEntries = {
+ val (packages, classesAndSources) = aggregates.map { cp =>
+ try {
+ cp.list(inPackage)
+ } catch {
+ case ex: java.io.IOException =>
+ val e = new FatalError(ex.getMessage)
+ e.initCause(ex)
+ throw e
+ }
+ }.unzip
+ val distinctPackages = packages.flatten.distinct
+ val distinctClassesAndSources = mergeClassesAndSources(classesAndSources: _*)
+ ClassPathEntries(distinctPackages, distinctClassesAndSources)
+ }
+
+ /**
+ * Returns only one entry for each name. If there's both a source and a class entry, it
+ * creates an entry containing both of them. If there would be more than one class or source
+ * entries for the same class it always would use the first entry of each type found on a classpath.
+ */
+ private def mergeClassesAndSources(entries: Seq[ClassRepresentation]*): Seq[ClassRepresentation] = {
+ // based on the implementation from MergedClassPath
+ var count = 0
+ val indices = collection.mutable.HashMap[String, Int]()
+ val mergedEntries = new ArrayBuffer[ClassRepresentation](1024)
+
+ for {
+ partOfEntries <- entries
+ entry <- partOfEntries
+ } {
+ val name = entry.name
+ if (indices contains name) {
+ val index = indices(name)
+ val existing = mergedEntries(index)
+
+ if (existing.binary.isEmpty && entry.binary.isDefined)
+ mergedEntries(index) = ClassAndSourceFilesEntry(entry.binary.get, existing.source.get)
+ if (existing.source.isEmpty && entry.source.isDefined)
+ mergedEntries(index) = ClassAndSourceFilesEntry(existing.binary.get, entry.source.get)
+ }
+ else {
+ indices(name) = count
+ mergedEntries += entry
+ count += 1
+ }
+ }
+ mergedEntries.toIndexedSeq
+ }
+
+ private def getDistinctEntries[EntryType <: ClassRepresentation](getEntries: ClassPath => Seq[EntryType]): Seq[EntryType] = {
+ val seenNames = collection.mutable.HashSet[String]()
+ val entriesBuffer = new ArrayBuffer[EntryType](1024)
+ for {
+ cp <- aggregates
+ entry <- getEntries(cp) if !seenNames.contains(entry.name)
+ } {
+ entriesBuffer += entry
+ seenNames += entry.name
+ }
+ entriesBuffer.toIndexedSeq
+ }
+}
+
+object AggregateClassPath {
+ def createAggregate(parts: ClassPath*): ClassPath = {
+ val elems = new ArrayBuffer[ClassPath]()
+ parts foreach {
+ case AggregateClassPath(ps) => elems ++= ps
+ case p => elems += p
+ }
+ if (elems.size == 1) elems.head
+ else AggregateClassPath(elems.toIndexedSeq)
+ }
+}
diff --git a/compiler/src/dotty/tools/dotc/classpath/ClassPath.scala b/compiler/src/dotty/tools/dotc/classpath/ClassPath.scala
new file mode 100644
index 000000000..129c6b9fe
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/classpath/ClassPath.scala
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package dotty.tools.dotc.classpath
+
+import scala.reflect.io.AbstractFile
+import dotty.tools.io.ClassRepresentation
+
+case class ClassPathEntries(packages: Seq[PackageEntry], classesAndSources: Seq[ClassRepresentation])
+
+object ClassPathEntries {
+ import scala.language.implicitConversions
+ // to have working unzip method
+ implicit def entry2Tuple(entry: ClassPathEntries): (Seq[PackageEntry], Seq[ClassRepresentation]) = (entry.packages, entry.classesAndSources)
+}
+
+trait ClassFileEntry extends ClassRepresentation {
+ def file: AbstractFile
+}
+
+trait SourceFileEntry extends ClassRepresentation {
+ def file: AbstractFile
+}
+
+trait PackageEntry {
+ def name: String
+}
+
+private[dotty] case class ClassFileEntryImpl(file: AbstractFile) extends ClassFileEntry {
+ override def name = FileUtils.stripClassExtension(file.name) // class name
+
+ override def binary: Option[AbstractFile] = Some(file)
+ override def source: Option[AbstractFile] = None
+}
+
+private[dotty] case class SourceFileEntryImpl(file: AbstractFile) extends SourceFileEntry {
+ override def name = FileUtils.stripSourceExtension(file.name)
+
+ override def binary: Option[AbstractFile] = None
+ override def source: Option[AbstractFile] = Some(file)
+}
+
+private[dotty] case class ClassAndSourceFilesEntry(classFile: AbstractFile, srcFile: AbstractFile) extends ClassRepresentation {
+ override def name = FileUtils.stripClassExtension(classFile.name)
+
+ override def binary: Option[AbstractFile] = Some(classFile)
+ override def source: Option[AbstractFile] = Some(srcFile)
+}
+
+private[dotty] case class PackageEntryImpl(name: String) extends PackageEntry
+
+private[dotty] trait NoSourcePaths {
+ def asSourcePathString: String = ""
+ private[dotty] def sources(inPackage: String): Seq[SourceFileEntry] = Seq.empty
+}
+
+private[dotty] trait NoClassPaths {
+ def findClassFile(className: String): Option[AbstractFile] = None
+ private[dotty] def classes(inPackage: String): Seq[ClassFileEntry] = Seq.empty
+}
diff --git a/compiler/src/dotty/tools/dotc/classpath/ClassPathFactory.scala b/compiler/src/dotty/tools/dotc/classpath/ClassPathFactory.scala
new file mode 100644
index 000000000..ac8fc633f
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/classpath/ClassPathFactory.scala
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package dotty.tools.dotc.classpath
+
+import scala.reflect.io.{AbstractFile, VirtualDirectory}
+import scala.reflect.io.Path.string2path
+import dotty.tools.dotc.config.Settings
+import FileUtils.AbstractFileOps
+import dotty.tools.io.ClassPath
+import dotty.tools.dotc.core.Contexts.Context
+
+/**
+ * Provides factory methods for classpath. When creating classpath instances for a given path,
+ * it uses proper type of classpath depending on a types of particular files containing sources or classes.
+ */
+class ClassPathFactory {
+ /**
+ * Create a new classpath based on the abstract file.
+ */
+ def newClassPath(file: AbstractFile)(implicit ctx: Context): ClassPath = ClassPathFactory.newClassPath(file)
+
+ /**
+ * Creators for sub classpaths which preserve this context.
+ */
+ def sourcesInPath(path: String)(implicit ctx: Context): List[ClassPath] =
+ for {
+ file <- expandPath(path, expandStar = false)
+ dir <- Option(AbstractFile getDirectory file)
+ } yield createSourcePath(dir)
+
+
+ def expandPath(path: String, expandStar: Boolean = true): List[String] = dotty.tools.io.ClassPath.expandPath(path, expandStar)
+
+ def expandDir(extdir: String): List[String] = dotty.tools.io.ClassPath.expandDir(extdir)
+
+ def contentsOfDirsInPath(path: String)(implicit ctx: Context): List[ClassPath] =
+ for {
+ dir <- expandPath(path, expandStar = false)
+ name <- expandDir(dir)
+ entry <- Option(AbstractFile.getDirectory(name))
+ } yield newClassPath(entry)
+
+ def classesInExpandedPath(path: String)(implicit ctx: Context): IndexedSeq[ClassPath] =
+ classesInPathImpl(path, expand = true).toIndexedSeq
+
+ def classesInPath(path: String)(implicit ctx: Context) = classesInPathImpl(path, expand = false)
+
+ def classesInManifest(useManifestClassPath: Boolean)(implicit ctx: Context) =
+ if (useManifestClassPath) dotty.tools.io.ClassPath.manifests.map(url => newClassPath(AbstractFile getResources url))
+ else Nil
+
+ // Internal
+ protected def classesInPathImpl(path: String, expand: Boolean)(implicit ctx: Context) =
+ for {
+ file <- expandPath(path, expand)
+ dir <- {
+ def asImage = if (file.endsWith(".jimage")) Some(AbstractFile.getFile(file)) else None
+ Option(AbstractFile.getDirectory(file)).orElse(asImage)
+ }
+ } yield newClassPath(dir)
+
+ private def createSourcePath(file: AbstractFile)(implicit ctx: Context): ClassPath =
+ if (file.isJarOrZip)
+ ZipAndJarSourcePathFactory.create(file)
+ else if (file.isDirectory)
+ new DirectorySourcePath(file.file)
+ else
+ sys.error(s"Unsupported sourcepath element: $file")
+}
+
+object ClassPathFactory {
+ def newClassPath(file: AbstractFile)(implicit ctx: Context): ClassPath = file match {
+ case vd: VirtualDirectory => VirtualDirectoryClassPath(vd)
+ case _ =>
+ if (file.isJarOrZip)
+ ZipAndJarClassPathFactory.create(file)
+ else if (file.isDirectory)
+ new DirectoryClassPath(file.file)
+ else
+ sys.error(s"Unsupported classpath element: $file")
+ }
+}
diff --git a/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala b/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala
new file mode 100644
index 000000000..1ed233ed7
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package dotty.tools.dotc.classpath
+
+import java.io.File
+import java.net.{URI, URL}
+import java.nio.file.{FileSystems, Files, SimpleFileVisitor}
+import java.util.function.IntFunction
+import java.util
+import java.util.Comparator
+
+import scala.reflect.io.{AbstractFile, PlainFile}
+import dotty.tools.io.{ClassPath, ClassRepresentation, PlainNioFile}
+import FileUtils._
+import scala.collection.JavaConverters._
+
+/**
+ * A trait allowing to look for classpath entries in directories. It provides common logic for
+ * classes handling class and source files.
+ * It makes use of the fact that in the case of nested directories it's easy to find a file
+ * when we have a name of a package.
+ * It abstracts over the file representation to work with both JFile and AbstractFile.
+ */
+trait DirectoryLookup[FileEntryType <: ClassRepresentation] extends ClassPath {
+ type F
+
+ val dir: F
+
+ protected def emptyFiles: Array[F] // avoids reifying ClassTag[F]
+ protected def getSubDir(dirName: String): Option[F]
+ protected def listChildren(dir: F, filter: Option[F => Boolean] = None): Array[F]
+ protected def getName(f: F): String
+ protected def toAbstractFile(f: F): AbstractFile
+ protected def isPackage(f: F): Boolean
+
+ protected def createFileEntry(file: AbstractFile): FileEntryType
+ protected def isMatchingFile(f: F): Boolean
+
+ private def getDirectory(forPackage: String): Option[F] = {
+ if (forPackage == ClassPath.RootPackage) {
+ Some(dir)
+ } else {
+ val packageDirName = FileUtils.dirPath(forPackage)
+ getSubDir(packageDirName)
+ }
+ }
+
+ private[dotty] def packages(inPackage: String): Seq[PackageEntry] = {
+ val dirForPackage = getDirectory(inPackage)
+ val nestedDirs: Array[F] = dirForPackage match {
+ case None => emptyFiles
+ case Some(directory) => listChildren(directory, Some(isPackage))
+ }
+ val prefix = PackageNameUtils.packagePrefix(inPackage)
+ nestedDirs.map(f => PackageEntryImpl(prefix + getName(f)))
+ }
+
+ protected def files(inPackage: String): Seq[FileEntryType] = {
+ val dirForPackage = getDirectory(inPackage)
+ val files: Array[F] = dirForPackage match {
+ case None => emptyFiles
+ case Some(directory) => listChildren(directory, Some(isMatchingFile))
+ }
+ files.map(f => createFileEntry(toAbstractFile(f)))
+ }
+
+ private[dotty] def list(inPackage: String): ClassPathEntries = {
+ val dirForPackage = getDirectory(inPackage)
+ val files: Array[F] = dirForPackage match {
+ case None => emptyFiles
+ case Some(directory) => listChildren(directory)
+ }
+ val packagePrefix = PackageNameUtils.packagePrefix(inPackage)
+ val packageBuf = collection.mutable.ArrayBuffer.empty[PackageEntry]
+ val fileBuf = collection.mutable.ArrayBuffer.empty[FileEntryType]
+ for (file <- files) {
+ if (isPackage(file))
+ packageBuf += PackageEntryImpl(packagePrefix + getName(file))
+ else if (isMatchingFile(file))
+ fileBuf += createFileEntry(toAbstractFile(file))
+ }
+ ClassPathEntries(packageBuf, fileBuf)
+ }
+}
+
+trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends DirectoryLookup[FileEntryType] {
+ type F = File
+
+ protected def emptyFiles: Array[File] = Array.empty
+ protected def getSubDir(packageDirName: String): Option[File] = {
+ val packageDir = new File(dir, packageDirName)
+ if (packageDir.exists && packageDir.isDirectory) Some(packageDir)
+ else None
+ }
+ protected def listChildren(dir: File, filter: Option[File => Boolean]): Array[File] = {
+ val listing = filter match {
+ case Some(f) => dir.listFiles(mkFileFilter(f))
+ case None => dir.listFiles()
+ }
+
+ if (listing != null) {
+ // Sort by file name for stable order of directory .class entries in package scope.
+ // This gives stable results ordering of base type sequences for unrelated classes
+ // with the same base type depth.
+ //
+ // Notably, this will stably infer`Product with Serializable`
+ // as the type of `case class C(); case class D(); List(C(), D()).head`, rather than the opposite order.
+ // On Mac, the HFS performs this sorting transparently, but on Linux the order is unspecified.
+ //
+ // Note this behaviour can be enabled in javac with `javac -XDsortfiles`, but that's only
+ // intended to improve determinism of the compiler for compiler hackers.
+ java.util.Arrays.sort(listing,
+ new java.util.Comparator[File] {
+ def compare(o1: File, o2: File) = o1.getName.compareTo(o2.getName)
+ })
+ listing
+ } else Array()
+ }
+ protected def getName(f: File): String = f.getName
+ protected def toAbstractFile(f: File): AbstractFile = new PlainFile(new scala.reflect.io.File(f))
+ protected def isPackage(f: File): Boolean = f.isPackage
+
+ assert(dir != null, "Directory file in DirectoryFileLookup cannot be null")
+
+ def asURLs: Seq[URL] = Seq(dir.toURI.toURL)
+ def asClassPathStrings: Seq[String] = Seq(dir.getPath)
+}
+
+object JrtClassPath {
+ import java.nio.file._, java.net.URI
+ def apply(): Option[ClassPath] = {
+ try {
+ val fs = FileSystems.getFileSystem(URI.create("jrt:/"))
+ Some(new JrtClassPath(fs))
+ } catch {
+ case _: ProviderNotFoundException | _: FileSystemNotFoundException =>
+ None
+ }
+ }
+}
+
+/**
+ * Implementation `ClassPath` based on the JDK 9 encapsulated runtime modules (JEP-220)
+ *
+ * https://bugs.openjdk.java.net/browse/JDK-8066492 is the most up to date reference
+ * for the structure of the jrt:// filesystem.
+ *
+ * The implementation assumes that no classes exist in the empty package.
+ */
+final class JrtClassPath(fs: java.nio.file.FileSystem) extends ClassPath with NoSourcePaths {
+ import java.nio.file.Path, java.nio.file._
+ type F = Path
+ private val dir: Path = fs.getPath("/packages")
+
+ // e.g. "java.lang" -> Seq("/modules/java.base")
+ private val packageToModuleBases: Map[String, Seq[Path]] = {
+ val ps = Files.newDirectoryStream(dir).iterator().asScala
+ def lookup(pack: Path): Seq[Path] = {
+ Files.list(pack).iterator().asScala.map(l => if (Files.isSymbolicLink(l)) Files.readSymbolicLink(l) else l).toList
+ }
+ ps.map(p => (p.toString.stripPrefix("/packages/"), lookup(p))).toMap
+ }
+
+ override private[dotty] def packages(inPackage: String): Seq[PackageEntry] = {
+ def matches(packageDottedName: String) =
+ if (packageDottedName.contains("."))
+ packageOf(packageDottedName) == inPackage
+ else inPackage == ""
+ packageToModuleBases.keysIterator.filter(matches).map(PackageEntryImpl(_)).toVector
+ }
+ private[dotty] def classes(inPackage: String): Seq[ClassFileEntry] = {
+ if (inPackage == "") Nil
+ else {
+ packageToModuleBases.getOrElse(inPackage, Nil).flatMap(x =>
+ Files.list(x.resolve(inPackage.replace('.', '/'))).iterator().asScala.filter(_.getFileName.toString.endsWith(".class"))).map(x =>
+ ClassFileEntryImpl(new PlainNioFile(x))).toVector
+ }
+ }
+
+ override private[dotty] def list(inPackage: String): ClassPathEntries =
+ if (inPackage == "") ClassPathEntries(packages(inPackage), Nil)
+ else ClassPathEntries(packages(inPackage), classes(inPackage))
+
+ def asURLs: Seq[URL] = Seq(dir.toUri.toURL)
+ // We don't yet have a scheme to represent the JDK modules in our `-classpath`.
+ // java models them as entries in the new "module path", we'll probably need to follow this.
+ def asClassPathStrings: Seq[String] = Nil
+
+ def findClassFile(className: String): Option[AbstractFile] = {
+ if (!className.contains(".")) None
+ else {
+ val inPackage = packageOf(className)
+ packageToModuleBases.getOrElse(inPackage, Nil).iterator.flatMap{x =>
+ val file = x.resolve(className.replace('.', '/') + ".class")
+ if (Files.exists(file)) new PlainNioFile(file) :: Nil else Nil
+ }.take(1).toList.headOption
+ }
+ }
+ private def packageOf(dottedClassName: String): String =
+ dottedClassName.substring(0, dottedClassName.lastIndexOf("."))
+}
+
+case class DirectoryClassPath(dir: File) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
+ override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl
+
+ def findClassFile(className: String): Option[AbstractFile] = {
+ val relativePath = FileUtils.dirPath(className)
+ val classFile = new File(s"$dir/$relativePath.class")
+ if (classFile.exists) {
+ val wrappedClassFile = new scala.reflect.io.File(classFile)
+ val abstractClassFile = new PlainFile(wrappedClassFile)
+ Some(abstractClassFile)
+ } else None
+ }
+
+ protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file)
+ protected def isMatchingFile(f: File): Boolean = f.isClass
+
+ private[dotty] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage)
+}
+
+case class DirectorySourcePath(dir: File) extends JFileDirectoryLookup[SourceFileEntryImpl] with NoClassPaths {
+ def asSourcePathString: String = asClassPathString
+
+ protected def createFileEntry(file: AbstractFile): SourceFileEntryImpl = SourceFileEntryImpl(file)
+ protected def isMatchingFile(f: File): Boolean = endsScalaOrJava(f.getName)
+
+ override def findClass(className: String): Option[ClassRepresentation] = findSourceFile(className) map SourceFileEntryImpl
+
+ private def findSourceFile(className: String): Option[AbstractFile] = {
+ val relativePath = FileUtils.dirPath(className)
+ val sourceFile = Stream("scala", "java")
+ .map(ext => new File(s"$dir/$relativePath.$ext"))
+ .collectFirst { case file if file.exists() => file }
+
+ sourceFile.map { file =>
+ val wrappedSourceFile = new scala.reflect.io.File(file)
+ val abstractSourceFile = new PlainFile(wrappedSourceFile)
+ abstractSourceFile
+ }
+ }
+
+ private[dotty] def sources(inPackage: String): Seq[SourceFileEntry] = files(inPackage)
+}
diff --git a/compiler/src/dotty/tools/dotc/classpath/FileUtils.scala b/compiler/src/dotty/tools/dotc/classpath/FileUtils.scala
new file mode 100644
index 000000000..823efbb9d
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/classpath/FileUtils.scala
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package dotty.tools.dotc.classpath
+
+import java.io.{File => JFile, FileFilter}
+import java.net.URL
+import scala.reflect.internal.FatalError
+import scala.reflect.io.AbstractFile
+
+/**
+ * Common methods related to Java files and abstract files used in the context of classpath
+ */
+object FileUtils {
+ implicit class AbstractFileOps(val file: AbstractFile) extends AnyVal {
+ def isPackage: Boolean = file.isDirectory && mayBeValidPackage(file.name)
+
+ def isClass: Boolean = !file.isDirectory && file.hasExtension("class") && !file.name.endsWith("$class.class")
+ // FIXME: drop last condition when we stop being compatible with Scala 2.11
+
+ def isScalaOrJavaSource: Boolean = !file.isDirectory && (file.hasExtension("scala") || file.hasExtension("java"))
+
+ // TODO do we need to check also other files using ZipMagicNumber like in scala.tools.nsc.io.Jar.isJarOrZip?
+ def isJarOrZip: Boolean = file.hasExtension("jar") || file.hasExtension("zip")
+
+ /**
+ * Safe method returning a sequence containing one URL representing this file, when underlying file exists,
+ * and returning given default value in other case
+ */
+ def toURLs(default: => Seq[URL] = Seq.empty): Seq[URL] = if (file.file == null) default else Seq(file.toURL)
+ }
+
+ implicit class FileOps(val file: JFile) extends AnyVal {
+ def isPackage: Boolean = file.isDirectory && mayBeValidPackage(file.getName)
+
+ def isClass: Boolean = file.isFile && file.getName.endsWith(".class") && !file.getName.endsWith("$class.class")
+ // FIXME: drop last condition when we stop being compatible with Scala 2.11
+ }
+
+ def stripSourceExtension(fileName: String): String = {
+ if (endsScala(fileName)) stripClassExtension(fileName)
+ else if (endsJava(fileName)) stripJavaExtension(fileName)
+ else throw new FatalError("Unexpected source file ending: " + fileName)
+ }
+
+ def dirPath(forPackage: String) = forPackage.replace('.', '/')
+
+ def endsClass(fileName: String): Boolean =
+ fileName.length > 6 && fileName.substring(fileName.length - 6) == ".class"
+
+ def endsScalaOrJava(fileName: String): Boolean =
+ endsScala(fileName) || endsJava(fileName)
+
+ def endsJava(fileName: String): Boolean =
+ fileName.length > 5 && fileName.substring(fileName.length - 5) == ".java"
+
+ def endsScala(fileName: String): Boolean =
+ fileName.length > 6 && fileName.substring(fileName.length - 6) == ".scala"
+
+ def stripClassExtension(fileName: String): String =
+ fileName.substring(0, fileName.length - 6) // equivalent of fileName.length - ".class".length
+
+ def stripJavaExtension(fileName: String): String =
+ fileName.substring(0, fileName.length - 5)
+
+ // probably it should match a pattern like [a-z_]{1}[a-z0-9_]* but it cannot be changed
+ // because then some tests in partest don't pass
+ def mayBeValidPackage(dirName: String): Boolean =
+ (dirName != "META-INF") && (dirName != "") && (dirName.charAt(0) != '.')
+
+ def mkFileFilter(f: JFile => Boolean) = new FileFilter {
+ def accept(pathname: JFile): Boolean = f(pathname)
+ }
+}
diff --git a/compiler/src/dotty/tools/dotc/classpath/PackageNameUtils.scala b/compiler/src/dotty/tools/dotc/classpath/PackageNameUtils.scala
new file mode 100644
index 000000000..303f142b9
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/classpath/PackageNameUtils.scala
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package dotty.tools.dotc.classpath
+
+import dotty.tools.io.ClassPath.RootPackage
+
+/**
+ * Common methods related to package names represented as String
+ */
+object PackageNameUtils {
+
+ /**
+ * @param fullClassName full class name with package
+ * @return (package, simple class name)
+ */
+ def separatePkgAndClassNames(fullClassName: String): (String, String) = {
+ val lastDotIndex = fullClassName.lastIndexOf('.')
+ if (lastDotIndex == -1)
+ (RootPackage, fullClassName)
+ else
+ (fullClassName.substring(0, lastDotIndex), fullClassName.substring(lastDotIndex + 1))
+ }
+
+ def packagePrefix(inPackage: String): String = if (inPackage == RootPackage) "" else inPackage + "."
+}
diff --git a/compiler/src/dotty/tools/dotc/classpath/VirtualDirectoryClassPath.scala b/compiler/src/dotty/tools/dotc/classpath/VirtualDirectoryClassPath.scala
new file mode 100644
index 000000000..5b0855554
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/classpath/VirtualDirectoryClassPath.scala
@@ -0,0 +1,52 @@
+package dotty.tools.dotc.classpath
+
+import dotty.tools.io.ClassRepresentation
+import scala.reflect.io.{AbstractFile, Path, PlainFile, VirtualDirectory}
+import FileUtils._
+import java.net.URL
+
+import scala.reflect.internal.util.AbstractFileClassLoader
+import dotty.tools.io.ClassPath
+
+case class VirtualDirectoryClassPath(dir: VirtualDirectory) extends ClassPath with DirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
+ type F = AbstractFile
+
+ // From AbstractFileClassLoader
+ private final def lookupPath(base: AbstractFile)(pathParts: Seq[String], directory: Boolean): AbstractFile = {
+ var file: AbstractFile = base
+ for (dirPart <- pathParts.init) {
+ file = file.lookupName(dirPart, directory = true)
+ if (file == null)
+ return null
+ }
+
+ file.lookupName(pathParts.last, directory = directory)
+ }
+
+ protected def emptyFiles: Array[AbstractFile] = Array.empty
+ protected def getSubDir(packageDirName: String): Option[AbstractFile] =
+ Option(lookupPath(dir)(packageDirName.split('/'), directory = true))
+ protected def listChildren(dir: AbstractFile, filter: Option[AbstractFile => Boolean] = None): Array[F] = filter match {
+ case Some(f) => dir.iterator.filter(f).toArray
+ case _ => dir.toArray
+ }
+ def getName(f: AbstractFile): String = f.name
+ def toAbstractFile(f: AbstractFile): AbstractFile = f
+ def isPackage(f: AbstractFile): Boolean = f.isPackage
+
+ // mimic the behavior of the old nsc.util.DirectoryClassPath
+ def asURLs: Seq[URL] = Seq(new URL(dir.name))
+ def asClassPathStrings: Seq[String] = Seq(dir.path)
+
+ override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl
+
+ def findClassFile(className: String): Option[AbstractFile] = {
+ val relativePath = FileUtils.dirPath(className) + ".class"
+ Option(lookupPath(dir)(relativePath split '/', directory = false))
+ }
+
+ private[dotty] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage)
+
+ protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file)
+ protected def isMatchingFile(f: AbstractFile): Boolean = f.isClass
+}
diff --git a/compiler/src/dotty/tools/dotc/classpath/ZipAndJarFileLookupFactory.scala b/compiler/src/dotty/tools/dotc/classpath/ZipAndJarFileLookupFactory.scala
new file mode 100644
index 000000000..5210c699e
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/classpath/ZipAndJarFileLookupFactory.scala
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package dotty.tools.dotc.classpath
+
+import java.io.File
+import java.net.URL
+import scala.annotation.tailrec
+import scala.reflect.io.{AbstractFile, FileZipArchive, ManifestResources}
+import dotty.tools.io.ClassPath
+import dotty.tools.dotc.config.Settings
+import dotty.tools.dotc.core.Contexts.Context
+import FileUtils._
+
+/**
+ * A trait providing an optional cache for classpath entries obtained from zip and jar files.
+ * It's possible to create such a cache assuming that entries in such files won't change (at
+ * least will be the same each time we'll load classpath during the lifetime of JVM process)
+ * - unlike class and source files in directories, which can be modified and recompiled.
+ * It allows us to e.g. reduce significantly memory used by PresentationCompilers in Scala IDE
+ * when there are a lot of projects having a lot of common dependencies.
+ */
+sealed trait ZipAndJarFileLookupFactory {
+ private val cache = collection.mutable.Map.empty[AbstractFile, ClassPath]
+
+ def create(zipFile: AbstractFile)(implicit ctx: Context): ClassPath = {
+ if (ctx.settings.YdisableFlatCpCaching.value) createForZipFile(zipFile)
+ else createUsingCache(zipFile)
+ }
+
+ protected def createForZipFile(zipFile: AbstractFile): ClassPath
+
+ private def createUsingCache(zipFile: AbstractFile)(implicit ctx: Context): ClassPath = cache.synchronized {
+ def newClassPathInstance = {
+ if (ctx.settings.verbose.value || ctx.settings.Ylogcp.value)
+ println(s"$zipFile is not yet in the classpath cache")
+ createForZipFile(zipFile)
+ }
+ cache.getOrElseUpdate(zipFile, newClassPathInstance)
+ }
+}
+
+/**
+ * Manages creation of classpath for class files placed in zip and jar files.
+ * It should be the only way of creating them as it provides caching.
+ */
+object ZipAndJarClassPathFactory extends ZipAndJarFileLookupFactory {
+ private case class ZipArchiveClassPath(zipFile: File)
+ extends ZipArchiveFileLookup[ClassFileEntryImpl]
+ with NoSourcePaths {
+
+ override def findClassFile(className: String): Option[AbstractFile] = {
+ val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className)
+ classes(pkg).find(_.name == simpleClassName).map(_.file)
+ }
+
+ override private[dotty] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage)
+
+ override protected def createFileEntry(file: FileZipArchive#Entry): ClassFileEntryImpl = ClassFileEntryImpl(file)
+ override protected def isRequiredFileType(file: AbstractFile): Boolean = file.isClass
+ }
+
+ /**
+ * This type of classpath is closely related to the support for JSR-223.
+ * Its usage can be observed e.g. when running:
+ * jrunscript -classpath scala-compiler.jar;scala-reflect.jar;scala-library.jar -l scala
+ * with a particularly prepared scala-library.jar. It should have all classes listed in the manifest like e.g. this entry:
+ * Name: scala/Function2$mcFJD$sp.class
+ */
+ private case class ManifestResourcesClassPath(file: ManifestResources) extends ClassPath with NoSourcePaths {
+ override def findClassFile(className: String): Option[AbstractFile] = {
+ val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className)
+ classes(pkg).find(_.name == simpleClassName).map(_.file)
+ }
+
+ override def asClassPathStrings: Seq[String] = Seq(file.path)
+
+ override def asURLs: Seq[URL] = file.toURLs()
+
+ import ManifestResourcesClassPath.PackageFileInfo
+ import ManifestResourcesClassPath.PackageInfo
+
+ /**
+ * A cache mapping package name to abstract file for package directory and subpackages of given package.
+ *
+ * ManifestResources can iterate through the collections of entries from e.g. remote jar file.
+ * We can't just specify the path to the concrete directory etc. so we can't just 'jump' into
+ * given package, when it's needed. On the other hand we can iterate over entries to get
+ * AbstractFiles, iterate over entries of these files etc.
+ *
+ * Instead of traversing a tree of AbstractFiles once and caching all entries or traversing each time,
+ * when we need subpackages of a given package or its classes, we traverse once and cache only packages.
+ * Classes for given package can be then easily loaded when they are needed.
+ */
+ private lazy val cachedPackages: collection.mutable.HashMap[String, PackageFileInfo] = {
+ val packages = collection.mutable.HashMap[String, PackageFileInfo]()
+
+ def getSubpackages(dir: AbstractFile): List[AbstractFile] =
+ (for (file <- dir if file.isPackage) yield file)(collection.breakOut)
+
+ @tailrec
+ def traverse(packagePrefix: String,
+ filesForPrefix: List[AbstractFile],
+ subpackagesQueue: collection.mutable.Queue[PackageInfo]): Unit = filesForPrefix match {
+ case pkgFile :: remainingFiles =>
+ val subpackages = getSubpackages(pkgFile)
+ val fullPkgName = packagePrefix + pkgFile.name
+ packages.put(fullPkgName, PackageFileInfo(pkgFile, subpackages))
+ val newPackagePrefix = fullPkgName + "."
+ subpackagesQueue.enqueue(PackageInfo(newPackagePrefix, subpackages))
+ traverse(packagePrefix, remainingFiles, subpackagesQueue)
+ case Nil if subpackagesQueue.nonEmpty =>
+ val PackageInfo(packagePrefix, filesForPrefix) = subpackagesQueue.dequeue()
+ traverse(packagePrefix, filesForPrefix, subpackagesQueue)
+ case _ =>
+ }
+
+ val subpackages = getSubpackages(file)
+ packages.put(ClassPath.RootPackage, PackageFileInfo(file, subpackages))
+ traverse(ClassPath.RootPackage, subpackages, collection.mutable.Queue())
+ packages
+ }
+
+ override private[dotty] def packages(inPackage: String): Seq[PackageEntry] = cachedPackages.get(inPackage) match {
+ case None => Seq.empty
+ case Some(PackageFileInfo(_, subpackages)) =>
+ val prefix = PackageNameUtils.packagePrefix(inPackage)
+ subpackages.map(packageFile => PackageEntryImpl(prefix + packageFile.name))
+ }
+
+ override private[dotty] def classes(inPackage: String): Seq[ClassFileEntry] = cachedPackages.get(inPackage) match {
+ case None => Seq.empty
+ case Some(PackageFileInfo(pkg, _)) =>
+ (for (file <- pkg if file.isClass) yield ClassFileEntryImpl(file))(collection.breakOut)
+ }
+
+ override private[dotty] def list(inPackage: String): ClassPathEntries = ClassPathEntries(packages(inPackage), classes(inPackage))
+ }
+
+ private object ManifestResourcesClassPath {
+ case class PackageFileInfo(packageFile: AbstractFile, subpackages: Seq[AbstractFile])
+ case class PackageInfo(packageName: String, subpackages: List[AbstractFile])
+ }
+
+ override protected def createForZipFile(zipFile: AbstractFile): ClassPath =
+ if (zipFile.file == null) createWithoutUnderlyingFile(zipFile)
+ else ZipArchiveClassPath(zipFile.file)
+
+ private def createWithoutUnderlyingFile(zipFile: AbstractFile) = zipFile match {
+ case manifestRes: ManifestResources =>
+ ManifestResourcesClassPath(manifestRes)
+ case _ =>
+ val errorMsg = s"Abstract files which don't have an underlying file and are not ManifestResources are not supported. There was $zipFile"
+ throw new IllegalArgumentException(errorMsg)
+ }
+}
+
+/**
+ * Manages creation of classpath for source files placed in zip and jar files.
+ * It should be the only way of creating them as it provides caching.
+ */
+object ZipAndJarSourcePathFactory extends ZipAndJarFileLookupFactory {
+ private case class ZipArchiveSourcePath(zipFile: File)
+ extends ZipArchiveFileLookup[SourceFileEntryImpl]
+ with NoClassPaths {
+
+ override def asSourcePathString: String = asClassPathString
+
+ override private[dotty] def sources(inPackage: String): Seq[SourceFileEntry] = files(inPackage)
+
+ override protected def createFileEntry(file: FileZipArchive#Entry): SourceFileEntryImpl = SourceFileEntryImpl(file)
+ override protected def isRequiredFileType(file: AbstractFile): Boolean = file.isScalaOrJavaSource
+ }
+
+ override protected def createForZipFile(zipFile: AbstractFile): ClassPath = ZipArchiveSourcePath(zipFile.file)
+}
diff --git a/compiler/src/dotty/tools/dotc/classpath/ZipArchiveFileLookup.scala b/compiler/src/dotty/tools/dotc/classpath/ZipArchiveFileLookup.scala
new file mode 100644
index 000000000..8184708ad
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/classpath/ZipArchiveFileLookup.scala
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package dotty.tools.dotc.classpath
+
+import java.io.File
+import java.net.URL
+import scala.collection.Seq
+import scala.reflect.io.AbstractFile
+import scala.reflect.io.FileZipArchive
+import FileUtils.AbstractFileOps
+import dotty.tools.io.{ClassPath, ClassRepresentation}
+
+/**
+ * A trait allowing to look for classpath entries of given type in zip and jar files.
+ * It provides common logic for classes handling class and source files.
+ * It's aware of things like e.g. META-INF directory which is correctly skipped.
+ */
+trait ZipArchiveFileLookup[FileEntryType <: ClassRepresentation] extends ClassPath {
+ val zipFile: File
+
+ assert(zipFile != null, "Zip file in ZipArchiveFileLookup cannot be null")
+
+ override def asURLs: Seq[URL] = Seq(zipFile.toURI.toURL)
+ override def asClassPathStrings: Seq[String] = Seq(zipFile.getPath)
+
+ private val archive = new FileZipArchive(zipFile)
+
+ override private[dotty] def packages(inPackage: String): Seq[PackageEntry] = {
+ val prefix = PackageNameUtils.packagePrefix(inPackage)
+ for {
+ dirEntry <- findDirEntry(inPackage).toSeq
+ entry <- dirEntry.iterator if entry.isPackage
+ } yield PackageEntryImpl(prefix + entry.name)
+ }
+
+ protected def files(inPackage: String): Seq[FileEntryType] =
+ for {
+ dirEntry <- findDirEntry(inPackage).toSeq
+ entry <- dirEntry.iterator if isRequiredFileType(entry)
+ } yield createFileEntry(entry)
+
+ override private[dotty] def list(inPackage: String): ClassPathEntries = {
+ val foundDirEntry = findDirEntry(inPackage)
+
+ foundDirEntry map { dirEntry =>
+ val pkgBuf = collection.mutable.ArrayBuffer.empty[PackageEntry]
+ val fileBuf = collection.mutable.ArrayBuffer.empty[FileEntryType]
+ val prefix = PackageNameUtils.packagePrefix(inPackage)
+
+ for (entry <- dirEntry.iterator) {
+ if (entry.isPackage)
+ pkgBuf += PackageEntryImpl(prefix + entry.name)
+ else if (isRequiredFileType(entry))
+ fileBuf += createFileEntry(entry)
+ }
+ ClassPathEntries(pkgBuf, fileBuf)
+ } getOrElse ClassPathEntries(Seq.empty, Seq.empty)
+ }
+
+ private def findDirEntry(pkg: String): Option[archive.DirEntry] = {
+ val dirName = s"${FileUtils.dirPath(pkg)}/"
+ archive.allDirs.get(dirName)
+ }
+
+ protected def createFileEntry(file: FileZipArchive#Entry): FileEntryType
+ protected def isRequiredFileType(file: AbstractFile): Boolean
+}
diff --git a/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala b/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala
index 8bc18c387..d2a8e18a2 100644
--- a/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala
+++ b/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala
@@ -2,8 +2,8 @@ package dotty.tools
package dotc
package config
-import io.{AbstractFile,ClassPath,JavaClassPath,MergedClassPath,DeltaClassPath}
-import ClassPath.{ JavaContext, DefaultJavaContext }
+import io._
+import classpath.AggregateClassPath
import core._
import Symbols._, Types._, Contexts._, Denotations._, SymDenotations._, StdNames._, Names._
import Flags._, Scopes._, Decorators._, NameOps._, util.Positions._
@@ -11,7 +11,7 @@ import transform.ExplicitOuter, transform.SymUtils._
class JavaPlatform extends Platform {
- private var currentClassPath: Option[MergedClassPath] = None
+ private var currentClassPath: Option[ClassPath] = None
def classPath(implicit ctx: Context): ClassPath = {
if (currentClassPath.isEmpty)
@@ -35,8 +35,12 @@ class JavaPlatform extends Platform {
}
/** Update classpath with a substituted subentry */
- def updateClassPath(subst: Map[ClassPath, ClassPath]) =
- currentClassPath = Some(new DeltaClassPath(currentClassPath.get, subst))
+ def updateClassPath(subst: Map[ClassPath, ClassPath]): Unit = currentClassPath.get match {
+ case AggregateClassPath(entries) =>
+ currentClassPath = Some(AggregateClassPath(entries map (e => subst.getOrElse(e, e))))
+ case cp: ClassPath =>
+ currentClassPath = Some(subst.getOrElse(cp, cp))
+ }
def rootLoader(root: TermSymbol)(implicit ctx: Context): SymbolLoader = new ctx.base.loaders.PackageLoader(root, classPath)
diff --git a/compiler/src/dotty/tools/dotc/config/PathResolver.scala b/compiler/src/dotty/tools/dotc/config/PathResolver.scala
index 159989e6f..f0709f4d3 100644
--- a/compiler/src/dotty/tools/dotc/config/PathResolver.scala
+++ b/compiler/src/dotty/tools/dotc/config/PathResolver.scala
@@ -4,8 +4,9 @@ package config
import java.net.{ URL, MalformedURLException }
import WrappedProperties.AccessControl
-import io.{ ClassPath, JavaClassPath, File, Directory, Path, AbstractFile }
-import ClassPath.{ JavaContext, DefaultJavaContext, join, split }
+import io.{ ClassPath, File, Directory, Path, AbstractFile }
+import classpath.{AggregateClassPath, ClassPathFactory }
+import ClassPath.{ JavaContext, join, split }
import PartialFunction.condOpt
import scala.language.postfixOps
import core.Contexts._
@@ -128,7 +129,7 @@ object PathResolver {
)
}
- def fromPathString(path: String)(implicit ctx: Context): JavaClassPath = {
+ def fromPathString(path: String)(implicit ctx: Context): ClassPath = {
val settings = ctx.settings.classpath.update(path)
new PathResolver()(ctx.fresh.setSettings(settings)).result
}
@@ -150,7 +151,11 @@ object PathResolver {
val pr = new PathResolver()(ctx.fresh.setSettings(sstate))
println(" COMMAND: 'scala %s'".format(args.mkString(" ")))
println("RESIDUAL: 'scala %s'\n".format(rest.mkString(" ")))
- pr.result.show
+
+ pr.result match {
+ case cp: AggregateClassPath =>
+ println(s"ClassPath has ${cp.aggregates.size} entries and results in:\n${cp.asClassPathStrings}")
+ }
}
}
}
@@ -159,7 +164,7 @@ import PathResolver.{ Defaults, Environment, firstNonEmpty, ppcp }
class PathResolver(implicit ctx: Context) {
import ctx.base.settings
- val context = ClassPath.DefaultJavaContext
+ private val classPathFactory = new ClassPathFactory
private def cmdLineOrElse(name: String, alt: String) = {
(commandLineFor(name) match {
@@ -214,7 +219,7 @@ class PathResolver(implicit ctx: Context) {
else sys.env.getOrElse("CLASSPATH", ".")
}
- import context._
+ import classPathFactory._
// Assemble the elements!
// priority class path takes precedence
@@ -254,8 +259,8 @@ class PathResolver(implicit ctx: Context) {
def containers = Calculated.containers
- lazy val result: JavaClassPath = {
- val cp = new JavaClassPath(containers.toIndexedSeq, context)
+ lazy val result: ClassPath = {
+ val cp = AggregateClassPath(containers.toIndexedSeq)
if (settings.Ylogcp.value) {
Console.println("Classpath built from " + settings.toConciseString(ctx.sstate))
diff --git a/compiler/src/dotty/tools/dotc/config/Printers.scala b/compiler/src/dotty/tools/dotc/config/Printers.scala
index 002d0f933..a77607d18 100644
--- a/compiler/src/dotty/tools/dotc/config/Printers.scala
+++ b/compiler/src/dotty/tools/dotc/config/Printers.scala
@@ -31,4 +31,5 @@ object Printers {
val cyclicErrors: Printer = noPrinter
val pickling: Printer = noPrinter
val inlining: Printer = noPrinter
+ val exhaustivity: Printer = noPrinter
}
diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
index 49b64d869..941434dd5 100644
--- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
+++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
@@ -65,14 +65,16 @@ 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")
val emitTasty = BooleanSetting("-YemitTasty", "Generate tasty in separate *.tasty file.")
val Ylogcp = BooleanSetting("-Ylog-classpath", "Output information about what classpath is being applied.")
+ val YdisableFlatCpCaching = BooleanSetting("-YdisableFlatCpCaching", "Do not cache flat classpath representation of classpath elements from jars across compiler instances.")
+
val YnoImports = BooleanSetting("-Yno-imports", "Compile without importing scala.*, java.lang.*, or Predef.")
val YnoPredef = BooleanSetting("-Yno-predef", "Compile without importing Predef.")
val Yskip = PhasesSetting("-Yskip", "Skip")
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..a97589d73 100644
--- a/compiler/src/dotty/tools/dotc/core/Definitions.scala
+++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala
@@ -10,6 +10,7 @@ import scala.collection.{ mutable, immutable }
import PartialFunction._
import collection.mutable
import util.common.alwaysZero
+import typer.Applications
object Definitions {
@@ -67,7 +68,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 +109,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 +120,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))
@@ -477,6 +478,7 @@ class Definitions {
lazy val JavaCloneableClass = ctx.requiredClass("java.lang.Cloneable")
lazy val NullPointerExceptionClass = ctx.requiredClass("java.lang.NullPointerException")
+ lazy val IndexOutOfBoundsException = ctx.requiredClass("java.lang.IndexOutOfBoundsException")
lazy val ClassClass = ctx.requiredClass("java.lang.Class")
lazy val BoxedNumberClass = ctx.requiredClass("java.lang.Number")
lazy val ThrowableClass = ctx.requiredClass("java.lang.Throwable")
@@ -723,12 +725,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 +759,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
@@ -845,18 +846,7 @@ class Definitions {
TupleType(elems.size).appliedTo(elems)
}
- def isProductSubType(tp: Type)(implicit ctx: Context) =
- (tp derivesFrom ProductType.symbol) && tp.baseClasses.exists(isProductClass)
-
- def productArity(tp: Type)(implicit ctx: Context) =
- if (tp derivesFrom ProductType.symbol)
- tp.baseClasses.find(isProductClass) match {
- case Some(prod) => prod.typeParams.length
- case None => -1
- }
- else -1
-
- /** Is `tp` (an alias) of either a scala.FunctionN or a scala.ImplicitFunctionN ? */
+ /** Is `tp` (an alias) of either a scala.FunctionN or a scala.ImplicitFunctionN? */
def isFunctionType(tp: Type)(implicit ctx: Context) = {
val arity = functionArity(tp)
val sym = tp.dealias.typeSymbol
@@ -933,23 +923,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 +950,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 602848a50..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]
@@ -1493,6 +1503,9 @@ object SymDenotations {
myMemberCache
}
+ /** Hook to do a pre-enter test. Overridden in PackageDenotation */
+ protected def proceedWithEnter(sym: Symbol, mscope: MutableScope)(implicit ctx: Context): Boolean = true
+
/** Enter a symbol in current scope, and future scopes of same denotation.
* Note: We require that this does not happen after the first time
* someone does a findMember on a subclass.
@@ -1510,19 +1523,13 @@ object SymDenotations {
scope
case _ => unforcedDecls.openForMutations
}
- if (this is PackageClass) {
- val entry = mscope.lookupEntry(sym.name)
- if (entry != null) {
- if (entry.sym == sym) return
- mscope.unlink(entry)
- entry.sym.denot = sym.denot // to avoid stale symbols
+ if (proceedWithEnter(sym, mscope)) {
+ enterNoReplace(sym, mscope)
+ val nxt = this.nextInRun
+ if (nxt.validFor.code > this.validFor.code) {
+ this.nextInRun.asSymDenotation.asClass.enter(sym)
}
}
- enterNoReplace(sym, mscope)
- val nxt = this.nextInRun
- if (nxt.validFor.code > this.validFor.code) {
- this.nextInRun.asSymDenotation.asClass.enter(sym)
- }
}
/** Enter a symbol in given `scope` without potentially replacing the old copy. */
@@ -1533,8 +1540,8 @@ object SymDenotations {
!(this is Frozen) ||
(scope ne this.unforcedDecls) ||
sym.hasAnnotation(defn.ScalaStaticAnnot) ||
- sym.name.isInlineAccessor ||
- isUsecase)
+ sym.name.is(InlineAccessorName) ||
+ isUsecase, i"trying to enter $sym in $this, frozen = ${this is Frozen}")
scope.enter(sym)
@@ -1755,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
}
}
@@ -1773,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,
@@ -1800,7 +1807,7 @@ object SymDenotations {
/** The denotation of a package class.
* It overrides ClassDenotation to take account of package objects when looking for members
*/
- class PackageClassDenotation private[SymDenotations] (
+ final class PackageClassDenotation private[SymDenotations] (
symbol: Symbol,
ownerIfExists: Symbol,
name: Name,
@@ -1823,15 +1830,33 @@ object SymDenotations {
packageObjCache
}
- /** Look first for members in package; if none are found look in package object */
- override def computeNPMembersNamed(name: Name, inherited: Boolean)(implicit ctx: Context): PreDenotation = {
- val denots = super.computeNPMembersNamed(name, inherited)
- if (denots.exists) denots
- else packageObj.moduleClass.denot match {
- case pcls: ClassDenotation => pcls.computeNPMembersNamed(name, inherited)
- case _ => denots
+ /** Looks in both the package object and the package for members. The precise algorithm
+ * is as follows:
+ *
+ * If this is the scala package look in the package first, and if nothing is found
+ * there, look in the package object second. Otherwise, look in the package object
+ * first, and if nothing is found there, in the package second.
+ *
+ * The reason for the special treatment of the scala package is that if we
+ * complete it too early, we freeze its superclass Any, so that no members can
+ * be entered in it. As a consequence, there should be no entry in the scala package
+ * object that hides a class or object in the scala package of the same name, because
+ * the behavior would then be unintuitive for such members.
+ */
+ override def computeNPMembersNamed(name: Name, inherited: Boolean)(implicit ctx: Context): PreDenotation =
+ packageObj.moduleClass.denot match {
+ case pcls: ClassDenotation if !pcls.isCompleting =>
+ if (symbol eq defn.ScalaPackageClass) {
+ val denots = super.computeNPMembersNamed(name, inherited)
+ if (denots.exists) denots else pcls.computeNPMembersNamed(name, inherited)
+ }
+ else {
+ val denots = pcls.computeNPMembersNamed(name, inherited)
+ if (denots.exists) denots else super.computeNPMembersNamed(name, inherited)
+ }
+ case _ =>
+ super.computeNPMembersNamed(name, inherited)
}
- }
/** The union of the member names of the package and the package object */
override def memberNames(keepOnly: NameFilter)(implicit ctx: Context): Set[Name] = {
@@ -1841,6 +1866,21 @@ object SymDenotations {
case _ => ownNames
}
}
+
+ /** If another symbol with the same name is entered, unlink it,
+ * and, if symbol is a package object, invalidate the packageObj cache.
+ * @return `sym` is not already entered
+ */
+ override def proceedWithEnter(sym: Symbol, mscope: MutableScope)(implicit ctx: Context): Boolean = {
+ val entry = mscope.lookupEntry(sym.name)
+ if (entry != null) {
+ if (entry.sym == sym) return false
+ mscope.unlink(entry)
+ entry.sym.denot = sym.denot // to avoid stale symbols
+ if (sym.name == nme.PACKAGE) packageObjRunId = NoRunId
+ }
+ true
+ }
}
class NoDenotation extends SymDenotation(
diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala
index 79f8a6a45..63c2817a6 100644
--- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala
+++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala
@@ -9,11 +9,13 @@ package core
import java.io.IOException
import scala.compat.Platform.currentTime
-import dotty.tools.io.{ ClassPath, AbstractFile }
+import dotty.tools.io.{ ClassPath, ClassRepresentation, AbstractFile }
+import classpath._
import Contexts._, Symbols._, Flags._, SymDenotations._, Types._, Scopes._, util.Positions._, Names._
import StdNames._, NameOps._
import Decorators.{PreNamedString, StringInterpolators}
import classfile.ClassfileParser
+import util.Stats
import scala.util.control.NonFatal
object SymbolLoaders {
@@ -59,8 +61,7 @@ class SymbolLoaders {
/** Enter package with given `name` into scope of `owner`
* and give them `completer` as type.
*/
- def enterPackage(owner: Symbol, pkg: ClassPath)(implicit ctx: Context): Symbol = {
- val pname = pkg.name.toTermName
+ def enterPackage(owner: Symbol, pname: TermName, completer: (TermSymbol, ClassSymbol) => PackageLoader)(implicit ctx: Context): Symbol = {
val preExisting = owner.info.decls lookup pname
if (preExisting != NoSymbol) {
// Some jars (often, obfuscated ones) include a package and
@@ -83,7 +84,7 @@ class SymbolLoaders {
}
}
ctx.newModuleSymbol(owner, pname, PackageCreationFlags, PackageCreationFlags,
- (module, modcls) => new PackageLoader(module, pkg)).entered
+ completer).entered
}
/** Enter class and module with given `name` into scope of `owner`
@@ -125,7 +126,7 @@ class SymbolLoaders {
/** Initialize toplevel class and module symbols in `owner` from class path representation `classRep`
*/
- def initializeFromClassPath(owner: Symbol, classRep: ClassPath#ClassRep)(implicit ctx: Context): Unit = {
+ def initializeFromClassPath(owner: Symbol, classRep: ClassRepresentation)(implicit ctx: Context): Unit = {
((classRep.binary, classRep.source): @unchecked) match {
case (Some(bin), Some(src)) if needCompile(bin, src) && !binaryOnly(owner, classRep.name) =>
if (ctx.settings.verbose.value) ctx.inform("[symloader] picked up newer source file for " + src.path)
@@ -143,31 +144,99 @@ class SymbolLoaders {
/** Load contents of a package
*/
- class PackageLoader(_sourceModule: TermSymbol, classpath: ClassPath)
+ class PackageLoader(_sourceModule: TermSymbol, classPath: ClassPath)
extends SymbolLoader {
override def sourceModule(implicit ctx: Context) = _sourceModule
- def description = "package loader " + classpath.name
+ def description(implicit ctx: Context) = "package loader " + sourceModule.fullName
- 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: ClassRepresentation) = {
+ val idx = classRep.name.indexOf('$')
+ idx >= 0 && idx < classRep.name.length - 1
+ }
+
+ def maybeModuleClass(classRep: ClassRepresentation) = classRep.name.last == '$'
+
+ private def enterClasses(root: SymDenotation, packageName: String, flat: Boolean)(implicit ctx: Context) = {
+ def isAbsent(classRep: ClassRepresentation) =
+ !root.unforcedDecls.lookup(classRep.name.toTypeName).exists
+
+ if (!root.isRoot) {
+ val classReps = classPath.classes(packageName)
+
+ for (classRep <- classReps)
+ 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 <- classReps)
+ 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)
+
+ val packageName = if (root.isEffectiveRoot) "" else root.fullName.toString
+
+ enterFlatClasses = Some { ctx =>
+ enterFlatClasses = None
+ enterClasses(root, packageName, flat = true)(ctx)
}
+ enterClasses(root, packageName, flat = false)
if (!root.isEmptyPackage)
- for (pkg <- classpath.packages)
- enterPackage(root.symbol, pkg)
+ for (pkg <- classPath.packages(packageName)) {
+ val fullName = pkg.name
+ val name =
+ if (packageName.isEmpty) fullName
+ else fullName.substring(packageName.length + 1)
+
+ enterPackage(root.symbol, name.toTermName,
+ (module, modcls) => new PackageLoader(module, classPath))
+ }
}
}
}
@@ -185,7 +254,7 @@ abstract class SymbolLoader extends LazyType {
/** Description of the resource (ClassPath, AbstractFile)
* being processed by this loader
*/
- def description: String
+ def description(implicit ctx: Context): String
override def complete(root: SymDenotation)(implicit ctx: Context): Unit = {
def signalError(ex: Exception): Unit = {
@@ -226,7 +295,7 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader {
override def sourceFileOrNull: AbstractFile = classfile
- def description = "class file " + classfile.toString
+ def description(implicit ctx: Context) = "class file " + classfile.toString
def rootDenots(rootDenot: ClassDenotation)(implicit ctx: Context): (ClassDenotation, ClassDenotation) = {
val linkedDenot = rootDenot.scalacLinkedClass.denot match {
@@ -261,7 +330,7 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader {
}
class SourcefileLoader(val srcfile: AbstractFile) extends SymbolLoader {
- def description = "source file " + srcfile.toString
+ def description(implicit ctx: Context) = "source file " + srcfile.toString
override def sourceFileOrNull = srcfile
def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = unsupported("doComplete")
}
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..b37ed2b0a 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
@@ -428,7 +429,7 @@ class TypeApplications(val self: Type) extends AnyVal {
case dealiased: LazyRef =>
LazyRef(() => dealiased.ref.appliedTo(args))
case dealiased: WildcardType =>
- dealiased
+ WildcardType(dealiased.optBounds.appliedTo(args).bounds)
case dealiased: TypeRef if dealiased.symbol == defn.NothingClass =>
dealiased
case _ if typParams.isEmpty || typParams.head.isInstanceOf[LambdaParam] =>
@@ -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/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
index da6d63387..54b96a253 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -726,10 +726,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
tycon2 match {
case param2: TypeParamRef =>
- isMatchingApply(tp1) || {
- if (canConstrain(param2)) canInstantiate(param2)
- else compareLower(bounds(param2), tyconIsTypeRef = false)
- }
+ isMatchingApply(tp1) ||
+ canConstrain(param2) && canInstantiate(param2) ||
+ compareLower(bounds(param2), tyconIsTypeRef = false)
case tycon2: TypeRef =>
isMatchingApply(tp1) ||
compareLower(tycon2.info.bounds, tyconIsTypeRef = true)
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index 8ae3aa7ad..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._
@@ -107,10 +108,11 @@ object Types {
final def isValueTypeOrLambda: Boolean = isValueType || this.isInstanceOf[TypeLambda]
/** Does this type denote a stable reference (i.e. singleton type)? */
- @tailrec final def isStable(implicit ctx: Context): Boolean = stripTypeVar match {
- case tp: TermRef => tp.termSymbol.isStable && tp.prefix.isStable
+ final def isStable(implicit ctx: Context): Boolean = stripTypeVar match {
+ case tp: TermRef => tp.termSymbol.isStable && tp.prefix.isStable || tp.info.isStable
case _: SingletonType | NoPrefix => true
case tp: RefinedOrRecType => tp.parent.isStable
+ case tp: ExprType => tp.resultType.isStable
case _ => false
}
@@ -1504,20 +1506,29 @@ object Types {
case _ => NoType
}
assert(
- (lastSymbol eq sym) ||
- (lastSymbol eq null) || {
+ (lastSymbol eq sym)
+ ||
+ (lastSymbol eq null)
+ || {
val lastDefRunId = lastDenotation match {
case d: SymDenotation => d.validFor.runId
case _ => lastSymbol.defRunId
}
(lastDefRunId != sym.defRunId) ||
(lastDefRunId == NoRunId)
- } ||
- (lastSymbol.infoOrCompleter.isInstanceOf[ErrorType] ||
+ }
+ ||
+ lastSymbol.infoOrCompleter.isInstanceOf[ErrorType]
+ ||
+ sym.isPackageObject // package objects can be visited before we get around to index them
+ ||
sym.owner != lastSymbol.owner &&
- (sym.owner.derivesFrom(lastSymbol.owner) ||
- selfTypeOf(sym).derivesFrom(lastSymbol.owner) ||
- selfTypeOf(lastSymbol).derivesFrom(sym.owner))),
+ (sym.owner.derivesFrom(lastSymbol.owner)
+ ||
+ selfTypeOf(sym).derivesFrom(lastSymbol.owner)
+ ||
+ selfTypeOf(lastSymbol).derivesFrom(sym.owner)
+ ),
i"""data race? overwriting symbol of type $this,
|long form = $toString of class $getClass,
|last sym id = ${lastSymbol.id}, new sym id = ${sym.id},
@@ -1584,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)
@@ -1720,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 =>
@@ -1794,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 =>
@@ -2990,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..26c823f97 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(
@@ -661,7 +665,7 @@ class ClassfileParser(
for (entry <- innerClasses.values) {
// create a new class member for immediate inner classes
if (entry.outerName == currentClassName) {
- val file = ctx.platform.classPath.findBinaryFile(entry.externalName.toString) getOrElse {
+ val file = ctx.platform.classPath.findClassFile(entry.externalName.toString) getOrElse {
throw new AssertionError(entry.externalName)
}
enterClassAndModule(entry, file, entry.jflags)
@@ -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 e8fa45403..b35a07027 100644
--- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala
+++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala
@@ -107,7 +107,7 @@ object Formatting {
else nonSensicalStartTag + str + nonSensicalEndTag
}
- private type Recorded = AnyRef /*Symbol | TypeParamRef*/
+ private type Recorded = AnyRef /*Symbol | TypeParamRef | SkolemType */
private class Seen extends mutable.HashMap[String, List[Recorded]] {
@@ -135,8 +135,13 @@ object Formatting {
if ((sym is ModuleClass) && sym.sourceModule.exists) simpleNameString(sym.sourceModule)
else seen.record(super.simpleNameString(sym), sym)
- override def TypeParamRefNameString(param: TypeParamRef): String =
- seen.record(super.TypeParamRefNameString(param), param)
+ override def ParamRefNameString(param: ParamRef): String =
+ seen.record(super.ParamRefNameString(param), param)
+
+ override def toTextRef(tp: SingletonType): Text = tp match {
+ case tp: SkolemType => seen.record(tp.repr.toString, tp)
+ case _ => super.toTextRef(tp)
+ }
}
/** Create explanation for single `Recorded` type or symbol */
@@ -165,6 +170,8 @@ object Formatting {
s"is a type variable${addendum("constraint", ctx.typeComparer.bounds(param))}"
case sym: Symbol =>
s"is a ${ctx.printer.kindString(sym)}${sym.showExtendedLocation}${addendum("bounds", sym.info)}"
+ case tp: SkolemType =>
+ s"is an unknown value of type ${tp.widen.show}"
}
}
@@ -176,6 +183,7 @@ object Formatting {
private def explanations(seen: Seen)(implicit ctx: Context): String = {
def needsExplanation(entry: Recorded) = entry match {
case param: TypeParamRef => ctx.typerState.constraint.contains(param)
+ case skolem: SkolemType => true
case _ => false
}
diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
index d5014b547..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))
@@ -134,9 +130,8 @@ class PlainPrinter(_ctx: Context) extends Printer {
case tp: TypeType =>
toTextRHS(tp)
case tp: TermRef
- if !tp.denotationIsCurrent && !homogenizedView || // always print underyling when testing picklers
- tp.symbol.is(Module) ||
- tp.symbol.name.isImportName =>
+ if !tp.denotationIsCurrent && !homogenizedView || // always print underlying when testing picklers
+ tp.symbol.is(Module) || tp.symbol.name == nme.IMPORT =>
toTextRef(tp) ~ ".type"
case tp: TermRef if tp.denot.isOverloaded =>
"<overloaded " ~ toTextRef(tp) ~ ">"
@@ -183,7 +178,9 @@ class PlainPrinter(_ctx: Context) extends Printer {
toTextGlobal(tp.resultType)
}
case tp: TypeParamRef =>
- TypeParamRefNameString(tp) ~ lambdaHash(tp.binder)
+ ParamRefNameString(tp) ~ lambdaHash(tp.binder)
+ case tp: TermParamRef =>
+ ParamRefNameString(tp) ~ ".type"
case AnnotatedType(tpe, annot) =>
toTextLocal(tpe) ~ " " ~ toText(annot)
case HKApply(tycon, args) =>
@@ -206,10 +203,10 @@ class PlainPrinter(_ctx: Context) extends Printer {
}
}.close
- protected def TypeParamRefNameString(name: TypeName): String = name.toString
+ protected def ParamRefNameString(name: Name): String = name.toString
- protected def TypeParamRefNameString(param: TypeParamRef): String =
- TypeParamRefNameString(param.binder.paramNames(param.paramNum))
+ protected def ParamRefNameString(param: ParamRef): String =
+ ParamRefNameString(param.binder.paramNames(param.paramNum))
/** The name of the symbol without a unique id. Under refined printing,
* the decoded original name.
@@ -266,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 76bce7920..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, _) =>
@@ -604,7 +607,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
def optText[T >: Untyped](tree: List[Tree[T]])(encl: Text => Text): Text =
if (tree.exists(!_.isEmpty)) encl(blockText(tree)) else ""
- override protected def TypeParamRefNameString(name: TypeName): String =
+ override protected def ParamRefNameString(name: Name): String =
name.unexpandedName.toString
override protected def treatAsTypeParam(sym: Symbol): Boolean = sym is TypeParam
diff --git a/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala b/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala
index 65c64f708..eed75fe88 100644
--- a/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala
+++ b/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala
@@ -138,7 +138,7 @@ class CompilingInterpreter(
private val prevRequests = new ArrayBuffer[Request]()
/** the compiler's classpath, as URL's */
- val compilerClasspath: List[URL] = ictx.platform.classPath(ictx).asURLs
+ val compilerClasspath: Seq[URL] = ictx.platform.classPath(ictx).asURLs
/* A single class loader is used for all commands interpreted by this Interpreter.
It would also be possible to create a new class loader for each command
diff --git a/compiler/src/dotty/tools/dotc/repl/ammonite/Protocol.scala b/compiler/src/dotty/tools/dotc/repl/ammonite/Protocol.scala
index 34d31aeca..e066050b6 100644
--- a/compiler/src/dotty/tools/dotc/repl/ammonite/Protocol.scala
+++ b/compiler/src/dotty/tools/dotc/repl/ammonite/Protocol.scala
@@ -5,7 +5,7 @@ package ammonite.terminal
case class TermInfo(ts: TermState, width: Int)
-sealed trait TermAction
+trait TermAction
case class Printing(ts: TermState, stdout: String) extends TermAction
case class TermState(
inputs: LazyList[Int],
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/ElimByName.scala b/compiler/src/dotty/tools/dotc/transform/ElimByName.scala
index 839552799..06c489029 100644
--- a/compiler/src/dotty/tools/dotc/transform/ElimByName.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ElimByName.scala
@@ -112,6 +112,9 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform
override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree =
applyIfFunction(tree, tree)
+ override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree =
+ applyIfFunction(tree, tree)
+
override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree = tree match {
case TypeApply(Select(_, nme.asInstanceOf_), arg :: Nil) =>
// tree might be of form e.asInstanceOf[x.type] where x becomes a function.
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/IsInstanceOfEvaluator.scala b/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala
index ebd2ae436..b48d219d6 100644
--- a/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala
+++ b/compiler/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala
@@ -147,6 +147,9 @@ class IsInstanceOfEvaluator extends MiniPhaseTransform { thisTransformer =>
(scTrait && selTrait)
val inMatch = s.qualifier.symbol is Case
+ // FIXME: This will misclassify case objects! We need to find another way to characterize
+ // isInstanceOfs generated by matches.
+ // Probably the most robust way is to use another symbol for the isInstanceOf method.
if (valueClassesOrAny) tree
else if (knownStatically)
diff --git a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala
index 7578b57f1..a729368d4 100644
--- a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala
+++ b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala
@@ -143,13 +143,17 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
/** Set `liftedOwner(sym)` to `owner` if `owner` is more deeply nested
* than the previous value of `liftedowner(sym)`.
*/
- def narrowLiftedOwner(sym: Symbol, owner: Symbol)(implicit ctx: Context) =
+ def narrowLiftedOwner(sym: Symbol, owner: Symbol)(implicit ctx: Context): Unit =
if (sym.maybeOwner.isTerm &&
owner.isProperlyContainedIn(liftedOwner(sym)) &&
owner != sym) {
- ctx.log(i"narrow lifted $sym to $owner")
- changedLiftedOwner = true
- liftedOwner(sym) = owner
+ if (sym.is(InSuperCall) && owner.isProperlyContainedIn(sym.enclosingClass))
+ narrowLiftedOwner(sym, sym.enclosingClass)
+ else {
+ ctx.log(i"narrow lifted $sym to $owner")
+ changedLiftedOwner = true
+ liftedOwner(sym) = owner
+ }
}
/** Mark symbol `sym` as being free in `enclosure`, unless `sym` is defined
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..41a1218eb 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)
@@ -233,7 +233,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {
// next: MatchMonad[U]
// returns MatchMonad[U]
def flatMap(prev: Tree, b: Symbol, next: Tree): Tree = {
- val resultArity = defn.productArity(b.info)
+ val resultArity = productArity(b.info)
if (isProductMatch(prev.tpe, resultArity)) {
val nullCheck: Tree = prev.select(defn.Object_ne).appliedTo(Literal(Constant(null)))
ifThenElseZero(
@@ -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)))
@@ -1408,7 +1408,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {
protected def seqTree(binder: Symbol) = tupleSel(binder)(firstIndexingBinder + 1)
protected def tupleSel(binder: Symbol)(i: Int): Tree = {
val accessors =
- if (defn.isProductSubType(binder.info))
+ if (Applications.canProductMatch(binder.info))
productSelectors(binder.info)
else binder.caseAccessors
val res =
diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala
index 9821757e8..bacb88091 100644
--- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala
+++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala
@@ -104,8 +104,14 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
private def transformAnnot(annot: Annotation)(implicit ctx: Context): Annotation =
annot.derivedAnnotation(transformAnnot(annot.tree))
+ private def registerChild(sym: Symbol, tp: Type)(implicit ctx: Context) = {
+ val cls = tp.classSymbol
+ if (cls.is(Sealed)) cls.addAnnotation(Annotation.makeChild(sym))
+ }
+
private def transformMemberDef(tree: MemberDef)(implicit ctx: Context): Unit = {
val sym = tree.symbol
+ if (sym.is(CaseVal, butNot = Method | Module)) registerChild(sym, sym.info)
sym.transformAnnotations(transformAnnot)
}
@@ -227,9 +233,9 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
// Add Child annotation to sealed parents unless current class is anonymous
if (!sym.isAnonymousClass) // ignore anonymous class
- for (parent <- sym.asClass.classInfo.classParents) {
- val pclazz = parent.classSymbol
- if (pclazz.is(Sealed)) pclazz.addAnnotation(Annotation.makeChild(sym))
+ sym.asClass.classInfo.classParents.foreach { parent =>
+ val sym2 = if (sym.is(Module)) sym.sourceModule else sym
+ registerChild(sym2, parent)
}
tree
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/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala
index 8d926fcf0..baf1ae356 100644
--- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala
+++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala
@@ -13,6 +13,7 @@ import core.StdNames._
import core.NameOps._
import core.Constants._
import reporting.diagnostic.messages._
+import config.Printers.{ exhaustivity => debug }
/** Space logic for checking exhaustivity and unreachability of pattern matching
*
@@ -28,8 +29,6 @@ import reporting.diagnostic.messages._
* 3. A union of spaces `S1 | S2 | ...` is a space
* 4. For a case class Kon(x1: T1, x2: T2, .., xn: Tn), if S1, S2, ..., Sn
* are spaces, then `Kon(S1, S2, ..., Sn)` is a space.
- * 5. A constant `Const(value, T)` is a point in space
- * 6. A stable identifier `Var(sym, T)` is a space
*
* For the problem of exhaustivity check, its formulation in terms of space is as follows:
*
@@ -67,15 +66,6 @@ case class Kon(tp: Type, params: List[Space]) extends Space
/** Union of spaces */
case class Or(spaces: List[Space]) extends Space
-/** Point in space */
-sealed trait Point extends Space
-
-/** Point representing variables(stable identifier) in patterns */
-case class Var(sym: Symbol, tp: Type) extends Point
-
-/** Point representing literal constants in patterns */
-case class Const(value: Constant, tp: Type) extends Point
-
/** abstract space logic */
trait SpaceLogic {
/** Is `tp1` a subtype of `tp2`? */
@@ -97,6 +87,9 @@ trait SpaceLogic {
/** Get components of decomposable types */
def decompose(tp: Type): List[Space]
+ /** Display space in string format */
+ def show(sp: Space): String
+
/** Simplify space using the laws, there's no nested union after simplify */
def simplify(space: Space): Space = space match {
case Kon(tp, spaces) =>
@@ -137,7 +130,7 @@ trait SpaceLogic {
def tryDecompose1(tp: Type) = canDecompose(tp) && isSubspace(Or(decompose(tp)), b)
def tryDecompose2(tp: Type) = canDecompose(tp) && isSubspace(a, Or(decompose(tp)))
- (a, b) match {
+ val res = (a, b) match {
case (Empty, _) => true
case (_, Empty) => false
case (Or(ss), _) => ss.forall(isSubspace(_, b))
@@ -157,17 +150,11 @@ trait SpaceLogic {
simplify(minus(a, b)) == Empty
case (Kon(tp1, ss1), Kon(tp2, ss2)) =>
isEqualType(tp1, tp2) && ss1.zip(ss2).forall((isSubspace _).tupled)
- case (Const(v1, _), Const(v2, _)) => v1 == v2
- case (Const(_, tp1), Typ(tp2, _)) => isSubType(tp1, tp2) || tryDecompose2(tp2)
- case (Const(_, _), Or(ss)) => ss.exists(isSubspace(a, _))
- case (Const(_, _), _) => false
- case (_, Const(_, _)) => false
- case (Var(x, _), Var(y, _)) => x == y
- case (Var(_, tp1), Typ(tp2, _)) => isSubType(tp1, tp2) || tryDecompose2(tp2)
- case (Var(_, _), Or(ss)) => ss.exists(isSubspace(a, _))
- case (Var(_, _), _) => false
- case (_, Var(_, _)) => false
}
+
+ debug.println(s"${show(a)} < ${show(b)} = $res")
+
+ res
}
/** Intersection of two spaces */
@@ -175,7 +162,7 @@ trait SpaceLogic {
def tryDecompose1(tp: Type) = intersect(Or(decompose(tp)), b)
def tryDecompose2(tp: Type) = intersect(a, Or(decompose(tp)))
- (a, b) match {
+ val res = (a, b) match {
case (Empty, _) | (_, Empty) => Empty
case (_, Or(ss)) => Or(ss.map(intersect(a, _)).filterConserve(_ ne Empty))
case (Or(ss), _) => Or(ss.map(intersect(_, b)).filterConserve(_ ne Empty))
@@ -199,31 +186,11 @@ trait SpaceLogic {
if (!isEqualType(tp1, tp2)) Empty
else if (ss1.zip(ss2).exists(p => simplify(intersect(p._1, p._2)) == Empty)) Empty
else Kon(tp1, ss1.zip(ss2).map((intersect _).tupled))
- case (Const(v1, _), Const(v2, _)) =>
- if (v1 == v2) a else Empty
- case (Const(_, tp1), Typ(tp2, _)) =>
- if (isSubType(tp1, tp2)) a
- else if (canDecompose(tp2)) tryDecompose2(tp2)
- else Empty
- case (Const(_, _), _) => Empty
- case (Typ(tp1, _), Const(_, tp2)) =>
- if (isSubType(tp2, tp1)) b
- else if (canDecompose(tp1)) tryDecompose1(tp1)
- else Empty
- case (_, Const(_, _)) => Empty
- case (Var(x, _), Var(y, _)) =>
- if (x == y) a else Empty
- case (Var(_, tp1), Typ(tp2, _)) =>
- if (isSubType(tp1, tp2)) a
- else if (canDecompose(tp2)) tryDecompose2(tp2)
- else Empty
- case (Var(_, _), _) => Empty
- case (Typ(tp1, _), Var(_, tp2)) =>
- if (isSubType(tp2, tp1)) b
- else if (canDecompose(tp1)) tryDecompose1(tp1)
- else Empty
- case (_, Var(_, _)) => Empty
}
+
+ debug.println(s"${show(a)} & ${show(b)} = ${show(res)}")
+
+ res
}
/** The space of a not covered by b */
@@ -231,7 +198,7 @@ trait SpaceLogic {
def tryDecompose1(tp: Type) = minus(Or(decompose(tp)), b)
def tryDecompose2(tp: Type) = minus(a, Or(decompose(tp)))
- (a, b) match {
+ val res = (a, b) match {
case (Empty, _) => Empty
case (_, Empty) => a
case (Typ(tp1, _), Typ(tp2, _)) =>
@@ -264,26 +231,11 @@ trait SpaceLogic {
Or(ss1.zip(ss2).map((minus _).tupled).zip(0 to ss2.length - 1).map {
case (ri, i) => Kon(tp1, ss1.updated(i, ri))
})
- case (Const(v1, _), Const(v2, _)) =>
- if (v1 == v2) Empty else a
- case (Const(_, tp1), Typ(tp2, _)) =>
- if (isSubType(tp1, tp2)) Empty
- else if (canDecompose(tp2)) tryDecompose2(tp2)
- else a
- case (Const(_, _), _) => a
- case (Typ(tp1, _), Const(_, tp2)) => // Boolean & Java enum
- if (canDecompose(tp1)) tryDecompose1(tp1)
- else a
- case (_, Const(_, _)) => a
- case (Var(x, _), Var(y, _)) =>
- if (x == y) Empty else a
- case (Var(_, tp1), Typ(tp2, _)) =>
- if (isSubType(tp1, tp2)) Empty
- else if (canDecompose(tp2)) tryDecompose2(tp2)
- else a
- case (Var(_, _), _) => a
- case (_, Var(_, _)) => a
}
+
+ debug.println(s"${show(a)} - ${show(b)} = ${show(res)}")
+
+ res
}
}
@@ -297,19 +249,14 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
* otherwise approximate extractors to Empty
*/
def project(pat: Tree, roundUp: Boolean = true)(implicit ctx: Context): Space = pat match {
- case Literal(c) => Const(c, c.tpe)
- case _: BackquotedIdent => Var(pat.symbol, pat.tpe)
+ case Literal(c) =>
+ if (c.value.isInstanceOf[Symbol])
+ Typ(c.value.asInstanceOf[Symbol].termRef, false)
+ else
+ Typ(ConstantType(c), false)
+ case _: BackquotedIdent => Typ(pat.tpe, false)
case Ident(_) | Select(_, _) =>
- pat.tpe.stripAnnots match {
- case tp: TermRef =>
- if (pat.symbol.is(Enum))
- Const(Constant(pat.symbol), tp)
- else if (tp.underlyingIterator.exists(_.classSymbol.is(Module)))
- Typ(tp.widenTermRefExpr.stripAnnots, false)
- else
- Var(pat.symbol, tp)
- case tp => Typ(tp, false)
- }
+ Typ(pat.tpe.stripAnnots, false)
case Alternative(trees) => Or(trees.map(project(_, roundUp)))
case Bind(_, pat) => project(pat)
case UnApply(_, _, pats) =>
@@ -345,7 +292,9 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
/** Is `tp1` a subtype of `tp2`? */
def isSubType(tp1: Type, tp2: Type): Boolean = {
// check SI-9657 and tests/patmat/gadt.scala
- erase(tp1) <:< erase(tp2)
+ val res = erase(tp1) <:< erase(tp2)
+ debug.println(s"${tp1.show} <:< ${tp2.show} = $res")
+ res
}
def isEqualType(tp1: Type, tp2: Type): Boolean = tp1 =:= tp2
@@ -373,19 +322,23 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
}
}
+ debug.println(s"candidates for ${tp.show} : [${children.map(_.show).mkString(", ")}]")
+
tp match {
case OrType(tp1, tp2) => List(Typ(tp1, true), Typ(tp2, true))
case _ if tp =:= ctx.definitions.BooleanType =>
List(
- Const(Constant(true), ctx.definitions.BooleanType),
- Const(Constant(false), ctx.definitions.BooleanType)
+ Typ(ConstantType(Constant(true)), true),
+ Typ(ConstantType(Constant(false)), true)
)
case _ if tp.classSymbol.is(Enum) =>
- children.map(sym => Const(Constant(sym), tp))
+ children.map(sym => Typ(sym.termRef, true))
case _ =>
val parts = children.map { sym =>
if (sym.is(ModuleClass))
- sym.asClass.classInfo.selfType
+ refine(tp, sym.sourceModule.termRef)
+ else if (sym.isTerm)
+ refine(tp, sym.termRef)
else if (sym.info.typeParams.length > 0 || tp.isInstanceOf[TypeRef])
refine(tp, sym.typeRef)
else
@@ -393,9 +346,13 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
} filter { tpe =>
// Child class may not always be subtype of parent:
// GADT & path-dependent types
- tpe <:< expose(tp)
+ val res = tpe <:< expose(tp)
+ if (!res) debug.println(s"unqualified child ousted: ${tpe.show} !< ${tp.show}")
+ res
}
+ debug.println(s"${tp.show} decomposes to [${parts.map(_.show).mkString(", ")}]")
+
parts.map(Typ(_, true))
}
}
@@ -409,20 +366,26 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
* `path2`, then return `path1.B`.
*/
def refine(tp1: Type, tp2: Type): Type = (tp1, tp2) match {
- case (tp1: RefinedType, _) => tp1.wrapIfMember(refine(tp1.parent, tp2))
+ case (tp1: RefinedType, _: TypeRef) => tp1.wrapIfMember(refine(tp1.parent, tp2))
case (tp1: HKApply, _) => refine(tp1.superType, tp2)
- case (TypeRef(ref1: TypeProxy, _), tp2 @ TypeRef(ref2: TypeProxy, name)) =>
- if (ref1.underlying <:< ref2.underlying) TypeRef(ref1, name) else tp2
+ case (TypeRef(ref1: TypeProxy, _), tp2 @ TypeRef(ref2: TypeProxy, _)) =>
+ if (ref1.underlying <:< ref2.underlying) tp2.derivedSelect(ref1) else tp2
+ case (TypeRef(ref1: TypeProxy, _), tp2 @ TermRef(ref2: TypeProxy, _)) =>
+ if (ref1.underlying <:< ref2.underlying) tp2.derivedSelect(ref1) else tp2
case _ => tp2
}
/** Abstract sealed types, or-types, Boolean and Java enums can be decomposed */
def canDecompose(tp: Type): Boolean = {
- tp.classSymbol.is(allOf(Abstract, Sealed)) ||
+ val res = tp.classSymbol.is(allOf(Abstract, Sealed)) ||
tp.classSymbol.is(allOf(Trait, Sealed)) ||
tp.isInstanceOf[OrType] ||
tp =:= ctx.definitions.BooleanType ||
- tp.classSymbol.is(Enum)
+ tp.classSymbol.is(allOf(Enum, Sealed)) // Enum value doesn't have Sealed flag
+
+ debug.println(s"decomposable: ${tp.show} = $res")
+
+ res
}
/** Show friendly type name with current scope in mind
@@ -474,14 +437,12 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
def show(s: Space): String = {
def doShow(s: Space, mergeList: Boolean = false): String = s match {
case Empty => ""
- case Const(v, _) => v.show
- case Var(x, _) => x.show
+ case Typ(c: ConstantType, _) => c.value.show
+ case Typ(tp: TermRef, _) => tp.symbol.showName
case Typ(tp, decomposed) =>
val sym = tp.widen.classSymbol
- if (sym.is(ModuleClass))
- showType(tp)
- else if (ctx.definitions.isTupleType(tp))
+ if (ctx.definitions.isTupleType(tp))
signature(tp).map(_ => "_").mkString("(", ", ", ")")
else if (sym.showFullName == "scala.collection.immutable.::")
if (mergeList) "_" else "List(_)"
@@ -523,7 +484,9 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
}
val Match(sel, cases) = tree
- isCheckable(sel.tpe.widen.deAnonymize.dealiasKeepAnnots)
+ val res = isCheckable(sel.tpe.widen.deAnonymize.dealiasKeepAnnots)
+ debug.println(s"checkable: ${sel.show} = $res")
+ res
}
@@ -584,7 +547,11 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
val selTyp = sel.tpe.widen.deAnonymize.dealias
- val patternSpace = cases.map(x => project(x.pat)).reduce((a, b) => Or(List(a, b)))
+ val patternSpace = cases.map({ x =>
+ val space = project(x.pat)
+ debug.println(s"${x.pat.show} projects to ${show(space)}")
+ space
+ }).reduce((a, b) => Or(List(a, b)))
val uncovered = simplify(minus(Typ(selTyp, true), patternSpace))
if (uncovered != Empty)
diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala
index 4e43e429b..c4d3e2292 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._
@@ -47,13 +48,15 @@ object Applications {
ref.info.widenExpr.dealias
}
+ def canProductMatch(tp: Type)(implicit ctx: Context) =
+ extractorMemberType(tp, nme._1).exists
+
/** Does `tp` fit the "product match" conditions as an unapply result type
- * for a pattern with `numArgs` subpatterns>
- * This is the case of `tp` is a subtype of the Product<numArgs> class.
+ * for a pattern with `numArgs` subpatterns?
+ * This is the case of `tp` has members `_1` to `_N` where `N == numArgs`.
*/
def isProductMatch(tp: Type, numArgs: Int)(implicit ctx: Context) =
- 0 <= numArgs && numArgs <= Definitions.MaxTupleArity &&
- tp.derivesFrom(defn.ProductNType(numArgs).typeSymbol)
+ numArgs > 0 && productArity(tp) == numArgs
/** Does `tp` fit the "get match" conditions as an unapply result type?
* This is the case of `tp` has a `get` member as well as a
@@ -68,6 +71,9 @@ object Applications {
sels.takeWhile(_.exists).toList
}
+ def productArity(tp: Type)(implicit ctx: Context) =
+ if (canProductMatch(tp)) productSelectorTypes(tp).size else -1
+
def productSelectors(tp: Type)(implicit ctx: Context): List[Symbol] = {
val sels = for (n <- Iterator.from(0)) yield tp.member(nme.selectorName(n)).symbol
sels.takeWhile(_.exists).toList
@@ -108,7 +114,7 @@ object Applications {
getUnapplySelectors(getTp, args, pos)
else if (unapplyResult isRef defn.BooleanClass)
Nil
- else if (defn.isProductSubType(unapplyResult))
+ else if (canProductMatch(unapplyResult))
productSelectorTypes(unapplyResult)
// this will cause a "wrong number of arguments in pattern" error later on,
// which is better than the message in `fail`.
@@ -345,7 +351,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) {
@@ -395,15 +401,14 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
def addTyped(arg: Arg, formal: Type): Type => Type = {
addArg(typedArg(arg, formal), formal)
if (methodType.isParamDependent)
- _.substParam(methodType.newParamRef(n), typeOfArg(arg))
- else
- identity
+ safeSubstParam(_, methodType.paramRefs(n), typeOfArg(arg))
+ else identity
}
def missingArg(n: Int): Unit = {
val pname = methodType.paramNames(n)
fail(
- if (pname contains '$') s"not enough arguments for $methString"
+ if (pname.firstPart contains '$') s"not enough arguments for $methString"
else s"missing argument for parameter $pname of $methString")
}
@@ -719,7 +724,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 ce2030c01..da9f9f6ac 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,
@@ -842,7 +843,7 @@ class Namer { typer: Typer =>
val targs1 = targs map (typedAheadType(_))
val ptype = typedAheadType(tpt).tpe appliedTo targs1.tpes
if (ptype.typeParams.isEmpty) ptype
- else typedAheadExpr(parent).tpe
+ else fullyDefinedType(typedAheadExpr(parent).tpe, "class parent", parent.pos)
}
/* Check parent type tree `parent` for the following well-formedness conditions:
@@ -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,17 +1032,18 @@ 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}")
def isInline = sym.is(FinalOrInline, butNot = Method | Mutable)
// Widen rhs type and approximate `|' but keep ConstantTypes if
- // definition is inline (i.e. final in Scala2).
+ // definition is inline (i.e. final in Scala2) and keep module singleton types
+ // instead of widening to the underlying module class types.
def widenRhs(tp: Type): Type = tp.widenTermRefExpr match {
- case tp: ConstantType if isInline => tp
+ case ctp: ConstantType if isInline => ctp
+ case ref: TypeRef if ref.symbol.is(ModuleClass) => tp
case _ => ctx.harmonizeUnion(tp.widen)
}
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 2aa7036b4..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 =>
@@ -315,10 +315,28 @@ trait TypeAssigner {
}
}
+ /** Substitute argument type `argType` for parameter `pref` in type `tp`,
+ * skolemizing the argument type if it is not stable and `pref` occurs in `tp`.
+ */
+ def safeSubstParam(tp: Type, pref: ParamRef, argType: Type)(implicit ctx: Context) = {
+ val tp1 = tp.substParam(pref, argType)
+ if ((tp1 eq tp) || argType.isStable) tp1
+ else tp.substParam(pref, SkolemType(argType.widen))
+ }
+
def assignType(tree: untpd.Apply, fn: Tree, args: List[Tree])(implicit ctx: Context) = {
val ownType = fn.tpe.widen match {
case fntpe: MethodType =>
- if (sameLength(fntpe.paramInfos, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes)
+ def safeSubstParams(tp: Type, params: List[ParamRef], args: List[Tree]): Type = params match {
+ case param :: params1 =>
+ val tp1 = safeSubstParam(tp, param, args.head.tpe)
+ safeSubstParams(tp1, params1, args.tail)
+ case Nil =>
+ tp
+ }
+ if (sameLength(fntpe.paramInfos, args) || ctx.phase.prev.relaxedTyping)
+ if (fntpe.isDependent) safeSubstParams(fntpe.resultType, fntpe.paramRefs, args)
+ else fntpe.resultType
else
errorType(i"wrong number of arguments for $fntpe: ${fn.tpe}, expected: ${fntpe.paramInfos.length}, found: ${args.length}", tree.pos)
case t =>
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index 8a124b17b..4bf938fd4 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._
@@ -568,7 +569,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)))
@@ -757,10 +758,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
/** Is `formal` a product type which is elementwise compatible with `params`? */
def ptIsCorrectProduct(formal: Type) = {
- val pclass = defn.ProductNType(params.length).symbol
isFullyDefined(formal, ForceDegree.noBottom) &&
- formal.derivesFrom(pclass) &&
- formal.baseArgTypes(pclass).corresponds(params) {
+ Applications.canProductMatch(formal) &&
+ Applications.productSelectorTypes(formal).corresponds(params) {
(argType, param) =>
param.tpt.isEmpty || argType <:< typedAheadType(param.tpt).tpe
}
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/src/dotty/tools/io/ClassPath.scala b/compiler/src/dotty/tools/io/ClassPath.scala
index 5e77c1b61..b4cc426cf 100644
--- a/compiler/src/dotty/tools/io/ClassPath.scala
+++ b/compiler/src/dotty/tools/io/ClassPath.scala
@@ -1,56 +1,89 @@
/* NSC -- new Scala compiler
- * Copyright 2006-2012 LAMP/EPFL
+ * Copyright 2006-2013 LAMP/EPFL
* @author Martin Odersky
*/
+
package dotty.tools
package io
+import java.net.MalformedURLException
import java.net.URL
-import scala.collection.{ mutable, immutable }
-import dotc.core.Decorators.StringDecorator
+import java.util.regex.PatternSyntaxException
+
import File.pathSeparator
-import java.net.MalformedURLException
import Jar.isJarOrZip
-import ClassPath._
-import scala.Option.option2Iterable
-import scala.reflect.io.Path.string2path
-import language.postfixOps
-
-/** <p>
- * This module provides star expansion of '-classpath' option arguments, behaves the same as
- * java, see [http://java.sun.com/javase/6/docs/technotes/tools/windows/classpath.html]
- * </p>
- *
- * @author Stepan Koltsov
- */
+
+/**
+ * A representation of the compiler's class- or sourcepath.
+ */
+trait ClassPath {
+ import dotty.tools.dotc.classpath._
+ def asURLs: Seq[URL]
+
+ /** Empty string represents root package */
+ private[dotty] def packages(inPackage: String): Seq[PackageEntry]
+ private[dotty] def classes(inPackage: String): Seq[ClassFileEntry]
+ private[dotty] def sources(inPackage: String): Seq[SourceFileEntry]
+
+ /** Allows to get entries for packages and classes merged with sources possibly in one pass. */
+ private[dotty] def list(inPackage: String): ClassPathEntries
+
+ /**
+ * It returns both classes from class file and source files (as our base ClassRepresentation).
+ * So note that it's not so strictly related to findClassFile.
+ */
+ def findClass(className: String): Option[ClassRepresentation] = {
+ // A default implementation which should be overridden, if we can create the more efficient
+ // solution for a given type of ClassPath
+ val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className)
+
+ val foundClassFromClassFiles = classes(pkg).find(_.name == simpleClassName)
+ def findClassInSources = sources(pkg).find(_.name == simpleClassName)
+
+ foundClassFromClassFiles orElse findClassInSources
+ }
+ def findClassFile(className: String): Option[AbstractFile]
+
+ def asClassPathStrings: Seq[String]
+
+ /** The whole classpath in the form of one String.
+ */
+ def asClassPathString: String = ClassPath.join(asClassPathStrings: _*)
+ // for compatibility purposes
+ @deprecated("use asClassPathString instead of this one", "2.11.5")
+ def asClasspathString: String = asClassPathString
+
+ /** The whole sourcepath in the form of one String.
+ */
+ def asSourcePathString: String
+}
+
object ClassPath {
+ val RootPackage = ""
/** Expand single path entry */
private def expandS(pattern: String): List[String] = {
val wildSuffix = File.separator + "*"
- /** Get all subdirectories, jars, zips out of a directory. */
- def lsDir(dir: Directory, filt: String => Boolean = _ => true) = {
- val files = synchronized(dir.list)
- files filter (x => filt(x.name) && (x.isDirectory || isJarOrZip(x))) map (_.path) toList
- }
-
- def basedir(s: String) =
- if (s contains File.separator) s.substring(0, s.lastIndexOf(File.separator))
- else "."
+ /* Get all subdirectories, jars, zips out of a directory. */
+ def lsDir(dir: Directory, filt: String => Boolean = _ => true) =
+ dir.list.filter(x => filt(x.name) && (x.isDirectory || isJarOrZip(x))).map(_.path).toList
if (pattern == "*") lsDir(Directory("."))
else if (pattern endsWith wildSuffix) lsDir(Directory(pattern dropRight 2))
else if (pattern contains '*') {
- val regexp = ("^%s$" format pattern.replaceAll("""\*""", """.*""")).r
- lsDir(Directory(pattern).parent, regexp findFirstIn _ isDefined)
+ try {
+ val regexp = ("^" + pattern.replaceAllLiterally("""\*""", """.*""") + "$").r
+ lsDir(Directory(pattern).parent, regexp.findFirstIn(_).isDefined)
+ }
+ catch { case _: PatternSyntaxException => List(pattern) }
}
else List(pattern)
}
/** Split classpath using platform-dependent path separator */
- def split(path: String): List[String] = (path split pathSeparator).toList filterNot (_ == "") distinct
+ def split(path: String): List[String] = (path split pathSeparator).toList.filterNot(_ == "").distinct
/** Join classpath using platform-dependent path separator */
def join(paths: String*): String = paths filterNot (_ == "") mkString pathSeparator
@@ -58,22 +91,6 @@ object ClassPath {
/** Split the classpath, apply a transformation function, and reassemble it. */
def map(cp: String, f: String => String): String = join(split(cp) map f: _*)
- /** Split the classpath, filter according to predicate, and reassemble. */
- def filter(cp: String, p: String => Boolean): String = join(split(cp) filter p: _*)
-
- /** Split the classpath and map them into Paths */
- def toPaths(cp: String): List[Path] = split(cp) map (x => Path(x).toAbsolute)
-
- /** Make all classpath components absolute. */
- def makeAbsolute(cp: String): String = fromPaths(toPaths(cp): _*)
-
- /** Join the paths as a classpath */
- def fromPaths(paths: Path*): String = join(paths map (_.path): _*)
- def fromURLs(urls: URL*): String = fromPaths(urls map (x => Path(x.getPath)) : _*)
-
- /** Split the classpath and map them into URLs */
- def toURLs(cp: String): List[URL] = toPaths(cp) map (_.toURL)
-
/** Expand path and possibly expanding stars */
def expandPath(path: String, expandStar: Boolean = true): List[String] =
if (expandStar) split(path) flatMap expandS
@@ -83,9 +100,10 @@ object ClassPath {
def expandDir(extdir: String): List[String] = {
AbstractFile getDirectory extdir match {
case null => Nil
- case dir => dir filter (_.isClassContainer) map (x => new java.io.File(dir.file, x.name) getPath) toList
+ case dir => dir.filter(_.isClassContainer).map(x => new java.io.File(dir.file, x.name).getPath).toList
}
}
+
/** Expand manifest jar classpath entries: these are either urls, or paths
* relative to the location of the jar.
*/
@@ -99,317 +117,34 @@ object ClassPath {
)
}
- /** A useful name filter. */
- def isTraitImplementation(name: String) = name endsWith "$class.class"
-
def specToURL(spec: String): Option[URL] =
try Some(new URL(spec))
catch { case _: MalformedURLException => None }
- /** A class modeling aspects of a ClassPath which should be
- * propagated to any classpaths it creates.
- */
- abstract class ClassPathContext {
- /** A filter which can be used to exclude entities from the classpath
- * based on their name.
- */
- def isValidName(name: String): Boolean = true
-
- /** From the representation to its identifier.
- */
- def toBinaryName(rep: AbstractFile): String
-
- /** Create a new classpath based on the abstract file.
- */
- def newClassPath(file: AbstractFile): ClassPath
-
- /** Creators for sub classpaths which preserve this context.
- */
- def sourcesInPath(path: String): List[ClassPath] =
- for (file <- expandPath(path, false) ; dir <- Option(AbstractFile getDirectory file)) yield
- new SourcePath(dir, this)
-
- def contentsOfDirsInPath(path: String): List[ClassPath] =
- for (dir <- expandPath(path, false) ; name <- expandDir(dir) ; entry <- Option(AbstractFile getDirectory name)) yield
- newClassPath(entry)
-
- def classesAtAllURLS(path: String): List[ClassPath] =
- (path split " ").toList flatMap classesAtURL
-
- def classesAtURL(spec: String) =
- for (url <- specToURL(spec).toList ; location <- Option(AbstractFile getURL url)) yield
- newClassPath(location)
-
- def classesInExpandedPath(path: String): IndexedSeq[ClassPath] =
- classesInPathImpl(path, true).toIndexedSeq
-
- def classesInPath(path: String) = classesInPathImpl(path, false)
-
- // Internal
- private def classesInPathImpl(path: String, expand: Boolean) =
- for (file <- expandPath(path, expand) ; dir <- Option(AbstractFile getDirectory file)) yield
- newClassPath(dir)
- }
-
- class JavaContext extends ClassPathContext {
- def toBinaryName(rep: AbstractFile) = {
- val name = rep.name
- assert(endsClass(name), name)
- name.substring(0, name.length - 6)
- }
- def newClassPath(dir: AbstractFile) = new DirectoryClassPath(dir, this)
- }
-
- object DefaultJavaContext extends JavaContext {
- override def isValidName(name: String) = !isTraitImplementation(name)
+ def manifests: List[java.net.URL] = {
+ import scala.collection.JavaConverters._
+ val resources = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF")
+ resources.asScala.filter(_.getProtocol == "jar").toList
}
- private def endsClass(s: String) = s.length > 6 && s.substring(s.length - 6) == ".class"
- private def endsScala(s: String) = s.length > 6 && s.substring(s.length - 6) == ".scala"
- private def endsJava(s: String) = s.length > 5 && s.substring(s.length - 5) == ".java"
-
- /** From the source file to its identifier.
- */
- def toSourceName(f: AbstractFile): String = {
- val name = f.name
+ @deprecated("shim for sbt's compiler interface", since = "2.12.0")
+ sealed abstract class ClassPathContext
- if (endsScala(name)) name.substring(0, name.length - 6)
- else if (endsJava(name)) name.substring(0, name.length - 5)
- else throw new FatalError("Unexpected source file ending: " + name)
- }
+ @deprecated("shim for sbt's compiler interface", since = "2.12.0")
+ sealed abstract class JavaContext
}
-/**
- * Represents a package which contains classes and other packages
- */
-abstract class ClassPath {
- type AnyClassRep = ClassPath#ClassRep
-
- /**
- * The short name of the package (without prefix)
- */
+trait ClassRepresentation {
def name: String
-
- /**
- * A String representing the origin of this classpath element, if known.
- * For example, the path of the directory or jar.
- */
- def origin: Option[String] = None
-
- /** A list of URLs representing this classpath.
- */
- def asURLs: List[URL]
-
- /** The whole classpath in the form of one String.
- */
- def asClasspathString: String
-
- /** Info which should be propagated to any sub-classpaths.
- */
- def context: ClassPathContext
-
- /** Lists of entities.
- */
- def classes: IndexedSeq[AnyClassRep]
- def packages: IndexedSeq[ClassPath]
- def sourcepaths: IndexedSeq[AbstractFile]
-
- /**
- * Represents classes which can be loaded with a ClassfileLoader
- * and / or a SourcefileLoader.
- */
- case class ClassRep(binary: Option[AbstractFile], source: Option[AbstractFile]) {
- def name: String = binary match {
- case Some(x) => context.toBinaryName(x)
- case _ =>
- assert(source.isDefined)
- toSourceName(source.get)
- }
- }
-
- /** Filters for assessing validity of various entities.
- */
- def validClassFile(name: String) = endsClass(name) && context.isValidName(name)
- def validPackage(name: String) = (name != "META-INF") && (name != "") && (name.charAt(0) != '.')
- def validSourceFile(name: String) = endsScala(name) || endsJava(name)
-
- /**
- * Find a ClassRep given a class name of the form "package.subpackage.ClassName".
- * Does not support nested classes on .NET
- */
- def findClass(name: String): Option[AnyClassRep] =
- name.splitWhere(_ == '.', doDropIndex = true) match {
- case Some((pkg, rest)) =>
- packages find (_.name == pkg) flatMap (_ findClass rest)
- case _ =>
- classes find (_.name == name)
- }
-
- def findBinaryFile(name: String): Option[AbstractFile] =
- findClass(name).flatMap(_.binary)
-
- def sortString = join(split(asClasspathString).sorted: _*)
-
- override def equals(that: Any) = that match {
- case x: ClassPath => this.sortString == x.sortString
- case _ => false
- }
- override def hashCode = sortString.hashCode()
+ def binary: Option[AbstractFile]
+ def source: Option[AbstractFile]
}
-/**
- * A Classpath containing source files
- */
-class SourcePath(dir: AbstractFile, val context: ClassPathContext) extends ClassPath {
- def name = dir.name
- override def origin = dir.underlyingSource map (_.path)
- def asURLs = if (dir.file == null) Nil else List(dir.toURL)
- def asClasspathString = dir.path
- val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq(dir)
-
- private def traverse() = {
- val classBuf = immutable.Vector.newBuilder[ClassRep]
- val packageBuf = immutable.Vector.newBuilder[SourcePath]
- dir foreach { f =>
- if (!f.isDirectory && validSourceFile(f.name))
- classBuf += ClassRep(None, Some(f))
- else if (f.isDirectory && validPackage(f.name))
- packageBuf += new SourcePath(f, context)
- }
- (packageBuf.result, classBuf.result)
- }
+@deprecated("shim for sbt's compiler interface", since = "2.12.0")
+sealed abstract class DirectoryClassPath
- lazy val (packages, classes) = traverse()
- override def toString() = "sourcepath: " + dir.toString()
-}
+@deprecated("shim for sbt's compiler interface", since = "2.12.0")
+sealed abstract class MergedClassPath
-/**
- * A directory (or a .jar file) containing classfiles and packages
- */
-class DirectoryClassPath(val dir: AbstractFile, val context: ClassPathContext) extends ClassPath {
- def name = dir.name
- override def origin = dir.underlyingSource map (_.path)
- def asURLs = if (dir.file == null) Nil else List(dir.toURL)
- def asClasspathString = dir.path
- val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq()
-
- // calculates (packages, classes) in one traversal.
- private def traverse() = {
- val classBuf = immutable.Vector.newBuilder[ClassRep]
- val packageBuf = immutable.Vector.newBuilder[DirectoryClassPath]
- dir foreach { f =>
- if (!f.isDirectory && validClassFile(f.name))
- classBuf += ClassRep(Some(f), None)
- else if (f.isDirectory && validPackage(f.name))
- packageBuf += new DirectoryClassPath(f, context)
- }
- (packageBuf.result, classBuf.result)
- }
-
- lazy val (packages, classes) = traverse()
- override def toString() = "directory classpath: " + origin.getOrElse("?")
-}
-
-class DeltaClassPath(original: MergedClassPath, subst: Map[ClassPath, ClassPath])
-extends MergedClassPath(original.entries map (e => subst getOrElse (e, e)), original.context) {
- // not sure we should require that here. Commented out for now.
- // require(subst.keySet subsetOf original.entries.toSet)
- // We might add specialized operations for computing classes packages here. Not sure it's worth it.
-}
-
-/**
- * A classpath unifying multiple class- and sourcepath entries.
- */
-class MergedClassPath(
- val entries: IndexedSeq[ClassPath],
- val context: ClassPathContext)
-extends ClassPath {
- def this(entries: TraversableOnce[ClassPath], context: ClassPathContext) =
- this(entries.toIndexedSeq, context)
-
- def name = entries.head.name
- def asURLs = (entries flatMap (_.asURLs)).toList
- lazy val sourcepaths: IndexedSeq[AbstractFile] = entries flatMap (_.sourcepaths)
-
- override def origin = Some(entries map (x => x.origin getOrElse x.name) mkString ("Merged(", ", ", ")"))
- override def asClasspathString: String = join(entries map (_.asClasspathString) : _*)
-
- lazy val classes: IndexedSeq[AnyClassRep] = {
- var count = 0
- val indices = mutable.AnyRefMap[String, Int]()
- val cls = new mutable.ArrayBuffer[AnyClassRep](1024)
-
- for (e <- entries; c <- e.classes) {
- val name = c.name
- if (indices contains name) {
- val idx = indices(name)
- val existing = cls(idx)
-
- if (existing.binary.isEmpty && c.binary.isDefined)
- cls(idx) = existing.copy(binary = c.binary)
- if (existing.source.isEmpty && c.source.isDefined)
- cls(idx) = existing.copy(source = c.source)
- }
- else {
- indices(name) = count
- cls += c
- count += 1
- }
- }
- cls.toIndexedSeq
- }
-
- lazy val packages: IndexedSeq[ClassPath] = {
- var count = 0
- val indices = mutable.AnyRefMap[String, Int]()
- val pkg = new mutable.ArrayBuffer[ClassPath](256)
-
- for (e <- entries; p <- e.packages) {
- val name = p.name
- if (indices contains name) {
- val idx = indices(name)
- pkg(idx) = addPackage(pkg(idx), p)
- }
- else {
- indices(name) = count
- pkg += p
- count += 1
- }
- }
- pkg.toIndexedSeq
- }
-
- private def addPackage(to: ClassPath, pkg: ClassPath) = {
- val newEntries: IndexedSeq[ClassPath] = to match {
- case cp: MergedClassPath => cp.entries :+ pkg
- case _ => IndexedSeq(to, pkg)
- }
- new MergedClassPath(newEntries, context)
- }
- def show(): Unit = {
- println("ClassPath %s has %d entries and results in:\n".format(name, entries.size))
- asClasspathString split ':' foreach (x => println(" " + x))
- }
- override def toString() = "merged classpath " + entries.mkString("(", "\n", ")")
-}
-
-/**
- * The classpath when compiling with target:jvm. Binary files (classfiles) are represented
- * as AbstractFile. nsc.io.ZipArchive is used to view zip/jar archives as directories.
- */
-class JavaClassPath(
- containers: IndexedSeq[ClassPath],
- context: JavaContext)
-extends MergedClassPath(containers, context) { }
-
-object JavaClassPath {
- def fromURLs(urls: Seq[URL], context: JavaContext): JavaClassPath = {
- val containers = {
- for (url <- urls ; f = AbstractFile getURL url ; if f != null) yield
- new DirectoryClassPath(f, context)
- }
- new JavaClassPath(containers.toIndexedSeq, context)
- }
- def fromURLs(urls: Seq[URL]): JavaClassPath =
- fromURLs(urls, ClassPath.DefaultJavaContext)
-}
+@deprecated("shim for sbt's compiler interface", since = "2.12.0")
+sealed abstract class JavaClassPath
diff --git a/compiler/src/dotty/tools/io/PlainFile.scala b/compiler/src/dotty/tools/io/PlainFile.scala
new file mode 100644
index 000000000..53474e778
--- /dev/null
+++ b/compiler/src/dotty/tools/io/PlainFile.scala
@@ -0,0 +1,170 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package dotty.tools
+package io
+
+/** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */
+class PlainDirectory(givenPath: Directory) extends PlainFile(givenPath) {
+ override def isDirectory = true
+ override def iterator = givenPath.list filter (_.exists) map (x => new PlainFile(x))
+ override def delete(): Unit = givenPath.deleteRecursively()
+}
+
+/** This class implements an abstract file backed by a File.
+ *
+ * ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
+ */
+class PlainFile(val givenPath: Path) extends AbstractFile {
+ assert(path ne null)
+
+ val file = givenPath.jfile
+ override def underlyingSource = Some(this)
+
+ private val fpath = givenPath.toAbsolute
+
+ /** Returns the name of this abstract file. */
+ def name = givenPath.name
+
+ /** Returns the path of this abstract file. */
+ def path = givenPath.path
+
+ /** The absolute file. */
+ def absolute = new PlainFile(givenPath.toAbsolute)
+
+ override def container: AbstractFile = new PlainFile(givenPath.parent)
+ override def input = givenPath.toFile.inputStream()
+ override def output = givenPath.toFile.outputStream()
+ override def sizeOption = Some(givenPath.length.toInt)
+
+ override def hashCode(): Int = fpath.hashCode()
+ override def equals(that: Any): Boolean = that match {
+ case x: PlainFile => fpath == x.fpath
+ case _ => false
+ }
+
+ /** Is this abstract file a directory? */
+ def isDirectory: Boolean = givenPath.isDirectory
+
+ /** Returns the time that this abstract file was last modified. */
+ def lastModified: Long = givenPath.lastModified
+
+ /** Returns all abstract subfiles of this abstract directory. */
+ def iterator: Iterator[AbstractFile] = {
+ // Optimization: Assume that the file was not deleted and did not have permissions changed
+ // between the call to `list` and the iteration. This saves a call to `exists`.
+ def existsFast(path: Path) = path match {
+ case (_: Directory | _: io.File) => true
+ case _ => path.exists
+ }
+ if (!isDirectory) Iterator.empty
+ else givenPath.toDirectory.list filter existsFast map (new PlainFile(_))
+ }
+
+ /**
+ * Returns the abstract file in this abstract directory with the
+ * specified name. If there is no such file, returns null. The
+ * argument "directory" tells whether to look for a directory or
+ * or a regular file.
+ */
+ def lookupName(name: String, directory: Boolean): AbstractFile = {
+ val child = givenPath / name
+ if ((child.isDirectory && directory) || (child.isFile && !directory)) new PlainFile(child)
+ else null
+ }
+
+ /** Does this abstract file denote an existing file? */
+ def create(): Unit = if (!exists) givenPath.createFile()
+
+ /** Delete the underlying file or directory (recursively). */
+ def delete(): Unit =
+ if (givenPath.isFile) givenPath.delete()
+ else if (givenPath.isDirectory) givenPath.toDirectory.deleteRecursively()
+
+ /** Returns a plain file with the given name. It does not
+ * check that it exists.
+ */
+ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
+ new PlainFile(givenPath / name)
+}
+
+private[dotty] class PlainNioFile(nioPath: java.nio.file.Path) extends AbstractFile {
+ import java.nio.file._
+
+ assert(nioPath ne null)
+
+ /** Returns the underlying File if any and null otherwise. */
+ override def file: java.io.File = try {
+ nioPath.toFile
+ } catch {
+ case _: UnsupportedOperationException => null
+ }
+
+ override def underlyingSource = Some(this)
+
+ private val fpath = nioPath.toAbsolutePath.toString
+
+ /** Returns the name of this abstract file. */
+ def name = nioPath.getFileName.toString
+
+ /** Returns the path of this abstract file. */
+ def path = nioPath.toString
+
+ /** The absolute file. */
+ def absolute = new PlainNioFile(nioPath.toAbsolutePath)
+
+ override def container: AbstractFile = new PlainNioFile(nioPath.getParent)
+ override def input = Files.newInputStream(nioPath)
+ override def output = Files.newOutputStream(nioPath)
+ override def sizeOption = Some(Files.size(nioPath).toInt)
+ override def hashCode(): Int = fpath.hashCode()
+ override def equals(that: Any): Boolean = that match {
+ case x: PlainNioFile => fpath == x.fpath
+ case _ => false
+ }
+
+ /** Is this abstract file a directory? */
+ def isDirectory: Boolean = Files.isDirectory(nioPath)
+
+ /** Returns the time that this abstract file was last modified. */
+ def lastModified: Long = Files.getLastModifiedTime(nioPath).toMillis
+
+ /** Returns all abstract subfiles of this abstract directory. */
+ def iterator: Iterator[AbstractFile] = {
+ try {
+ import scala.collection.JavaConverters._
+ val it = Files.newDirectoryStream(nioPath).iterator()
+ it.asScala.map(new PlainNioFile(_))
+ } catch {
+ case _: NotDirectoryException => Iterator.empty
+ }
+ }
+
+ /**
+ * Returns the abstract file in this abstract directory with the
+ * specified name. If there is no such file, returns null. The
+ * argument "directory" tells whether to look for a directory or
+ * or a regular file.
+ */
+ def lookupName(name: String, directory: Boolean): AbstractFile = {
+ val child = nioPath.resolve(name)
+ if ((Files.isDirectory(child) && directory) || (Files.isRegularFile(child) && !directory)) new PlainNioFile(child)
+ else null
+ }
+
+ /** Does this abstract file denote an existing file? */
+ def create(): Unit = if (!exists) Files.createFile(nioPath)
+
+ /** Delete the underlying file or directory (recursively). */
+ def delete(): Unit =
+ if (Files.isRegularFile(nioPath)) Files.deleteIfExists(nioPath)
+ else if (Files.isDirectory(nioPath)) new Directory(nioPath.toFile).deleteRecursively()
+
+ /** Returns a plain file with the given name. It does not
+ * check that it exists.
+ */
+ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
+ new PlainNioFile(nioPath.resolve(name))
+}
diff --git a/compiler/src/dotty/tools/io/package.scala b/compiler/src/dotty/tools/io/package.scala
index 1c0e0b5c4..7acb827c9 100644
--- a/compiler/src/dotty/tools/io/package.scala
+++ b/compiler/src/dotty/tools/io/package.scala
@@ -20,8 +20,6 @@ package object io {
val File = scala.reflect.io.File
type Path = scala.reflect.io.Path
val Path = scala.reflect.io.Path
- type PlainFile = scala.reflect.io.PlainFile
- //val PlainFile = scala.reflect.io.PlainFile
val Streamable = scala.reflect.io.Streamable
type VirtualDirectory = scala.reflect.io.VirtualDirectory
type VirtualFile = scala.reflect.io.VirtualFile
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 ", "")
diff --git a/project/build.properties b/project/build.properties
index 866eb2660..64317fdae 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version=0.13.14-RC2
+sbt.version=0.13.15
diff --git a/sbt-bridge/test/xsbt/ScalaCompilerForUnitTesting.scala b/sbt-bridge/test/xsbt/ScalaCompilerForUnitTesting.scala
index a6b9fa65e..a835421d8 100644
--- a/sbt-bridge/test/xsbt/ScalaCompilerForUnitTesting.scala
+++ b/sbt-bridge/test/xsbt/ScalaCompilerForUnitTesting.scala
@@ -173,7 +173,7 @@ class ScalaCompilerForUnitTesting(nameHashing: Boolean, includeSynthToNameHashin
private def prepareCompiler(outputDir: File, analysisCallback: AnalysisCallback, classpath: String = ".") = {
val args = Array.empty[String]
- import dotty.tools.dotc._
+ import dotty.tools.dotc.{Compiler, Driver}
import dotty.tools.dotc.core.Contexts._
val driver = new Driver {
diff --git a/tests/neg/i2142.scala b/tests/neg/i2142.scala
new file mode 100644
index 000000000..7aeef95f0
--- /dev/null
+++ b/tests/neg/i2142.scala
@@ -0,0 +1,28 @@
+object Foo {
+
+class A
+val a1 = new A()
+val a2 = new A()
+
+def f(x: A, y: x.type) = ()
+f(a1, a1) // ok
+f(a1, a2) // error
+f(new A(), new A()) // error
+f(new A(), a1) // error
+
+def g(x: A)(y: x.type) = ()
+g(a1)(a1) // ok
+g(a1)(a2) // error
+g(new A())(new A()) // error
+g(new A())(a1) // error
+
+val x0 = g(new A()) _
+x0 (new A()) // error
+
+class C[T]
+
+def h(x: A): C[x.type] = ???
+val x = h(a1)
+val y = h(new A())
+
+}
diff --git a/tests/patmat/enum-HList.scala b/tests/patmat/enum-HList.scala
new file mode 100644
index 000000000..c019cb6cc
--- /dev/null
+++ b/tests/patmat/enum-HList.scala
@@ -0,0 +1,22 @@
+enum HLst {
+ case HCons[+Hd, +Tl <: HLst](hd: Hd, tl: Tl)
+ case HNil
+}
+
+object Test {
+ import HLst._
+ def length(hl: HLst): Int = hl match {
+ case HCons(_, tl) => 1 + length(tl)
+ case HNil => 0
+ }
+ def sumInts(hl: HLst): Int = hl match {
+ case HCons(x: Int, tl) => x + sumInts(tl)
+ case HCons(_, tl) => sumInts(tl)
+ case HNil => 0
+ }
+ def main(args: Array[String]) = {
+ val hl = HCons(1, HCons("A", HNil))
+ assert(length(hl) == 2, length(hl))
+ assert(sumInts(hl) == 1)
+ }
+}
diff --git a/tests/patmat/enum-Tree.scala b/tests/patmat/enum-Tree.scala
new file mode 100644
index 000000000..ef5bd7a57
--- /dev/null
+++ b/tests/patmat/enum-Tree.scala
@@ -0,0 +1,29 @@
+enum Tree[T] {
+ case True extends Tree[Boolean]
+ case False extends Tree[Boolean]
+ case Zero extends Tree[Int]
+ case Succ(n: Tree[Int]) extends Tree[Int]
+ case Pred(n: Tree[Int]) extends Tree[Int]
+ case IsZero(n: Tree[Int]) extends Tree[Boolean]
+ case If(cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T])
+}
+
+object Test {
+ import Tree._
+
+ def eval[T](e: Tree[T]): T = e match {
+ case True => true
+ case False => false
+ case Zero => 0
+ case Succ(f) => eval(f) + 1
+ case Pred(f) => eval(f) - 1
+ case IsZero(f) => eval(f) == 0
+ case If(cond, thenp, elsep) => if (eval(cond)) eval(thenp) else eval(elsep)
+ }
+
+ val data = If(IsZero(Pred(Succ(Zero))), Succ(Succ(Zero)), Pred(Pred(Zero)))
+
+ def main(args: Array[String]) = {
+ println(s"$data --> ${eval(data)}")
+ }
+}
diff --git a/tests/patmat/enumColor.scala b/tests/patmat/enumColor.scala
new file mode 100644
index 000000000..60d610d0d
--- /dev/null
+++ b/tests/patmat/enumColor.scala
@@ -0,0 +1,12 @@
+ enum Color {
+ case Red, Green, Blue
+ }
+
+ object Test {
+ def f(color: Color) = {
+ import Color._
+ color match {
+ case Red | Green | Blue =>
+ }
+ }
+}
diff --git a/tests/patmat/patmat-indent.check b/tests/patmat/patmat-indent.check
index 79845ebcf..4f0ec4dd9 100644
--- a/tests/patmat/patmat-indent.check
+++ b/tests/patmat/patmat-indent.check
@@ -1,3 +1,3 @@
9: Pattern Match Exhaustivity: Nil
-23: Pattern Match Exhaustivity: _: Boolean
+23: Pattern Match Exhaustivity: true, false
27: Pattern Match Exhaustivity: _: Int
diff --git a/tests/patmat/patmat-indent.scala b/tests/patmat/patmat-indent.scala
index ef25bb2c7..a2b18e7fb 100644
--- a/tests/patmat/patmat-indent.scala
+++ b/tests/patmat/patmat-indent.scala
@@ -1,5 +1,5 @@
object Test {
- val Nil = scala.Nil
+ val Nil: scala.collection.immutable.Nil.type = scala.collection.immutable.Nil
val X = 5
object Inner {
diff --git a/tests/patmat/planets.scala b/tests/patmat/planets.scala
new file mode 100644
index 000000000..bcbfd7eeb
--- /dev/null
+++ b/tests/patmat/planets.scala
@@ -0,0 +1,26 @@
+enum class Planet(mass: Double, radius: Double) {
+ private final val G = 6.67300E-11
+ def surfaceGravity = G * mass / (radius * radius)
+ def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity
+}
+object Planet {
+ case MERCURY extends Planet(3.303e+23, 2.4397e6)
+ case VENUS extends Planet(4.869e+24, 6.0518e6)
+ case EARTH extends Planet(5.976e+24, 6.37814e6)
+ case MARS extends Planet(6.421e+23, 3.3972e6)
+ case JUPITER extends Planet(1.9e+27, 7.1492e7)
+ case SATURN extends Planet(5.688e+26, 6.0268e7)
+ case URANUS extends Planet(8.686e+25, 2.5559e7)
+ case NEPTUNE extends Planet(1.024e+26, 2.4746e7)
+}
+object Test {
+ def main(args: Array[String]) = {
+ import Planet._
+ assert(enumValueNamed("SATURN") == SATURN)
+ assert(enumValue(2) == EARTH)
+ val earthWeight = 100
+ val mass = earthWeight/EARTH.surfaceGravity
+ for (p <- enumValues)
+ println(s"Your weight on $p is ${p.surfaceWeight(mass)}")
+ }
+}
diff --git a/tests/patmat/t6420.check b/tests/patmat/t6420.check
index 73acf1454..c15701594 100644
--- a/tests/patmat/t6420.check
+++ b/tests/patmat/t6420.check
@@ -1 +1 @@
-5: Pattern Match Exhaustivity: (Nil, _), (List(_, _), _), (Nil, Nil), (Nil, List(_, _)), (List(_, _), Nil), (List(_, _), List(_, _)), (_, Nil), (_, List(_, _))
+5: Pattern Match Exhaustivity: (Nil, _), (List(true, _), _), (List(false, _), _), (_, Nil), (_, List(true, _)), (_, List(false, _))
diff --git a/tests/patmat/t7285.check b/tests/patmat/t7285.check
index 1c2841920..d40b77e4b 100644
--- a/tests/patmat/t7285.check
+++ b/tests/patmat/t7285.check
@@ -1,3 +1,3 @@
15: Pattern Match Exhaustivity: (Up, Down)
33: Pattern Match Exhaustivity: Down
-51: Pattern Match Exhaustivity: (Base.Up, Base.Down)
+51: Pattern Match Exhaustivity: (Up, Down)
diff --git a/tests/patmat/t7466.check b/tests/patmat/t7466.check
index 35227484e..af596399b 100644
--- a/tests/patmat/t7466.check
+++ b/tests/patmat/t7466.check
@@ -1 +1 @@
-8: Pattern Match Exhaustivity: (_, _)
+8: Pattern Match Exhaustivity: (true, _), (false, _), (_, true), (_, false)
diff --git a/tests/pos/i2188.scala b/tests/pos/i2188.scala
new file mode 100644
index 000000000..4129977ac
--- /dev/null
+++ b/tests/pos/i2188.scala
@@ -0,0 +1,5 @@
+class Fill(elem: => Int) {
+ class Iter {
+ def next(): Int = elem
+ }
+}
diff --git a/tests/pos/i2198.scala b/tests/pos/i2198.scala
new file mode 100644
index 000000000..62ae7e8b5
--- /dev/null
+++ b/tests/pos/i2198.scala
@@ -0,0 +1,6 @@
+object Test {
+ val nil = scala.collection.immutable.Nil
+ def f(x: nil.type): Int = 3
+
+ f(scala.collection.immutable.Nil)
+}
diff --git a/tests/pos/i2200/Hello.scala b/tests/pos/i2200/Hello.scala
new file mode 100644
index 000000000..47e8b2024
--- /dev/null
+++ b/tests/pos/i2200/Hello.scala
@@ -0,0 +1,6 @@
+package bar
+import scala.language.higherKinds
+class Fix[F[_]](unfix: F[Fix[F]])
+object DocTree {
+ def docTree(s: StreamTree[DocTree]): DocTree = new Fix(s: StreamTree[DocTree])
+}
diff --git a/tests/pos/i2200/package.scala b/tests/pos/i2200/package.scala
new file mode 100644
index 000000000..3bc519b72
--- /dev/null
+++ b/tests/pos/i2200/package.scala
@@ -0,0 +1,4 @@
+package object bar {
+ type StreamTree[T] = Stream[Int]
+ type DocTree = Fix[StreamTree]
+}
diff --git a/tests/pos/i2218.scala b/tests/pos/i2218.scala
new file mode 100644
index 000000000..fbede8b9b
--- /dev/null
+++ b/tests/pos/i2218.scala
@@ -0,0 +1,9 @@
+trait Rule[In]
+
+class C {
+ def ruleWithName[In](f: In => Int): Rule[In] = {
+ new DefaultRule(f) {}
+ }
+
+ class DefaultRule[In](f: In => Int) extends Rule[In]
+}
diff --git a/tests/pos/i2219.scala b/tests/pos/i2219.scala
new file mode 100644
index 000000000..7f786eb3e
--- /dev/null
+++ b/tests/pos/i2219.scala
@@ -0,0 +1,7 @@
+object Test {
+ type Inv[T[_]] = T[_]
+
+ class Hi[T[_]](x: Inv[T]) {
+ def foo[T[_]](value: Inv[T] = x) = {}
+ }
+}
diff --git a/tests/pending/pos/t7296.scala b/tests/pos/t7296.scala
index fcba17c08..fcba17c08 100644
--- a/tests/pending/pos/t7296.scala
+++ b/tests/pos/t7296.scala
diff --git a/tests/run/1938.scala b/tests/run/1938.scala
new file mode 100644
index 000000000..95e94678d
--- /dev/null
+++ b/tests/run/1938.scala
@@ -0,0 +1,45 @@
+case class Large(
+ e1: Int,
+ e2: Int,
+ e3: Int,
+ e4: Int,
+ e5: Int,
+ e6: Int,
+ e7: Int,
+ e8: Int,
+ e9: Int,
+ e10: Int,
+ e11: Int,
+ e12: Int,
+ e13: Int,
+ e14: Int,
+ e15: Int,
+ e16: Int,
+ e17: Int,
+ e18: Int,
+ e19: Int,
+ e20: Int,
+ e21: Int,
+ e22: Int,
+ e23: Int
+)
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val l = Large(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23)
+
+ assert(l.productArity == 23)
+
+ assert(l.productElement(0) == 1)
+ assert(l.productElement(1) == 2)
+ assert(l.productElement(21) == 22)
+ assert(l.productElement(22) == 23)
+
+ try {
+ l.productElement(23)
+ ???
+ } catch {
+ case e: IndexOutOfBoundsException => assert(e.getMessage == "23")
+ }
+ }
+}
diff --git a/tests/pending/run/case-class-23.check b/tests/run/case-class-23.check
index 888ed2c9e..888ed2c9e 100644
--- a/tests/pending/run/case-class-23.check
+++ b/tests/run/case-class-23.check
diff --git a/tests/pending/run/case-class-23.scala b/tests/run/case-class-23.scala
index a6d78763c..a6d78763c 100644
--- a/tests/pending/run/case-class-23.scala
+++ b/tests/run/case-class-23.scala
diff --git a/tests/run/double-pattern-type.scala b/tests/run/double-pattern-type.scala
new file mode 100644
index 000000000..8045d173b
--- /dev/null
+++ b/tests/run/double-pattern-type.scala
@@ -0,0 +1,40 @@
+case class C1(i: String, s: Int) { def isEmpty = false; def get = ("EMPTY", -1) }
+case class C2(i: String, s: String) { def isEmpty = false; def get = (-1, -2, -3) }
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ // When both Product and name based patterns with same arity are available,
+ // we follow scalac and silently use the Product one:
+
+ val c1 = C1("s", 0)
+ c1 match {
+ case C1(a, b) =>
+ assert(a == "s")
+ assert(b == 0)
+ }
+
+ // When the size differ, both are patterns become usable:
+
+ val c2 = C2("a", "b")
+ c2 match {
+ case C2(a, b) =>
+ assert(a == "a")
+ assert(b == "b")
+ }
+
+ c2 match {
+ case C2(a, b, c) =>
+ assert(a == -1)
+ assert(b == -2)
+ assert(c == -3)
+ }
+
+ // Interestingly things also compile with a single pattern, in which case
+ // the tuple returned by get is binded to `a`:
+
+ c2 match {
+ case C2(a) =>
+ assert(a == (-1, -2, -3))
+ }
+ }
+}
diff --git a/tests/run/enum-Color.scala b/tests/run/enum-Color.scala
index 683d18d9e..f4f6aaef8 100644
--- a/tests/run/enum-Color.scala
+++ b/tests/run/enum-Color.scala
@@ -7,5 +7,9 @@ object Test {
for (color <- Color.enumValues) {
println(s"$color: ${color.enumTag}")
assert(Color.enumValue(color.enumTag) eq color)
+ import Color._
+ color match {
+ case Red | Green | Blue =>
+ }
}
}
diff --git a/tests/run/i2163.scala b/tests/run/i2163.scala
new file mode 100644
index 000000000..952f651e3
--- /dev/null
+++ b/tests/run/i2163.scala
@@ -0,0 +1,21 @@
+class Base(f: Int => Int) {
+ def result = f(3)
+}
+
+class Child(x: Int) extends Base(y => x + y)
+
+class Outer(z: Int) {
+ class Base(f: Int => Int) {
+ def result = f(3)
+ }
+
+ class Child(x: Int) extends Base(y => x + y + z)
+}
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ assert(new Child(4).result == 7)
+ val o = new Outer(2)
+ assert(new o.Child(2).result == 7)
+ }
+}
diff --git a/tests/run/zero-arity-case-class.scala b/tests/run/zero-arity-case-class.scala
new file mode 100644
index 000000000..de0ba4fe1
--- /dev/null
+++ b/tests/run/zero-arity-case-class.scala
@@ -0,0 +1,26 @@
+case class Foo()
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ assert(Foo.unapply(Foo()) == true)
+
+ // unapply generate by scalac are `_ != null`,
+ // dotty returns true in all cases
+ assert(Foo.unapply(null) == true)
+
+ Foo() match {
+ case Foo() => ()
+ case _ => ???
+ }
+
+ Foo() match {
+ case _: Foo => ()
+ case _ => ???
+ }
+
+ (Foo(): Any) match {
+ case Foo() => ()
+ case _ => ???
+ }
+ }
+}