From 11af53faa46fbff5c9e661d98fe3d81bcce2a968 Mon Sep 17 00:00:00 2001 From: "Aaron S. Hawley" Date: Wed, 31 Jul 2019 14:47:32 -0400 Subject: [PATCH 1/6] Escape $ in docs for undefined variables --- .../scala/reflect/quasiquotes/Reifiers.scala | 10 +++---- .../scala/tools/nsc/ScriptRunner.scala | 2 +- .../scala/tools/nsc/ast/TreeGen.scala | 2 +- .../scala/tools/nsc/backend/jvm/BTypes.scala | 4 +-- .../nsc/backend/jvm/analysis/package.scala | 2 +- .../tools/nsc/backend/jvm/opt/BoxUnbox.scala | 18 +++++------ .../nsc/classpath/DirectoryClassPath.scala | 2 +- .../nsc/transform/AccessorSynthesis.scala | 12 ++++---- .../tools/nsc/transform/ExplicitOuter.scala | 8 ++--- .../nsc/transform/ExtensionMethods.scala | 10 +++---- .../scala/tools/nsc/transform/Fields.scala | 16 +++++----- .../tools/nsc/transform/SpecializeTypes.scala | 24 +++++++-------- .../scala/tools/nsc/transform/UnCurry.scala | 12 ++++---- .../nsc/transform/patmat/MatchCodeGen.scala | 2 +- .../tools/nsc/typechecker/EtaExpansion.scala | 6 ++-- .../tools/nsc/typechecker/NamesDefaults.scala | 20 ++++++------- .../scala/tools/nsc/typechecker/Typers.scala | 14 ++++----- .../scala/tools/reflect/ToolBox.scala | 2 +- .../scala/tools/nsc/interactive/Pickler.scala | 2 +- src/library/scala/Console.scala | 14 ++++----- src/library/scala/Option.scala | 2 +- src/library/scala/StringContext.scala | 16 +++++----- .../scala/annotation/implicitAmbiguous.scala | 4 +-- src/library/scala/io/AnsiColor.scala | 2 +- src/library/scala/reflect/ClassTag.scala | 2 +- src/library/scala/util/Either.scala | 14 ++++----- src/library/scala/util/matching/Regex.scala | 30 +++++++++---------- src/reflect/scala/reflect/api/FlagSets.scala | 2 +- src/reflect/scala/reflect/api/Liftables.scala | 6 ++-- src/reflect/scala/reflect/api/TypeTags.scala | 6 ++-- .../scala/reflect/internal/Names.scala | 4 +-- .../scala/reflect/internal/TreeInfo.scala | 6 ++-- .../scala/reflect/internal/Trees.scala | 6 ++-- src/reflect/scala/reflect/macros/Evals.scala | 2 +- .../tools/nsc/doc/model/ModelFactory.scala | 2 +- 35 files changed, 143 insertions(+), 143 deletions(-) diff --git a/src/compiler/scala/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/reflect/quasiquotes/Reifiers.scala index a149862aa052..f316500ec20d 100644 --- a/src/compiler/scala/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/reflect/quasiquotes/Reifiers.scala @@ -48,9 +48,9 @@ trait Reifiers { self: Quasiquotes => * and ends with reified tree: * * { - * val name$1: universe.TermName = universe.build.freshTermName(prefix1) + * val name\$1: universe.TermName = universe.build.freshTermName(prefix1) * ... - * val name$N: universe.TermName = universe.build.freshTermName(prefixN) + * val name\$N: universe.TermName = universe.build.freshTermName(prefixN) * tree * } * @@ -348,9 +348,9 @@ trait Reifiers { self: Quasiquotes => * * Sample execution of previous concrete list reifier: * - * > val lst = List(foo, bar, qq$f3948f9s$1) + * > val lst = List(foo, bar, qq\$f3948f9s\$1) * > reifyHighRankList(lst) { ... } { ... } - * q"List($foo, $bar) ++ ${holeMap(qq$f3948f9s$1).tree}" + * q"List(\$foo, \$bar) ++ \${holeMap(qq\$f3948f9s\$1).tree}" */ def reifyHighRankList(xs: List[Any])(fill: PartialFunction[Any, Tree])(fallback: Any => Tree): Tree @@ -373,7 +373,7 @@ trait Reifiers { self: Quasiquotes => case List(Placeholder(Hole(tree, DotDotDot))) => tree } - /** Reifies arbitrary list filling ..$x and ...$y holeMap when they are put + /** Reifies arbitrary list filling ..\$x and ...\$y holeMap when they are put * in the correct position. Falls back to regular reification for zero rank * elements. */ diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index 79eaba84bb34..e268200f6284 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -24,7 +24,7 @@ import util.Exceptional.unwrap * For example, here is a complete Scala script on Unix: * {{{ * #!/bin/sh - * exec scala "$0" "$@" + * exec scala "\$0" "\$@" * !# * Console.println("Hello, world!") * args.toList foreach Console.println diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 4e13ad3d9f6a..09107b3ba43e 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -148,7 +148,7 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { * * x.asInstanceOf[`pt`] up to phase uncurry * x.asInstanceOf[`pt`]() if after uncurry but before erasure - * x.$asInstanceOf[`pt`]() if at or after erasure + * x.\$asInstanceOf[`pt`]() if at or after erasure */ override def mkCast(tree: Tree, pt: Type): Tree = { debuglog("casting " + tree + ":" + tree.tpe + " to " + pt + " at phase: " + phase) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala index 521f5c471b49..89e8d5f419a3 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala @@ -1098,10 +1098,10 @@ object BTypes { * @param isEffectivelyFinal True if the class cannot have subclasses: final classes, module * classes. * - * @param sam If this class is a SAM type, the SAM's "$name$descriptor". + * @param sam If this class is a SAM type, the SAM's "\$name\$descriptor". * * @param methodInfos The [[MethodInlineInfo]]s for the methods declared in this class. - * The map is indexed by the string s"$name$descriptor" (to + * The map is indexed by the string s"\$name\$descriptor" (to * disambiguate overloads). * * @param warning Contains an warning message if an error occurred when building this diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala index 00702da6cb84..9ba60e975c3a 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala @@ -96,7 +96,7 @@ package scala.tools.nsc.backend.jvm * val m = cn.methods.iterator.asScala.find(_.name == "f").head * * // the value is read from the classfile, so it's 4 - * println(s"maxLocals: ${m.maxLocals}, maxStack: ${m.maxStack}") // maxLocals: 5, maxStack: 4 + * println(s"maxLocals: \${m.maxLocals}, maxStack: \${m.maxStack}") // maxLocals: 5, maxStack: 4 * * // we can safely set it to 2 for running the analyzer. * m.maxStack = 2 diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala index 70866382da06..997cc13b89a9 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala @@ -37,13 +37,13 @@ abstract class BoxUnbox { * f(1, 2) // invokes the generic `apply` * } * - * The closure optimizer re-writes the `apply` call to `anonfun$adapted` method, which takes + * The closure optimizer re-writes the `apply` call to `anonfun\$adapted` method, which takes * boxed arguments. After inlining this method, we get * * def t2 = { * val a = boxByte(1) * val b = boxInteger(2) - * val r = boxInteger(anonfun$(unboxByte(a), unboxInt(b))) + * val r = boxInteger(anonfun\$(unboxByte(a), unboxInt(b))) * unboxInt(r) * } * @@ -166,8 +166,8 @@ abstract class BoxUnbox { * * * Special case for tuples wrt specialization: a tuple getter may box or unbox the value stored - * in the tuple: calling `_1` on a `Tuple2$mcII$sp` boxes the primitive Int stored in the tuple. - * Similarly, calling `_1$mcI$sp` on a non-specialized `Tuple2` unboxes the Integer in the tuple. + * in the tuple: calling `_1` on a `Tuple2\$mcII\$sp` boxes the primitive Int stored in the tuple. + * Similarly, calling `_1\$mcI\$sp` on a non-specialized `Tuple2` unboxes the Integer in the tuple. * When eliminating such getters, we have to introduce appropriate box / unbox calls. * * @@ -629,7 +629,7 @@ abstract class BoxUnbox { /** * If `mi` is an invocation of a method on Predef, check if the receiver is a GETSTATIC of - * Predef.MODULE$ and return it. + * Predef.MODULE\$ and return it. */ def checkReceiverPredefLoad(mi: MethodInsnNode, prodCons: ProdConsAnalyzer): Option[AbstractInsnNode] = { val numArgs = Type.getArgumentTypes(mi.desc).length @@ -913,7 +913,7 @@ abstract class BoxUnbox { /** * If this box consumer extracts a boxed value and applies a conversion, this method returns - * equivalent conversion operations. For example, invoking `_1$mcI$sp` on a non-specialized + * equivalent conversion operations. For example, invoking `_1\$mcI\$sp` on a non-specialized * `Tuple2` extracts the Integer value and unboxes it. */ def postExtractionAdaptationOps(typeOfExtractedValue: Type): List[AbstractInsnNode] = this match { @@ -929,15 +929,15 @@ abstract class BoxUnbox { /** Static extractor (BoxesRunTime.unboxToInt) or GETFIELD or getter invocation */ case class StaticGetterOrInstanceRead(consumer: AbstractInsnNode) extends BoxConsumer - /** A getter that boxes the returned value, e.g., `Tuple2$mcII$sp._1` */ + /** A getter that boxes the returned value, e.g., `Tuple2\$mcII\$sp._1` */ case class PrimitiveBoxingGetter(consumer: MethodInsnNode) extends BoxConsumer - /** A getter that unboxes the returned value, e.g., `Tuple2._1$mcI$sp` */ + /** A getter that unboxes the returned value, e.g., `Tuple2._1\$mcI\$sp` */ case class PrimitiveUnboxingGetter(consumer: MethodInsnNode, unboxedPrimitive: Type) extends BoxConsumer /** An extractor method in a Scala module, e.g., `Predef.Integer2int` */ case class ModuleGetter(moduleLoad: AbstractInsnNode, consumer: MethodInsnNode) extends BoxConsumer /** PUTFIELD or setter invocation */ case class StaticSetterOrInstanceWrite(consumer: AbstractInsnNode) extends BoxConsumer - /** `.$isInstanceOf[T]` (can be statically proven true or false) */ + /** `.\$isInstanceOf[T]` (can be statically proven true or false) */ case class BoxedPrimitiveTypeCheck(consumer: AbstractInsnNode, success: Boolean) extends BoxConsumer /** An unknown box consumer */ case class EscapingConsumer(consumer: AbstractInsnNode) extends BoxConsumer diff --git a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala index 6ecae9a7ca18..da69060b4664 100644 --- a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala +++ b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala @@ -231,7 +231,7 @@ final class JrtClassPath(fs: java.nio.file.FileSystem) extends ClassPath with No } /** - * Implementation `ClassPath` based on the $JAVA_HOME/lib/ct.sym backing http://openjdk.java.net/jeps/247 + * Implementation `ClassPath` based on the \$JAVA_HOME/lib/ct.sym backing http://openjdk.java.net/jeps/247 */ final class CtSymClassPath(ctSym: java.nio.file.Path, release: Int) extends ClassPath with NoSourcePaths with Closeable { import java.nio.file.Path, java.nio.file._ diff --git a/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala b/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala index 1ecaf61e96c6..8e26e3689af3 100644 --- a/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala +++ b/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala @@ -257,22 +257,22 @@ trait AccessorSynthesis extends Transform with ast.TreeDSL { * The compute method (slow path) looks like: * * ``` - * def l$compute() = { + * def l\$compute() = { * synchronized(this) { - * if ((bitmap$n & MASK) == 0) { - * init // l$ = - * bitmap$n = bimap$n | MASK + * if ((bitmap\$n & MASK) == 0) { + * init // l\$ = + * bitmap\$n = bimap\$n | MASK * } * } * ... * this.f1 = null * ... * this.fn = null - * l$ + * l\$ * } * ``` * - * `bitmap$n` is a byte, int or long value acting as a bitmap of initialized values. + * `bitmap\$n` is a byte, int or long value acting as a bitmap of initialized values. * The kind of the bitmap determines how many bit indicators for lazy vals are stored in it. * For Int bitmap it is 32 and then 'n' in the above code is: (offset / 32), * the MASK is (1 << (offset % 32)). diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 1412c2088f91..8c92ab05c0d9 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -134,12 +134,12 @@ abstract class ExplicitOuter extends InfoTransform * in an inner non-trait class; * *
  • - * Add a protected $outer field to an inner class which is + * Add a protected \$outer field to an inner class which is * not a trait. *
  • *
  • *

    - * Add an outer accessor $outer$$C to every inner class + * Add an outer accessor \$outer\$\$C to every inner class * with fully qualified name C that is not an interface. * The outer accessor is abstract for traits, concrete for other * classes. @@ -300,9 +300,9 @@ abstract class ExplicitOuter extends InfoTransform * (4) A constructor of a non-trait inner class gets an outer parameter. * * (5) A reference C.this where C refers to an outer class is replaced by a selection - * `this.$outer$$C1 ... .$outer$$Cn` (@see outerPath) + * `this.\$outer\$\$C1 ... .\$outer\$\$Cn` (@see outerPath) * - * (7) A call to a constructor Q.(args) or Q.$init$(args) where Q != this and + * (7) A call to a constructor Q.(args) or Q.\$init\$(args) where Q != this and * the constructor belongs to a non-static class is augmented by an outer argument. * E.g. Q.(OUTER, args) where OUTER * is the qualifier corresponding to the singleton type Q. diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index 73766c570fd6..a8621a0da282 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -97,10 +97,10 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { /** Recognize a MethodType which represents an extension method. * - * It may have a curried parameter list with the `$this` alone in the first + * It may have a curried parameter list with the `\$this` alone in the first * parameter list, in which case that parameter list is dropped. Or, since * the curried lists disappear during uncurry, it may have a single parameter - * list with `$this` as the first parameter, in which case that parameter is + * list with `\$this` as the first parameter, in which case that parameter is * removed from the list. */ object ExtensionMethodType { @@ -112,9 +112,9 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { } } - /** This method removes the `$this` argument from the parameter list a method. + /** This method removes the `\$this` argument from the parameter list a method. * - * A method may be a `PolyType`, in which case we tear out the `$this` and the class + * A method may be a `PolyType`, in which case we tear out the `\$this` and the class * type params from its nested `MethodType`. Or it may be a MethodType, as * described at the ExtensionMethodType extractor. */ @@ -150,7 +150,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { * def baz[B >: A](x: B): List[B] = x :: xs * // baz has to be transformed into this extension method, where * // A is cloned from class Foo and B is cloned from method baz: - * // def extension$baz[B >: A <: Any, A >: Nothing <: AnyRef]($this: Foo[A])(x: B): List[B] + * // def extension\$baz[B >: A <: Any, A >: Nothing <: AnyRef](\$this: Foo[A])(x: B): List[B] * } * * TODO: factor out the logic for consolidating type parameters from a class diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index cc737e808e48..97230a0b372f 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -52,7 +52,7 @@ import symtab.Flags._ * * * In the future, would like to get closer to dotty, which lifts a val's RHS (a similar thing is done for template-level statements) - * to a method `$_initialize_$1$x` instead of a block, which is used in the constructor to initialize the val. + * to a method `\$_initialize_\$1\$x` instead of a block, which is used in the constructor to initialize the val. * This makes for a nice unification of strict and lazy vals, in that the RHS is lifted to a method for both, * with the corresponding compute method called at the appropriate time.) * @@ -562,17 +562,17 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor * or a local `object x { ...}` (the rhs will be instantiating the module's class) into: * * ``` - * val x$lzy = new scala.runtime.LazyInt() - * def x$lzycompute(): Int = - * x$lzy.synchronized { - * if (x$lzy.initialized()) x$lzy.value() - * else x$lzy.initialize(rhs) // for a Unit-typed lazy val, this becomes `{ rhs ; x$lzy.initialize() }` to avoid passing around BoxedUnit + * val x\$lzy = new scala.runtime.LazyInt() + * def x\$lzycompute(): Int = + * x\$lzy.synchronized { + * if (x\$lzy.initialized()) x\$lzy.value() + * else x\$lzy.initialize(rhs) // for a Unit-typed lazy val, this becomes `{ rhs ; x\$lzy.initialize() }` to avoid passing around BoxedUnit * } - * def x(): Int = if (x$lzy.initialized()) x$lzy.value() else x$lzycompute() + * def x(): Int = if (x\$lzy.initialized()) x\$lzy.value() else x\$lzycompute() * ``` * * The expansion is the same for local lazy vals and local objects, - * except for the suffix of the underlying val's name ($lzy or $module) + * except for the suffix of the underlying val's name (\$lzy or \$module) */ private def mkLazyLocalDef(lazySym: Symbol, rhs: Tree): Tree = { import CODE._ diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index dee93f362444..2baf02cb0a14 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -46,13 +46,13 @@ import scala.collection.{immutable, mutable} * Specialization will generate a specialized class and a specialized method: * * {{{ - * class A$mcI$sp(protected val d: Int) extends A[Int] { - * def foo(that: A[Int]) = foo$mcI$sp(that) + * class A\$mcI\$sp(protected val d: Int) extends A[Int] { + * def foo(that: A[Int]) = foo\$mcI\$sp(that) * def foo(that: A[Int]) = that.d * } * }}} * - * Above, `A$mcI$sp` cannot access `d`, so the method cannot be typechecked. + * Above, `A\$mcI\$sp` cannot access `d`, so the method cannot be typechecked. */ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { import global._ @@ -557,7 +557,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * Non-specialized type parameters are cloned into new ones. * Type parameters specialized on AnyRef have preexisting symbols. * - * For instance, a @specialized(AnyRef) T, will become T$sp <: AnyRef. + * For instance, a @specialized(AnyRef) T, will become T\$sp <: AnyRef. */ def produceTypeParameters(syms: List[Symbol], nowner: Symbol, env: TypeEnv) = { val cloned = for (s <- syms) yield if (!env.contains(s)) s.cloneSymbol(nowner) else env(s).typeSymbol @@ -887,8 +887,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * * Given method m[@specialized T, U](x: T, y: U) it returns * m[T, U](x: T, y: U), - * m$I[ U](x: Int, y: U), - * m$D[ U](x: Double, y: U) + * m\$I[ U](x: Int, y: U), + * m\$D[ U](x: Double, y: U) * // etc. */ private def normalizeMember(owner: Symbol, sym: Symbol, outerEnv: TypeEnv): List[Symbol] = { @@ -1019,7 +1019,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * def apply(x: Int): Int = .. * } * - * this method will return List('apply$mcII$sp') + * this method will return List('apply\$mcII\$sp') */ private def specialOverrides(clazz: Symbol) = logResultIf[List[Symbol]]("specialized overrides in " + clazz, _.nonEmpty) { /* Return the overridden symbol in syms that needs a specialized overriding symbol, @@ -1387,7 +1387,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * def spec_method[@specialized(Int) T](t: T, expectedXSuper: String) = { * class X extends Parent[T]() * // even in the specialized variant, the local X class - * // doesn't extend Parent$mcI$sp, since its symbol has + * // doesn't extend Parent\$mcI\$sp, since its symbol has * // been created after specialization and was not seen * // by specialization's info transformer. * ... @@ -1591,7 +1591,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Computes residual type parameters after rewiring, like "String" in the following example: * ``` * def specMe[@specialized T, U](t: T, u: U) = ??? - * specMe[Int, String](1, "2") => specMe$mIc$sp[String](1, "2") + * specMe[Int, String](1, "2") => specMe\$mIc\$sp[String](1, "2") * ``` */ def computeResidualTypeVars(baseTree: Tree, specMember: Symbol, specTree: Tree, baseTargs: List[Tree], env: TypeEnv): Tree = { @@ -1992,9 +1992,9 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * {{{ * case class Tuple2[T, U](x: T, y: U) * - * class Tuple2$II { - * val _x$I: Int = .. - * def x = _x$I + * class Tuple2\$II { + * val _x\$I: Int = .. + * def x = _x\$I * // same for y * def this(x: Int, y: Int) { * super.this(null.asInstanceOf[Int], null.asInstanceOf[Int]) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index b85842b26fee..a04c03f706f4 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -51,8 +51,8 @@ import scala.reflect.internal.util.ListOfNil * * meth(x_1,..., try { x_i } catch { ..}, .. x_b0) ==> * { - * def liftedTry$1 = try { x_i } catch { .. } - * meth(x_1, .., liftedTry$1(), .. ) + * def liftedTry\$1 = try { x_i } catch { .. } + * meth(x_1, .., liftedTry\$1(), .. ) * } * - remove calls to elidable methods and replace their bodies with NOPs when elide-below * requires it @@ -210,10 +210,10 @@ abstract class UnCurry extends InfoTransform /** Transform a function node (x_1,...,x_n) => body of type FunctionN[T_1, .., T_N, R] to * - * class $anon() extends AbstractFunctionN[T_1, .., T_N, R] with Serializable { + * class \$anon() extends AbstractFunctionN[T_1, .., T_N, R] with Serializable { * def apply(x_1: T_1, ..., x_N: T_n): R = body * } - * new $anon() + * new \$anon() * */ def transformFunction(fun: Function): Tree = @@ -382,7 +382,7 @@ abstract class UnCurry extends InfoTransform * mark the method symbol SYNCHRONIZED for bytecode generation. * * Delambdafy targets are deemed ineligible as the Delambdafy phase will - * replace `this.synchronized` with `$this.synchronized` now that it emits + * replace `this.synchronized` with `\$this.synchronized` now that it emits * all lambda impl methods as static. */ private def translateSynchronized(tree: Tree) = tree match { @@ -668,7 +668,7 @@ abstract class UnCurry extends InfoTransform * For the example above, this results in: * * {{{ - * def foo(a: A, b: a.B forSome { val a: A }): a.B = { val b$1 = b.asInstanceOf[a.B]; b$1; b$1 } + * def foo(a: A, b: a.B forSome { val a: A }): a.B = { val b\$1 = b.asInstanceOf[a.B]; b\$1; b\$1 } * }}} */ private object dependentParamTypeErasure { diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala index 440fdf34751b..88cf43ae85ce 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala @@ -156,7 +156,7 @@ trait MatchCodeGen extends Interface { /** Inline runOrElse and get rid of Option allocations * - * runOrElse(scrut: scrutTp)(matcher): resTp = matcher(scrut) getOrElse ${catchAll(`scrut`)} + * runOrElse(scrut: scrutTp)(matcher): resTp = matcher(scrut) getOrElse \${catchAll(`scrut`)} * the matcher's optional result is encoded as a flag, keepGoing, where keepGoing == true encodes result.isEmpty, * if keepGoing is false, the result Some(x) of the naive translation is encoded as matchRes == x */ diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala index 0a3b07e10e45..44d0fe15dd1f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala +++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala @@ -32,11 +32,11 @@ trait EtaExpansion { self: Analyzer => * * ``` * { - * private synthetic val eta$f = p.f // if p is not stable + * private synthetic val eta\$f = p.f // if p is not stable * ... - * private synthetic val eta$e_i = e_i // if e_i is not stable + * private synthetic val eta\$e_i = e_i // if e_i is not stable * ... - * (ps_1 => ... => ps_m => eta$f([es_1])...([es_m])(ps_1)...(ps_m)) + * (ps_1 => ... => ps_m => eta\$f([es_1])...([es_m])(ps_1)...(ps_m)) * } * ``` * diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 784c98ddcbcc..9d1856f8c930 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -95,22 +95,22 @@ trait NamesDefaults { self: Analyzer => * first the function "fun" (which might be an application itself!) is transformed into a * block of the form * { - * val qual$1 = qualifier_of_fun - * val x$1 = arg_1_of_fun + * val qual\$1 = qualifier_of_fun + * val x\$1 = arg_1_of_fun * ... - * val x$n = arg_n_of_fun - * qual$1.fun[targs](x$1, ...)...(..., x$n) + * val x\$n = arg_n_of_fun + * qual\$1.fun[targs](x\$1, ...)...(..., x\$n) * } * then for each argument in args, a value is created and entered into the block. finally * the application expression of the block is updated. * { - * val qual$1 = .. + * val qual\$1 = .. * ... - * val x$n = ... - * > val qual$n+1 = arg(1) + * val x\$n = ... + * > val qual\$n+1 = arg(1) * > ... - * > val qual$n+m = arg(m) - * > qual$1.fun[targs](x$1, ...)...(..., x$n)(x$n+1, ..., x$n+m) + * > val qual\$n+m = arg(m) + * > qual\$1.fun[targs](x\$1, ...)...(..., x\$n)(x\$n+1, ..., x\$n+m) * } * * @param typer the typer calling this method; this method calls @@ -437,7 +437,7 @@ trait NamesDefaults { self: Analyzer => * Example: given * def foo(x: Int = 2, y: String = "def") * foo(y = "lt") - * the argument list (y = "lt") is transformed to (y = "lt", x = foo$default$1()) + * the argument list (y = "lt") is transformed to (y = "lt", x = foo\$default\$1()) */ def addDefaults(givenArgs: List[Tree], qual: Option[Tree], targs: List[Tree], previousArgss: List[List[Tree]], params: List[Symbol], diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 4f4610d99811..96aa2c467766 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2603,11 +2603,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper * * `param => sel match { cases }` becomes: * - * new AbstractPartialFunction[$argTp, $matchResTp] { - * def applyOrElse[A1 <: $argTp, B1 >: $matchResTp]($param: A1, default: A1 => B1): B1 = - * $selector match { $cases } - * def isDefinedAt(x: $argTp): Boolean = - * $selector match { $casesTrue } + * new AbstractPartialFunction[\$argTp, \$matchResTp] { + * def applyOrElse[A1 <: \$argTp, B1 >: \$matchResTp](\$param: A1, default: A1 => B1): B1 = + * \$selector match { \$cases } + * def isDefinedAt(x: \$argTp): Boolean = + * \$selector match { \$casesTrue } * } * * TODO: it would be nicer to generate the tree specified above at once and type it as a whole, @@ -2846,8 +2846,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper * * ``` * new S { - * def apply$body(p1: T1, ..., pN: TN): T = body - * def apply(p1: T1', ..., pN: TN'): T' = apply$body(p1,..., pN) + * def apply\$body(p1: T1, ..., pN: TN): T = body + * def apply(p1: T1', ..., pN: TN'): T' = apply\$body(p1,..., pN) * } * ``` * diff --git a/src/compiler/scala/tools/reflect/ToolBox.scala b/src/compiler/scala/tools/reflect/ToolBox.scala index 1e31f2fcfdc7..b7d151fed6ba 100644 --- a/src/compiler/scala/tools/reflect/ToolBox.scala +++ b/src/compiler/scala/tools/reflect/ToolBox.scala @@ -133,7 +133,7 @@ trait ToolBox[U <: scala.reflect.api.Universe] { * For a ClassDef, a ClassSymbol is returned, and for a ModuleDef, a ModuleSymbol is returned (not a module class, but a module itself). * * This method can be used to generate definitions that will later be re-used by subsequent calls to - * `compile`, `define` or `eval`. To refer to the generated definition in a tree, use q"$sym". + * `compile`, `define` or `eval`. To refer to the generated definition in a tree, use q"\$sym". */ def define(tree: u.ImplDef): u.Symbol diff --git a/src/interactive/scala/tools/nsc/interactive/Pickler.scala b/src/interactive/scala/tools/nsc/interactive/Pickler.scala index 13c1d3d88811..c125fa3fff8a 100644 --- a/src/interactive/scala/tools/nsc/interactive/Pickler.scala +++ b/src/interactive/scala/tools/nsc/interactive/Pickler.scala @@ -247,7 +247,7 @@ object Pickler { .cond (x eq _.asInstanceOf[AnyRef]) /** A pickler the handles instances of classes that have an empty constructor. - * It represents than as `$new ( )`. + * It represents than as `\$new ( )`. * When unpickling, a new instance of the class is created using the empty * constructor of the class via `Class.forName().newInstance()`. */ diff --git a/src/library/scala/Console.scala b/src/library/scala/Console.scala index 399642fbcdbd..e02a86ae2e11 100644 --- a/src/library/scala/Console.scala +++ b/src/library/scala/Console.scala @@ -45,9 +45,9 @@ import scala.util.DynamicVariable * val prime = (2 to candidate - 1).forall(candidate % _ != 0) * * if (prime) - * Console.println(s"${RESET}${GREEN}yes${RESET}") + * Console.println(s"\${RESET}\${GREEN}yes\${RESET}") * else - * Console.err.println(s"${RESET}${YELLOW_B}${RED}${UNDERLINED}NO!${RESET}") + * Console.err.println(s"\${RESET}\${YELLOW_B}\${RED}\${UNDERLINED}NO!\${RESET}") * } * * def main(args: Array[String]): Unit = isPrime() @@ -56,10 +56,10 @@ import scala.util.DynamicVariable * }}} * * - * + * * * - * + * * * *
    $ scala PrimeTest
    \$ scala PrimeTest
    1234567891
    yes
    $ scala PrimeTest
    \$ scala PrimeTest
    56474
    NO!
    @@ -76,7 +76,7 @@ import scala.util.DynamicVariable * * def isPrime(candidate: Int): Boolean = { * - * val input = new StringReader(s"$candidate\n") + * val input = new StringReader(s"\$candidate\n") * val outCapture = new ByteArrayOutputStream * val errCapture = new ByteArrayOutputStream * @@ -97,7 +97,7 @@ import scala.util.DynamicVariable * * def main(args: Array[String]): Unit = { * val primes = (2 to 50) filter (isPrime) - * println(s"First primes: $primes") + * println(s"First primes: \$primes") * } * * } @@ -105,7 +105,7 @@ import scala.util.DynamicVariable * * * - * + * * *
    $ scala FunctionalPrimeTest
    \$ scala FunctionalPrimeTest
    First primes: Vector(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47)
    * diff --git a/src/library/scala/Option.scala b/src/library/scala/Option.scala index 3ee6582f9772..08a108b6b7b3 100644 --- a/src/library/scala/Option.scala +++ b/src/library/scala/Option.scala @@ -99,7 +99,7 @@ object Option { * bMaybe = Option(abc.get(2)) * bMaybe match { * case Some(b) => - * println(s"Found $b") + * println(s"Found \$b") * case None => * println("Not found") * } diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala index c592e232995e..68ff6e09a886 100644 --- a/src/library/scala/StringContext.scala +++ b/src/library/scala/StringContext.scala @@ -21,13 +21,13 @@ import scala.annotation.tailrec * Here's an example: * {{{ * val name = "James" - * println(s"Hello, $name") // Hello, James + * println(s"Hello, \$name") // Hello, James * }}} * * Any processed string literal is rewritten as an instantiation and * method call against this class. For example: * {{{ - * s"Hello, $name" + * s"Hello, \$name" * }}} * * is rewritten to be: @@ -45,7 +45,7 @@ import scala.annotation.tailrec * implicit class JsonHelper(private val sc: StringContext) extends AnyVal { * def json(args: Any*): JSONObject = ... * } - * val x: JSONObject = json"{ a: $a }" + * val x: JSONObject = json"{ a: \$a }" * }}} * * Here the `JsonHelper` extension class implicitly adds the `json` method to @@ -77,14 +77,14 @@ case class StringContext(parts: String*) { * Here's an example of usage: * {{{ * val name = "James" - * println(s"Hello, $name") // Hello, James + * println(s"Hello, \$name") // Hello, James * }}} - * In this example, the expression $name is replaced with the `toString` of the + * In this example, the expression \$name is replaced with the `toString` of the * variable `name`. * The `s` interpolator can take the `toString` of any arbitrary expression within - * a `${}` block, for example: + * a `\${}` block, for example: * {{{ - * println(s"1 + 1 = ${1 + 1}") + * println(s"1 + 1 = \${1 + 1}") * }}} * will print the string `1 + 1 = 2`. * @@ -149,7 +149,7 @@ case class StringContext(parts: String*) { * {{{ * val height = 1.9d * val name = "James" - * println(f"$name%s is $height%2.2f meters tall") // James is 1.90 meters tall + * println(f"\$name%s is \$height%2.2f meters tall") // James is 1.90 meters tall * }}} * * @param `args` The arguments to be inserted into the resulting string. diff --git a/src/library/scala/annotation/implicitAmbiguous.scala b/src/library/scala/annotation/implicitAmbiguous.scala index aaf091e27f33..c522413a77fe 100644 --- a/src/library/scala/annotation/implicitAmbiguous.scala +++ b/src/library/scala/annotation/implicitAmbiguous.scala @@ -17,7 +17,7 @@ package scala.annotation * multiple ambiguous values, annotate at least one of the implicit values * `@implicitAmbiguous`. Assuming the implicit value is a method with type * parameters `X1,..., XN`, the error message will be the result of replacing - * all occurrences of `${Xi}` in the string `msg` with the string representation + * all occurrences of `\${Xi}` in the string `msg` with the string representation * of the corresponding type argument `Ti`. * * If more than one `@implicitAmbiguous` annotation is collected, the compiler is @@ -31,7 +31,7 @@ package scala.annotation * * implicit def neq[E, F] : E =!= F = null * - * @annotation.implicitAmbiguous("Could not prove ${J} =!= ${J}") + * @annotation.implicitAmbiguous("Could not prove \${J} =!= \${J}") * implicit def neqAmbig1[G, H, J] : J =!= J = null * implicit def neqAmbig2[I] : I =!= I = null * diff --git a/src/library/scala/io/AnsiColor.scala b/src/library/scala/io/AnsiColor.scala index 161188b4a6c1..906f1098d0ce 100644 --- a/src/library/scala/io/AnsiColor.scala +++ b/src/library/scala/io/AnsiColor.scala @@ -25,7 +25,7 @@ package io * * object ColorDemo extends App { * - * println(s"${REVERSED}${BOLD}Hello 1979!${RESET}") + * println(s"\${REVERSED}\${BOLD}Hello 1979!\${RESET}") * } * }}} * diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index 3d0bc31faf61..0901658fbc49 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -30,7 +30,7 @@ import java.lang.{ Class => jClass } * For example: * {{{ * scala> def mkArray[T : ClassTag](elems: T*) = Array[T](elems: _*) - * mkArray: [T](elems: T*)(implicit evidence$1: scala.reflect.ClassTag[T])Array[T] + * mkArray: [T](elems: T*)(implicit evidence\$1: scala.reflect.ClassTag[T])Array[T] * * scala> mkArray(42, 13) * res0: Array[Int] = Array(42, 13) diff --git a/src/library/scala/util/Either.scala b/src/library/scala/util/Either.scala index 8fec3a409660..d330fe52e572 100644 --- a/src/library/scala/util/Either.scala +++ b/src/library/scala/util/Either.scala @@ -35,8 +35,8 @@ package util * } * * result match { - * case Right(x) => s"You passed me the Int: $x, which I will increment. $x + 1 = ${x+1}" - * case Left(x) => s"You passed me the String: $x" + * case Right(x) => s"You passed me the Int: \$x, which I will increment. \$x + 1 = \${x+1}" + * case Left(x) => s"You passed me the String: \$x" * } * }}} * @@ -159,10 +159,10 @@ sealed abstract class Either[+A, +B] extends Product with Serializable { * val report = for (result <- interactWithDB(someQuery)) yield generateReport(result) * report match { * case Right(r) => send(r) - * case Left(e) => log(s"report not generated, reason was $e") + * case Left(e) => log(s"report not generated, reason was \$e") * } * // only report errors - * for (e <- interactWithDB(someQuery).left) log(s"query failed, reason was $e") + * for (e <- interactWithDB(someQuery).left) log(s"query failed, reason was \$e") * }}} */ def left = Either.LeftProjection(this) @@ -178,8 +178,8 @@ sealed abstract class Either[+A, +B] extends Product with Serializable { * @example {{{ * val result = util.Try("42".toInt).toEither * result.fold( - * e => s"Operation failed with $e", - * v => s"Operation produced value: $v" + * e => s"Operation failed with \$e", + * v => s"Operation produced value: \$v" * ) * }}} * @@ -452,7 +452,7 @@ object Either { * Either.cond( * userInput.forall(_.isDigit) && userInput.size == 10, * PhoneNumber(userInput), - * s"The input ($userInput) does not look like a phone number" + * s"The input (\$userInput) does not look like a phone number" * }}} */ def cond[A, B](test: Boolean, right: => B, left: => A): Either[A, B] = diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala index 4614bf5bf658..6e256fe67771 100644 --- a/src/library/scala/util/matching/Regex.scala +++ b/src/library/scala/util/matching/Regex.scala @@ -59,7 +59,7 @@ import java.util.regex.{ Pattern, Matcher } * * {{{ * "2004-01-20" match { - * case date(year, month, day) => s"$year was a good year for PLs." + * case date(year, month, day) => s"\$year was a good year for PLs." * } * }}} * @@ -78,7 +78,7 @@ import java.util.regex.{ Pattern, Matcher } * * {{{ * "2004-01-20" match { - * case date(year, _*) => s"$year was a good year for PLs." + * case date(year, _*) => s"\$year was a good year for PLs." * } * }}} * @@ -121,7 +121,7 @@ import java.util.regex.{ Pattern, Matcher } * val mi = date.findAllIn(dates) * while (mi.hasNext) { * val d = mi.next - * if (mi.group(1).toInt < 1960) println(s"$d: An oldie but goodie.") + * if (mi.group(1).toInt < 1960) println(s"\$d: An oldie but goodie.") * } * }}} * @@ -165,8 +165,8 @@ import java.util.regex.{ Pattern, Matcher } * {{{ * val redacted = date.replaceAllIn(dates, "XXXX-XX-XX") * val yearsOnly = date.replaceAllIn(dates, m => m.group(1)) - * val months = (0 to 11).map { i => val c = Calendar.getInstance; c.set(2014, i, 1); f"$c%tb" } - * val reformatted = date.replaceAllIn(dates, _ match { case date(y,m,d) => f"${months(m.toInt - 1)} $d, $y" }) + * val months = (0 to 11).map { i => val c = Calendar.getInstance; c.set(2014, i, 1); f"\$c%tb" } + * val reformatted = date.replaceAllIn(dates, _ match { case date(y,m,d) => f"\${months(m.toInt - 1)} \$d, \$y" }) * }}} * * Pattern matching the `Match` against the `Regex` that created it does not reapply the `Regex`. @@ -191,7 +191,7 @@ import java.util.regex.{ Pattern, Matcher } * @param groupNames A mapping from names to indices in capture groups * * @define replacementString - * In the replacement String, a dollar sign (`$`) followed by a number will be + * In the replacement String, a dollar sign (`\$`) followed by a number will be * interpreted as a reference to a group in the matched pattern, with numbers * 1 through 9 corresponding to the first nine groups, and 0 standing for the * whole match. Any other character is an error. The backslash (`\`) character @@ -380,7 +380,7 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends * {{{ * val madhatter = "(h)(?=(at[^a]+))".r * val madhats = madhatter.findAllMatchIn(hathaway).map { - * case madhatter(x,y) => s"$x$y" + * case madhatter(x,y) => s"\$x\$y" * }.toList // List(hath, hatth, hattth, hatttt) * }}} * @@ -494,7 +494,7 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends * import scala.util.matching.Regex * val datePattern = new Regex("""(\d\d\d\d)-(\d\d)-(\d\d)""", "year", "month", "day") * val text = "From 2011-07-15 to 2011-07-17" - * val repl = datePattern replaceAllIn (text, m => s"${m group "month"}/${m group "day"}") + * val repl = datePattern replaceAllIn (text, m => s"\${m group "month"}/\${m group "day"}") * }}} * * $replacementString @@ -517,7 +517,7 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends * {{{ * import scala.util.matching.Regex._ * - * val vars = Map("x" -> "a var", "y" -> """some $ and \ signs""") + * val vars = Map("x" -> "a var", "y" -> """some \$ and \ signs""") * val text = "A text with variables %x, %y and %z." * val varPattern = """%(\w+)""".r * val mapper = (m: Match) => vars get (m group 1) map (quoteReplacement(_)) @@ -564,7 +564,7 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends * the entire String matches in extractor patterns. * * Normally, matching on `date` behaves as though the pattern were - * enclosed in anchors, `"^pattern$"`. + * enclosed in anchors, `"^pattern\$"`. * * The unanchored `Regex` behaves as though those anchors were removed. * @@ -578,7 +578,7 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends * val date(year, month, day) = "Date 2011-07-15" // OK * * val copyright: String = "Date of this document: 2011-07-15" match { - * case date(year, month, day) => s"Copyright $year" // OK + * case date(year, month, day) => s"Copyright \$year" // OK * case _ => "No copyright" * } * }}} @@ -766,7 +766,7 @@ object Regex { * * val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r * val text = "The doc spree happened on 2011-07-15." - * val day = date replaceAllIn(text, _ match { case Groups(_, month, day) => s"$month/$day" }) + * val day = date replaceAllIn(text, _ match { case Groups(_, month, day) => s"\$month/\$day" }) * }}} */ object Groups { @@ -904,21 +904,21 @@ object Regex { * * All regex metacharacters in the input match themselves literally in the output. * - * @example {{{List("US$", "CAN$").map(Regex.quote).mkString("|").r}}} + * @example {{{List("US\$", "CAN\$").map(Regex.quote).mkString("|").r}}} */ def quote(text: String): String = Pattern quote text /** Quotes replacement strings to be used in replacement methods. * * Replacement methods give special meaning to backslashes (`\`) and - * dollar signs (`$`) in replacement strings, so they are not treated + * dollar signs (`\$`) in replacement strings, so they are not treated * as literals. This method escapes these characters so the resulting * string can be used as a literal replacement representing the input * string. * * @param text The string one wishes to use as literal replacement. * @return A string that can be used to replace matches with `text`. - * @example {{{"CURRENCY".r.replaceAllIn(input, Regex quoteReplacement "US$")}}} + * @example {{{"CURRENCY".r.replaceAllIn(input, Regex quoteReplacement "US\$")}}} */ def quoteReplacement(text: String): String = Matcher quoteReplacement text } diff --git a/src/reflect/scala/reflect/api/FlagSets.scala b/src/reflect/scala/reflect/api/FlagSets.scala index a571398d9196..a8116613354b 100644 --- a/src/reflect/scala/reflect/api/FlagSets.scala +++ b/src/reflect/scala/reflect/api/FlagSets.scala @@ -245,7 +245,7 @@ trait FlagSets { self: Universe => /** Flag used to distinguish platform-specific implementation details. * Trees and symbols which are currently marked ARTIFACT by scalac: - * * $outer fields and accessors + * * \$outer fields and accessors * * super accessors * * protected accessors * * lazy local accessors diff --git a/src/reflect/scala/reflect/api/Liftables.scala b/src/reflect/scala/reflect/api/Liftables.scala index 5bccb63b4aae..14b4acffc868 100644 --- a/src/reflect/scala/reflect/api/Liftables.scala +++ b/src/reflect/scala/reflect/api/Liftables.scala @@ -38,9 +38,9 @@ trait Liftables { self: Universe => * * scala> val Oref = symbolOf[O.type].asClass.module * - * scala> implicit val liftO = Liftable[O.type] { _ => q"$Oref" } + * scala> implicit val liftO = Liftable[O.type] { _ => q"\$Oref" } * - * scala> val lifted = q"$O" + * scala> val lifted = q"\$O" * lifted: universe.Tree = O * }}} * @@ -75,7 +75,7 @@ trait Liftables { self: Universe => * * scala> implicit val unliftO = Unliftable[O.type] { case t if t.symbol == Oref => O } * - * scala> val q"${_: O.type}" = q"$Oref" + * scala> val q"\${_: O.type}" = q"\$Oref" * }}} * * @see [[http://docs.scala-lang.org/overviews/quasiquotes/unlifting.html]] diff --git a/src/reflect/scala/reflect/api/TypeTags.scala b/src/reflect/scala/reflect/api/TypeTags.scala index f61ca3862760..6e0f5427906f 100644 --- a/src/reflect/scala/reflect/api/TypeTags.scala +++ b/src/reflect/scala/reflect/api/TypeTags.scala @@ -66,7 +66,7 @@ import java.io.ObjectStreamException * * def paramInfo[T](x: T)(implicit tag: TypeTag[T]): Unit = { * val targs = tag.tpe match { case TypeRef(_, _, args) => args } - * println(s"type of $x has type arguments $targs") + * println(s"type of \$x has type arguments \$targs") * } * * scala> paramInfo(42) @@ -85,7 +85,7 @@ import java.io.ObjectStreamException * * def paramInfo[T: TypeTag](x: T): Unit = { * val targs = typeOf[T] match { case TypeRef(_, _, args) => args } - * println(s"type of $x has type arguments $targs") + * println(s"type of \$x has type arguments \$targs") * } * * scala> paramInfo(42) @@ -107,7 +107,7 @@ import java.io.ObjectStreamException * {{{ * def weakParamInfo[T](x: T)(implicit tag: WeakTypeTag[T]): Unit = { * val targs = tag.tpe match { case TypeRef(_, _, args) => args } - * println(s"type of $x has type arguments $targs") + * println(s"type of \$x has type arguments \$targs") * } * * scala> def foo[T] = weakParamInfo(List[T]()) diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index d22b6f203c07..95ce05790489 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -100,7 +100,7 @@ trait Names extends api.Names { /** Create a term name from the characters in cs[offset..offset+len-1]. * TODO - have a mode where name validation is performed at creation time - * (e.g. if a name has the string "$class" in it, then fail if that + * (e.g. if a name has the string "\$class" in it, then fail if that * string is not at the very end.) * * @param len0 the length of the name. Negative lengths result in empty names. @@ -487,7 +487,7 @@ trait Names extends api.Names { implicit def TypeNameOps(name: TypeName): NameOps[TypeName] = new NameOps(name) /** FIXME: This is a good example of something which is pure "value class" but cannot - * reap the benefits because an (unused) $outer pointer so it is not single-field. + * reap the benefits because an (unused) \$outer pointer so it is not single-field. */ final class NameOps[T <: Name](name: T) { import NameTransformer._ diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 4e4bd2d80adf..f4f5ebbcbac6 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -344,9 +344,9 @@ abstract class TreeInfo { * Named arguments can transform a constructor call into a block, e.g. * (b = foo, a = bar) * is transformed to - * { val x$1 = foo - * val x$2 = bar - * (x$2, x$1) + * { val x\$1 = foo + * val x\$2 = bar + * (x\$2, x\$1) * } */ def stripNamedApplyBlock(tree: Tree) = tree match { diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index d6dd771922e1..2eeff200b6af 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -1190,9 +1190,9 @@ trait Trees extends api.Trees { /** * Creates a tree that selects a specific member `sym` without having to qualify the `super`. - * For example, given traits `B <:< A`, a class `C <:< B` needs to invoke `A.$init$`. If `A` is - * not a direct parent, a tree `super[A].$init$` would not type check ("does not name a parent"). - * So we generate `super.$init$` and pre-assign the correct symbol. A special-case in + * For example, given traits `B <:< A`, a class `C <:< B` needs to invoke `A.\$init\$`. If `A` is + * not a direct parent, a tree `super[A].\$init\$` would not type check ("does not name a parent"). + * So we generate `super.\$init\$` and pre-assign the correct symbol. A special-case in * `typedSelectInternal` assigns the correct type `A` to the `super` qualifier. */ def SuperSelect(clazz: Symbol, sym: Symbol): Tree = { diff --git a/src/reflect/scala/reflect/macros/Evals.scala b/src/reflect/scala/reflect/macros/Evals.scala index 42350b075d69..311b10244c70 100644 --- a/src/reflect/scala/reflect/macros/Evals.scala +++ b/src/reflect/scala/reflect/macros/Evals.scala @@ -35,7 +35,7 @@ trait Evals { * {{{ * scala> def impl(c: Context)(x: c.Expr[String]) = { * | val x1 = c.Expr[String](c.untypecheck(x.tree.duplicate)) - * | println(s"compile-time value is: ${c.eval(x1)}") + * | println(s"compile-time value is: \${c.eval(x1)}") * | x * | } * impl: (c: Context)(x: c.Expr[String])c.Expr[String] diff --git a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala index cec4f2a45aef..4a2d5bdb8fc9 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala @@ -584,7 +584,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { * +---------------+ | +------------------ | -+ | +------------------- v ---+ | * | | package object foo#3 <-----(1)---- module class package#4 | | * | +----------------------+ | | +---------------------+ | | - * +--------------------------+ | | class package$Bar#5 | | | + * +--------------------------+ | | class package\$Bar#5 | | | * | +----------------- | -+ | | * +------------------- | ---+ | * | | From 68c2e7b10942ee4df73e5900fbcee54fb21fc3ea Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 12 Aug 2019 16:54:33 +1000 Subject: [PATCH 2/6] Cache the descriptor of this during class generation --- .../nsc/backend/jvm/BCodeBodyBuilder.scala | 2 +- .../nsc/backend/jvm/BCodeSkelBuilder.scala | 20 ++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 4c92b7bc7327..0242397a9b1c 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -576,7 +576,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { asm.Opcodes.PUTSTATIC, thisBType.internalName, strMODULE_INSTANCE_FIELD, - thisBType.descriptor + thisBTypeDescriptor ) } } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala index 6cf2a1a7536d..cc24f7a399a0 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala @@ -64,8 +64,9 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { final val MaximumJvmParameters = 254 // current class - var cnode: asm.tree.ClassNode = null - var thisBType: ClassBType = null + var cnode: asm.tree.ClassNode = null + var thisBType: ClassBType = null + var thisBTypeDescriptor: String = null var claszSymbol: Symbol = null var isCZParcelable = false @@ -89,11 +90,12 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { def genPlainClass(cd: ClassDef) { assert(cnode == null, "GenBCode detected nested methods.") - claszSymbol = cd.symbol - isCZParcelable = isAndroidParcelableClass(claszSymbol) - isCZStaticModule = isStaticModuleClass(claszSymbol) - isCZRemote = isRemote(claszSymbol) - thisBType = classBTypeFromSymbol(claszSymbol) + claszSymbol = cd.symbol + isCZParcelable = isAndroidParcelableClass(claszSymbol) + isCZStaticModule = isStaticModuleClass(claszSymbol) + isCZRemote = isRemote(claszSymbol) + thisBType = classBTypeFromSymbol(claszSymbol) + thisBTypeDescriptor = thisBType.descriptor cnode = new ClassNode1() @@ -194,7 +196,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { val fv = cnode.visitField(mods, strMODULE_INSTANCE_FIELD, - thisBType.descriptor, + thisBTypeDescriptor, null, // no java-generic-signature null // no initial value ) @@ -622,7 +624,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { if (!hasStaticBitSet) { mnode.visitLocalVariable( "this", - thisBType.descriptor, + thisBTypeDescriptor, null, veryFirstProgramPoint, onePastLastProgramPoint, From 4269cc3b8d4f6a1c2e998be5d473fa1cae523df8 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 12 Aug 2019 16:55:45 +1000 Subject: [PATCH 3/6] Optimize traitSuperAccessorName usage --- .../scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala | 2 +- src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala | 6 +++--- .../scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala | 2 +- .../scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 0242397a9b1c..6235a15ae962 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -1092,7 +1092,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { if (style == Super) { if (receiverClass.isTrait && !method.isJavaDefined) { val staticDesc = MethodBType(typeToBType(method.owner.info) :: bmType.argumentTypes, bmType.returnType).descriptor - val staticName = traitSuperAccessorName(method).toString + val staticName = traitSuperAccessorName(method) bc.invokestatic(receiverName, staticName, staticDesc, isInterface, pos) } else { if (receiverClass.isTraitOrInterface) { diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala index 6a6dfc17d327..ad92b21b2967 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala @@ -61,10 +61,10 @@ abstract class BCodeHelpers extends BCodeIdiomatic { def needsStaticImplMethod(sym: Symbol) = sym.hasAttachment[global.mixer.NeedStaticImpl.type] - final def traitSuperAccessorName(sym: Symbol): Name = { + final def traitSuperAccessorName(sym: Symbol): String = { val name = sym.javaSimpleName - if (sym.isMixinConstructor) name - else name.append(nme.NAME_JOIN_STRING) + if (sym.isMixinConstructor) name.toString + else name + nme.NAME_JOIN_STRING } /** diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala index cc24f7a399a0..029ed325417f 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala @@ -500,7 +500,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { genDefDef(statified) } else { val forwarderDefDef = { - val dd1 = global.gen.mkStatic(deriveDefDef(dd)(_ => EmptyTree), traitSuperAccessorName(sym), _.cloneSymbol.withoutAnnotations) + val dd1 = global.gen.mkStatic(deriveDefDef(dd)(_ => EmptyTree), newTermName(traitSuperAccessorName(sym)), _.cloneSymbol.withoutAnnotations) dd1.symbol.setFlag(Flags.ARTIFACT).resetFlag(Flags.OVERRIDE) val selfParam :: realParams = dd1.vparamss.head.map(_.symbol) deriveDefDef(dd1)(_ => diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala index 927d9a4ec0f2..b2348f4c0e0a 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala @@ -593,7 +593,7 @@ abstract class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { annotatedNoInline = methodSym.hasAnnotation(ScalaNoInlineClass)) if (needsStaticImplMethod(methodSym)) { - val staticName = traitSuperAccessorName(methodSym).toString + val staticName = traitSuperAccessorName(methodSym) val selfParam = methodSym.newSyntheticValueParam(methodSym.owner.typeConstructor, nme.SELF) val staticMethodType = methodSym.info match { case mt@MethodType(params, res) => copyMethodType(mt, selfParam :: params, res) From a37b257499035b26bf8a9773817f98de0ed9be05 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 19 Aug 2019 10:30:56 +1000 Subject: [PATCH 4/6] Use the first scalac-plugin.xml from the plugin classpath This commit reverts part of the #8322 I recently changed to using the last entry from getResources to avoid parent classloader delegation, but this leads to unwanted results if the plugin classpath itself contains multiple `scalac-plugin.xml` resources and wants the compiler to choose the first. I have _not_ reverted the other change in #8322 which overrides `getResource` to avoid parent delegation for `scalac-plugin.xml`. I have documented the `findPluginClassLoader` extension point with instructions to do the same. --- src/compiler/scala/tools/nsc/plugins/Plugin.scala | 6 +++--- src/compiler/scala/tools/nsc/plugins/Plugins.scala | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/compiler/scala/tools/nsc/plugins/Plugin.scala b/src/compiler/scala/tools/nsc/plugins/Plugin.scala index 643c85499c03..48f3ab69dda1 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugin.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugin.scala @@ -152,9 +152,9 @@ object Plugin { val fromLoaders = paths.map {path => val loader = findPluginClassloader(path) - loader.getResources(PluginXML).asScala.toList.lastOption match { - case None => Failure(new MissingPluginException(path)) - case Some(url) => + loader.getResource(PluginXML) match { + case null => Failure(new MissingPluginException(path)) + case url => val inputStream = url.openStream try { Try((PluginDescription.fromXML(inputStream), loader)) diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala index dda04fe5f8c5..6425d65f4037 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala @@ -62,7 +62,8 @@ trait Plugins { global: Global => /** * Locate or create the classloader to load a compiler plugin with `classpath`. * - * Subclasses may override to customise the behaviour. + * Subclasses may override to customise the behaviour. The returned classloader must return the first + * from plugin descriptor from `classpath` when `getResource("scalac-plugin.xml")` is called. * * @param classpath * @return From 33f11d3e3326606b3be1d09066d142fc789103a5 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 15 Aug 2019 18:38:42 +1000 Subject: [PATCH 5/6] Benchmark for classpah lookup --- .../nsc/AggregateClassPathBenchmark.scala | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 test/benchmarks/src/main/scala/scala/tools/nsc/AggregateClassPathBenchmark.scala diff --git a/test/benchmarks/src/main/scala/scala/tools/nsc/AggregateClassPathBenchmark.scala b/test/benchmarks/src/main/scala/scala/tools/nsc/AggregateClassPathBenchmark.scala new file mode 100644 index 000000000000..a4cfe9be0e2d --- /dev/null +++ b/test/benchmarks/src/main/scala/scala/tools/nsc/AggregateClassPathBenchmark.scala @@ -0,0 +1,43 @@ +package scala.tools.nsc + +import java.nio.file.{Files, Paths} +import java.util.concurrent.TimeUnit + +import org.openjdk.jmh +import org.openjdk.jmh.annotations._ +import org.openjdk.jmh.infra.Blackhole + +import scala.tools.nsc +import scala.tools.nsc.util.ClassPath +import scala.tools.util.PathResolver + +@BenchmarkMode(Array(jmh.annotations.Mode.AverageTime)) +@Fork(2) +@Threads(1) +@Warmup(iterations = 10) +@Measurement(iterations = 10) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) +class AggregateClassPathBenchmark { + @Param(Array("")) + var classpathString: String = _ + var classpath: ClassPath = _ + val closeableRegistry = new CloseableRegistry + @Setup def setup(): Unit = { + val settings = new nsc.Settings() + if (classpathString.startsWith("@")) + classpathString = new String(Files.readAllBytes(Paths.get(classpathString.drop(1)))) + settings.classpath.value = classpathString + val resolver = new PathResolver(settings, closeableRegistry) + classpath = resolver.result + classpath.list("") + } + + @TearDown def teardown(): Unit = { + closeableRegistry.close() + } + + @Benchmark def test(bh: Blackhole) = { + classpath.list("")._1.foreach(entry => bh.consume(classpath.list(entry.name))) + } +} From 22edf28c08aad971d823ec9db4b5f956671c611e Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Fri, 9 Aug 2019 11:30:03 +1000 Subject: [PATCH 6/6] Optimize the classpath implementation - Avoid repeated conversion between package dotted names ("com.foo") and relative paths ("com/foo/") by threading a `PackageName` instance through the aggregate classpath lookup which caches the path name. - Avoid creating result buffers inside of each element of the aggregate classpath by introducing a callback based API that lets `AggregateClasspath` use a single buffer. --- .../nsc/backend/jvm/ClassfileWriters.scala | 2 +- .../nsc/classpath/AggregateClassPath.scala | 53 +++++++----- .../scala/tools/nsc/classpath/ClassPath.scala | 19 ++++- .../nsc/classpath/DirectoryClassPath.scala | 82 +++++++++---------- .../classpath/VirtualDirectoryClassPath.scala | 2 +- .../ZipAndJarFileLookupFactory.scala | 21 +++-- .../nsc/classpath/ZipArchiveFileLookup.scala | 50 +++++------ .../scala/tools/nsc/util/ClassPath.scala | 38 +++++++-- .../scala/collection/mutable/AnyRefMap.scala | 6 +- src/reflect/scala/reflect/io/ZipArchive.scala | 22 ++--- .../classpath/AggregateClassPathTest.scala | 26 +++--- 11 files changed, 180 insertions(+), 141 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/ClassfileWriters.scala b/src/compiler/scala/tools/nsc/backend/jvm/ClassfileWriters.scala index 46c6ac36d33d..d8bf14db0557 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/ClassfileWriters.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/ClassfileWriters.scala @@ -12,7 +12,7 @@ package scala.tools.nsc.backend.jvm -import java.io.{BufferedOutputStream, DataOutputStream, FileOutputStream, IOException} +import java.io.{DataOutputStream, IOException} import java.nio.ByteBuffer import java.nio.channels.{ClosedByInterruptException, FileChannel} import java.nio.charset.StandardCharsets diff --git a/src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala b/src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala index f82e9a72b08e..703a1505472e 100644 --- a/src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala +++ b/src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala @@ -13,11 +13,11 @@ package scala.tools.nsc.classpath import java.net.URL + import scala.collection.mutable.ArrayBuffer import scala.reflect.internal.FatalError import scala.reflect.io.AbstractFile -import scala.tools.nsc.util.ClassPath -import scala.tools.nsc.util.ClassRepresentation +import scala.tools.nsc.util.{ClassPath, ClassRepresentation, EfficientClassPath} /** * A classpath unifying multiple class- and sourcepath entries. @@ -30,13 +30,13 @@ import scala.tools.nsc.util.ClassRepresentation case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath { override def findClassFile(className: String): Option[AbstractFile] = { val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className) - aggregatesForPackage(pkg).iterator.map(_.findClassFile(className)).collectFirst { + aggregatesForPackage(PackageName(pkg)).iterator.map(_.findClassFile(className)).collectFirst { case Some(x) => x } } private[this] val packageIndex: collection.mutable.Map[String, Seq[ClassPath]] = collection.mutable.Map() - private def aggregatesForPackage(pkg: String): Seq[ClassPath] = packageIndex.synchronized { - packageIndex.getOrElseUpdate(pkg, aggregates.filter(_.hasPackage(pkg))) + private def aggregatesForPackage(pkg: PackageName): Seq[ClassPath] = packageIndex.synchronized { + packageIndex.getOrElseUpdate(pkg.dottedString, aggregates.filter(_.hasPackage(pkg))) } // This method is performance sensitive as it is used by SBT's ExtractDependencies phase. @@ -44,7 +44,7 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath { val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className) def findEntry(isSource: Boolean): Option[ClassRepresentation] = { - aggregatesForPackage(pkg).iterator.map(_.findClass(className)).collectFirst { + aggregatesForPackage(PackageName(pkg)).iterator.map(_.findClass(className)).collectFirst { case Some(s: SourceFileEntry) if isSource => s case Some(s: ClassFileEntry) if !isSource => s } @@ -66,31 +66,44 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath { override def asSourcePathString: String = ClassPath.join(aggregates map (_.asSourcePathString): _*) - override private[nsc] def packages(inPackage: String): Seq[PackageEntry] = { + override private[nsc] def packages(inPackage: PackageName): Seq[PackageEntry] = { val aggregatedPackages = aggregates.flatMap(_.packages(inPackage)).distinct aggregatedPackages } - override private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = + override private[nsc] def classes(inPackage: PackageName): Seq[ClassFileEntry] = getDistinctEntries(_.classes(inPackage)) - override private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] = + override private[nsc] def sources(inPackage: PackageName): Seq[SourceFileEntry] = getDistinctEntries(_.sources(inPackage)) - override private[nsc] def hasPackage(pkg: String) = aggregates.exists(_.hasPackage(pkg)) - override private[nsc] def list(inPackage: String): ClassPathEntries = { - val (packages, classesAndSources) = aggregates.map { cp => + override private[nsc] def hasPackage(pkg: PackageName) = aggregates.exists(_.hasPackage(pkg)) + override private[nsc] def list(inPackage: PackageName): ClassPathEntries = { + val packages: java.util.HashSet[PackageEntry] = new java.util.HashSet[PackageEntry]() + val classesAndSourcesBuffer = collection.mutable.ArrayBuffer[ClassRepresentation]() + val onPackage: PackageEntry => Unit = packages.add(_) + val onClassesAndSources: ClassRepresentation => Unit = classesAndSourcesBuffer += _ + + aggregates.foreach { cp => try { - cp.list(inPackage) + cp match { + case ecp: EfficientClassPath => + ecp.list(inPackage, onPackage, onClassesAndSources) + case _ => + val entries = cp.list(inPackage) + entries._1.foreach(entry => packages.add(entry)) + classesAndSourcesBuffer ++= entries._2 + } } catch { case ex: java.io.IOException => val e = FatalError(ex.getMessage) e.initCause(ex) throw e } - }.unzip - val distinctPackages = packages.flatten.distinct - val distinctClassesAndSources = mergeClassesAndSources(classesAndSources) + } + + val distinctPackages: Seq[PackageEntry] = if (packages == null) Nil else packages.toArray(new Array[PackageEntry](packages.size())) + val distinctClassesAndSources = mergeClassesAndSources(classesAndSourcesBuffer) ClassPathEntries(distinctPackages, distinctClassesAndSources) } @@ -99,14 +112,12 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath { * 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[Seq[ClassRepresentation]]): Seq[ClassRepresentation] = { + private def mergeClassesAndSources(entries: Seq[ClassRepresentation]): Seq[ClassRepresentation] = { var count = 0 val indices = collection.mutable.HashMap[String, Int]() - val mergedEntries = new ArrayBuffer[ClassRepresentation](1024) - + val mergedEntries = new ArrayBuffer[ClassRepresentation](entries.size) for { - partOfEntries <- entries - entry <- partOfEntries + entry <- entries } { val name = entry.name if (indices contains name) { diff --git a/src/compiler/scala/tools/nsc/classpath/ClassPath.scala b/src/compiler/scala/tools/nsc/classpath/ClassPath.scala index 1a65c230ab80..d21b28e2aac7 100644 --- a/src/compiler/scala/tools/nsc/classpath/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/classpath/ClassPath.scala @@ -32,6 +32,21 @@ trait SourceFileEntry extends ClassRepresentation { def file: AbstractFile } +case class PackageName(dottedString: String) { + def isRoot: Boolean = dottedString.isEmpty + val dirPathTrailingSlash: String = FileUtils.dirPath(dottedString) + "/" + + def entryName(entry: String): String = { + if (isRoot) entry else { + val builder = new java.lang.StringBuilder(dottedString.length + 1 + entry.length) + builder.append(dottedString) + builder.append('.') + builder.append(entry) + builder.toString + } + } +} + trait PackageEntry { def name: String } @@ -61,10 +76,10 @@ private[nsc] case class PackageEntryImpl(name: String) extends PackageEntry private[nsc] trait NoSourcePaths { final def asSourcePathString: String = "" - final private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] = Seq.empty + final private[nsc] def sources(inPackage: PackageName): Seq[SourceFileEntry] = Seq.empty } private[nsc] trait NoClassPaths { final def findClassFile(className: String): Option[AbstractFile] = None - private[nsc] final def classes(inPackage: String): Seq[ClassFileEntry] = Seq.empty + private[nsc] final def classes(inPackage: PackageName): Seq[ClassFileEntry] = Seq.empty } diff --git a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala index da69060b4664..edc427854edf 100644 --- a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala +++ b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala @@ -18,7 +18,7 @@ import java.nio.file.{FileSystems, Files} import java.util import scala.reflect.io.{AbstractFile, PlainFile, PlainNioFile} -import scala.tools.nsc.util.{ClassPath, ClassRepresentation} +import scala.tools.nsc.util.{ClassPath, ClassRepresentation, EfficientClassPath} import FileUtils._ import scala.collection.JavaConverters._ import scala.reflect.internal.JDK9Reflectors @@ -32,7 +32,7 @@ import scala.tools.nsc.classpath.PackageNameUtils.{packageContains, separatePkgA * 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 { +trait DirectoryLookup[FileEntryType <: ClassRepresentation] extends EfficientClassPath { type F val dir: F @@ -47,28 +47,26 @@ trait DirectoryLookup[FileEntryType <: ClassRepresentation] extends ClassPath { protected def createFileEntry(file: AbstractFile): FileEntryType protected def isMatchingFile(f: F): Boolean - private def getDirectory(forPackage: String): Option[F] = { - if (forPackage == ClassPath.RootPackage) { + private def getDirectory(forPackage: PackageName): Option[F] = { + if (forPackage.isRoot) { Some(dir) } else { - val packageDirName = FileUtils.dirPath(forPackage) - getSubDir(packageDirName) + getSubDir(forPackage.dirPathTrailingSlash) } } - override private[nsc] def hasPackage(pkg: String) = getDirectory(pkg).isDefined + override private[nsc] def hasPackage(pkg: PackageName) = getDirectory(pkg).isDefined - private[nsc] def packages(inPackage: String): Seq[PackageEntry] = { + private[nsc] def packages(inPackage: PackageName): 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))) + nestedDirs.map(f => PackageEntryImpl(inPackage.entryName(getName(f)))) } - protected def files(inPackage: String): Seq[FileEntryType] = { + protected def files(inPackage: PackageName): Seq[FileEntryType] = { val dirForPackage = getDirectory(inPackage) val files: Array[F] = dirForPackage match { case None => emptyFiles @@ -77,22 +75,18 @@ trait DirectoryLookup[FileEntryType <: ClassRepresentation] extends ClassPath { files.map(f => createFileEntry(toAbstractFile(f))) } - private[nsc] def list(inPackage: String): ClassPathEntries = { + override private[nsc] def list(inPackage: PackageName, onPackageEntry: PackageEntry => Unit, onClassesAndSources: ClassRepresentation => Unit): Unit = { 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)) + dirForPackage match { + case None => + case Some(directory) => + for (file <- listChildren(directory)) { + if (isPackage(file)) + onPackageEntry(PackageEntryImpl(inPackage.entryName(getName(file)))) + else if (isMatchingFile(file)) + onClassesAndSources(createFileEntry(toAbstractFile(file))) + } } - ClassPathEntries(packageBuf, fileBuf) } } @@ -196,21 +190,21 @@ final class JrtClassPath(fs: java.nio.file.FileSystem) extends ClassPath with No } /** Empty string represents root package */ - override private[nsc] def hasPackage(pkg: String) = packageToModuleBases.contains(pkg) - override private[nsc] def packages(inPackage: String): Seq[PackageEntry] = { - packageToModuleBases.keysIterator.filter(pack => packageContains(inPackage, pack)).map(PackageEntryImpl(_)).toVector + override private[nsc] def hasPackage(pkg: PackageName) = packageToModuleBases.contains(pkg.dottedString) + override private[nsc] def packages(inPackage: PackageName): Seq[PackageEntry] = { + packageToModuleBases.keysIterator.filter(pack => packageContains(inPackage.dottedString, pack)).map(PackageEntryImpl(_)).toVector } - private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = { - if (inPackage == "") Nil + private[nsc] def classes(inPackage: PackageName): Seq[ClassFileEntry] = { + if (inPackage.isRoot) Nil else { - packageToModuleBases.getOrElse(inPackage, Nil).flatMap(x => - Files.list(x.resolve(inPackage.replace('.', '/'))).iterator().asScala.filter(_.getFileName.toString.endsWith(".class"))).map(x => + packageToModuleBases.getOrElse(inPackage.dottedString, Nil).flatMap(x => + Files.list(x.resolve(inPackage.dirPathTrailingSlash)).iterator().asScala.filter(_.getFileName.toString.endsWith(".class"))).map(x => ClassFileEntryImpl(new PlainNioFile(x))).toVector } } - override private[nsc] def list(inPackage: String): ClassPathEntries = - if (inPackage == "") ClassPathEntries(packages(inPackage), Nil) + override private[nsc] def list(inPackage: PackageName): ClassPathEntries = + if (inPackage.isRoot) ClassPathEntries(packages(inPackage), Nil) else ClassPathEntries(packages(inPackage), classes(inPackage)) def asURLs: Seq[URL] = Seq(new URL("jrt:/")) @@ -262,21 +256,21 @@ final class CtSymClassPath(ctSym: java.nio.file.Path, release: Int) extends Clas } /** Empty string represents root package */ - override private[nsc] def hasPackage(pkg: String) = packageIndex.contains(pkg) - override private[nsc] def packages(inPackage: String): Seq[PackageEntry] = { - packageIndex.keysIterator.filter(pack => packageContains(inPackage, pack)).map(PackageEntryImpl(_)).toVector + override private[nsc] def hasPackage(pkg: PackageName) = packageIndex.contains(pkg.dottedString) + override private[nsc] def packages(inPackage: PackageName): Seq[PackageEntry] = { + packageIndex.keysIterator.filter(pack => packageContains(inPackage.dottedString, pack)).map(PackageEntryImpl(_)).toVector } - private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = { - if (inPackage == "") Nil + private[nsc] def classes(inPackage: PackageName): Seq[ClassFileEntry] = { + if (inPackage.isRoot) Nil else { - val sigFiles = packageIndex.getOrElse(inPackage, Nil).iterator.flatMap(p => + val sigFiles = packageIndex.getOrElse(inPackage.dottedString, Nil).iterator.flatMap(p => Files.list(p).iterator().asScala.filter(_.getFileName.toString.endsWith(".sig"))) sigFiles.map(f => ClassFileEntryImpl(new PlainNioFile(f))).toVector } } - override private[nsc] def list(inPackage: String): ClassPathEntries = - if (inPackage == "") ClassPathEntries(packages(inPackage), Nil) + override private[nsc] def list(inPackage: PackageName): ClassPathEntries = + if (inPackage.isRoot) ClassPathEntries(packages(inPackage), Nil) else ClassPathEntries(packages(inPackage), classes(inPackage)) def asURLs: Seq[URL] = Nil @@ -310,7 +304,7 @@ case class DirectoryClassPath(dir: File) extends JFileDirectoryLookup[ClassFileE protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file) protected def isMatchingFile(f: File): Boolean = f.isClass - private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage) + private[nsc] def classes(inPackage: PackageName): Seq[ClassFileEntry] = files(inPackage) } case class DirectorySourcePath(dir: File) extends JFileDirectoryLookup[SourceFileEntryImpl] with NoClassPaths { @@ -334,5 +328,5 @@ case class DirectorySourcePath(dir: File) extends JFileDirectoryLookup[SourceFil } } - private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] = files(inPackage) + private[nsc] def sources(inPackage: PackageName): Seq[SourceFileEntry] = files(inPackage) } diff --git a/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryClassPath.scala b/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryClassPath.scala index af13a720d795..40eb63200b37 100644 --- a/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryClassPath.scala +++ b/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryClassPath.scala @@ -45,7 +45,7 @@ case class VirtualDirectoryClassPath(dir: VirtualDirectory) extends ClassPath wi Option(AbstractFileClassLoader.lookupPath(dir)(relativePath split '/', directory = false)) } - private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage) + private[nsc] def classes(inPackage: PackageName): Seq[ClassFileEntry] = files(inPackage) protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file) protected def isMatchingFile(f: AbstractFile): Boolean = f.isClass diff --git a/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala b/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala index c8c759f07cd4..cce816a6ff8b 100644 --- a/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala +++ b/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala @@ -59,15 +59,15 @@ object ZipAndJarClassPathFactory extends ZipAndJarFileLookupFactory { override def findClassFile(className: String): Option[AbstractFile] = { val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className) - file(pkg, simpleClassName + ".class").map(_.file) + file(PackageName(pkg), simpleClassName + ".class").map(_.file) } // This method is performance sensitive as it is used by SBT's ExtractDependencies phase. override def findClass(className: String): Option[ClassRepresentation] = { val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className) - file(pkg, simpleClassName + ".class") + file(PackageName(pkg), simpleClassName + ".class") } - override private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage) + override private[nsc] def classes(inPackage: PackageName): Seq[ClassFileEntry] = files(inPackage) override protected def createFileEntry(file: FileZipArchive#Entry): ClassFileEntryImpl = ClassFileEntryImpl(file) override protected def isRequiredFileType(file: AbstractFile): Boolean = file.isClass @@ -83,7 +83,7 @@ object ZipAndJarClassPathFactory extends ZipAndJarFileLookupFactory { private case class ManifestResourcesClassPath(file: ManifestResources) extends ClassPath with NoSourcePaths with Closeable { override def findClassFile(className: String): Option[AbstractFile] = { val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className) - classes(pkg).find(_.name == simpleClassName).map(_.file) + classes(PackageName(pkg)).find(_.name == simpleClassName).map(_.file) } override def asClassPathStrings: Seq[String] = Seq(file.path) @@ -135,22 +135,21 @@ object ZipAndJarClassPathFactory extends ZipAndJarFileLookupFactory { packages } - override private[nsc] def packages(inPackage: String): Seq[PackageEntry] = cachedPackages.get(inPackage) match { + override private[nsc] def packages(inPackage: PackageName): Seq[PackageEntry] = cachedPackages.get(inPackage.dottedString) match { case None => Seq.empty case Some(PackageFileInfo(_, subpackages)) => - val prefix = PackageNameUtils.packagePrefix(inPackage) - subpackages.map(packageFile => PackageEntryImpl(prefix + packageFile.name)) + subpackages.map(packageFile => PackageEntryImpl(inPackage.entryName(packageFile.name))) } - override private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = cachedPackages.get(inPackage) match { + override private[nsc] def classes(inPackage: PackageName): Seq[ClassFileEntry] = cachedPackages.get(inPackage.dottedString) match { case None => Seq.empty case Some(PackageFileInfo(pkg, _)) => (for (file <- pkg if file.isClass) yield ClassFileEntryImpl(file))(collection.breakOut) } - override private[nsc] def hasPackage(pkg: String) = cachedPackages.contains(pkg) - override private[nsc] def list(inPackage: String): ClassPathEntries = ClassPathEntries(packages(inPackage), classes(inPackage)) + override private[nsc] def hasPackage(pkg: PackageName) = cachedPackages.contains(pkg.dottedString) + override private[nsc] def list(inPackage: PackageName): ClassPathEntries = ClassPathEntries(packages(inPackage), classes(inPackage)) } private object ManifestResourcesClassPath { @@ -183,7 +182,7 @@ object ZipAndJarSourcePathFactory extends ZipAndJarFileLookupFactory { override def asSourcePathString: String = asClassPathString - override private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] = files(inPackage) + override private[nsc] def sources(inPackage: PackageName): Seq[SourceFileEntry] = files(inPackage) override protected def createFileEntry(file: FileZipArchive#Entry): SourceFileEntryImpl = SourceFileEntryImpl(file) override protected def isRequiredFileType(file: AbstractFile): Boolean = file.isScalaOrJavaSource diff --git a/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala b/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala index 9f0dab7a71cf..294bdbe49345 100644 --- a/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala +++ b/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala @@ -14,18 +14,19 @@ package scala.tools.nsc.classpath import java.io.{Closeable, File} import java.net.URL + import scala.collection.Seq import scala.reflect.io.AbstractFile import scala.reflect.io.FileZipArchive import FileUtils.AbstractFileOps -import scala.tools.nsc.util.{ClassPath, ClassRepresentation} +import scala.tools.nsc.util.{ClassRepresentation, EfficientClassPath} /** * 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 with Closeable { +trait ZipArchiveFileLookup[FileEntryType <: ClassRepresentation] extends EfficientClassPath with Closeable { val zipFile: File def release: Option[String] @@ -36,54 +37,47 @@ trait ZipArchiveFileLookup[FileEntryType <: ClassRepresentation] extends ClassPa private val archive = new FileZipArchive(zipFile, release) override def close(): Unit = archive.close() - override private[nsc] def packages(inPackage: String): Seq[PackageEntry] = { - val prefix = PackageNameUtils.packagePrefix(inPackage) + override private[nsc] def packages(inPackage: PackageName): Seq[PackageEntry] = { for { dirEntry <- findDirEntry(inPackage).toSeq entry <- dirEntry.iterator if entry.isPackage - } yield PackageEntryImpl(prefix + entry.name) + } yield PackageEntryImpl(inPackage.entryName(entry.name)) } - protected def files(inPackage: String): Seq[FileEntryType] = + protected def files(inPackage: PackageName): Seq[FileEntryType] = for { dirEntry <- findDirEntry(inPackage).toSeq entry <- dirEntry.iterator if isRequiredFileType(entry) } yield createFileEntry(entry) - protected def file(inPackage: String, name: String): Option[FileEntryType] = + protected def file(inPackage: PackageName, name: String): Option[FileEntryType] = for { dirEntry <- findDirEntry(inPackage) entry <- Option(dirEntry.lookupName(name, directory = false)) if isRequiredFileType(entry) } yield createFileEntry(entry) - override private[nsc] def hasPackage(pkg: String) = findDirEntry(pkg).isDefined - override private[nsc] 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) + override private[nsc] def hasPackage(pkg: PackageName) = findDirEntry(pkg).isDefined - for (entry <- dirEntry.iterator) { - if (entry.isPackage) - pkgBuf += PackageEntryImpl(prefix + entry.name) - else if (isRequiredFileType(entry)) - fileBuf += createFileEntry(entry) - } - ClassPathEntries(pkgBuf, fileBuf) - } getOrElse ClassPathEntries.empty + private[nsc] def list(inPackage: PackageName, onPackageEntry: PackageEntry => Unit, onClassesAndSources: ClassRepresentation => Unit): Unit = { + findDirEntry(inPackage) match { + case Some(dirEntry) => + for (entry <- dirEntry.iterator) { + if (entry.isPackage) + onPackageEntry(PackageEntryImpl(inPackage.entryName(entry.name))) + else if (isRequiredFileType(entry)) + onClassesAndSources(createFileEntry(entry)) + } + case None => + } } - private def findDirEntry(pkg: String): Option[archive.DirEntry] = { - archive.allDirs.get(dottedToPath(pkg)) + private def findDirEntry(pkg: PackageName): Option[archive.DirEntry] = { + Option(archive.allDirs.get(pkg.dirPathTrailingSlash)) } - private def dottedToPath(dotted: String): String = { - dotted.replace('.', '/') + "/" - } protected def createFileEntry(file: FileZipArchive#Entry): FileEntryType protected def isRequiredFileType(file: AbstractFile): Boolean } + diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 827c7ce5dbd7..2cb28493fdf4 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -20,6 +20,7 @@ import java.util.regex.PatternSyntaxException import File.pathSeparator import Jar.isJarOrZip +import scala.tools.nsc.classpath.{ClassPathEntries, PackageEntry, PackageName} /** * A representation of the compiler's class- or sourcepath. @@ -28,6 +29,12 @@ trait ClassPath { import scala.tools.nsc.classpath._ def asURLs: Seq[URL] + final def hasPackage(pkg: String): Boolean = hasPackage(PackageName(pkg)) + final def packages(inPackage: String): Seq[PackageEntry] = packages(PackageName(inPackage)) + final def classes(inPackage: String): Seq[ClassFileEntry] = classes(PackageName(inPackage)) + final def sources(inPackage: String): Seq[SourceFileEntry] = sources(PackageName(inPackage)) + final def list(inPackage: String): ClassPathEntries = list(PackageName(inPackage)) + /* * These methods are mostly used in the ClassPath implementation to implement the `list` and * `findX` methods below. @@ -38,11 +45,10 @@ trait ClassPath { * * The `inPackage` string is a full package name, e.g. "" or "scala.collection". */ - - private[nsc] def hasPackage(pkg: String): Boolean - private[nsc] def packages(inPackage: String): Seq[PackageEntry] - private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] - private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] + private[nsc] def hasPackage(pkg: PackageName): Boolean + private[nsc] def packages(inPackage: PackageName): Seq[PackageEntry] + private[nsc] def classes(inPackage: PackageName): Seq[ClassFileEntry] + private[nsc] def sources(inPackage: PackageName): Seq[SourceFileEntry] /** * Returns packages and classes (source or classfile) that are members of `inPackage` (not @@ -51,7 +57,7 @@ trait ClassPath { * This is the main method uses to find classes, see class `PackageLoader`. The * `rootMirror.rootLoader` is created with `inPackage = ""`. */ - private[nsc] def list(inPackage: String): ClassPathEntries + private[nsc] def list(inPackage: PackageName): ClassPathEntries /** * Returns the class file and / or source file for a given external name, e.g., "java.lang.String". @@ -70,8 +76,9 @@ trait ClassPath { // 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) + val packageName = PackageName(pkg) + val foundClassFromClassFiles = classes(packageName).find(_.name == simpleClassName) + def findClassInSources = sources(packageName).find(_.name == simpleClassName) foundClassFromClassFiles orElse findClassInSources } @@ -101,6 +108,21 @@ trait ClassPath { def asSourcePathString: String } +trait EfficientClassPath extends ClassPath { + private[nsc] def list(inPackage: PackageName, onPackageEntry: PackageEntry => Unit, onClassesAndSources: ClassRepresentation => Unit): Unit + override private[nsc] def list(inPackage: PackageName): ClassPathEntries = { + val packageBuf = collection.mutable.ArrayBuffer.empty[PackageEntry] + val classRepBuf = collection.mutable.ArrayBuffer.empty[ClassRepresentation] + list(inPackage, packageBuf += _, classRepBuf += _) + if (packageBuf.isEmpty && classRepBuf.isEmpty) ClassPathEntries.empty + else ClassPathEntries(packageBuf, classRepBuf) + } +} +trait EfficientClassPathCallBack { + def packageEntry(entry: PackageEntry): Unit + def classesAndSources(entry: ClassRepresentation): Unit +} + object ClassPath { val RootPackage = "" diff --git a/src/library/scala/collection/mutable/AnyRefMap.scala b/src/library/scala/collection/mutable/AnyRefMap.scala index aaccb053dc05..377a511d382b 100644 --- a/src/library/scala/collection/mutable/AnyRefMap.scala +++ b/src/library/scala/collection/mutable/AnyRefMap.scala @@ -108,8 +108,10 @@ extends AbstractMap[K, V] var e = h & mask var x = 0 var g = 0 - while ({ g = _hashes(e); g != 0}) { - if (g == h && { val q = _keys(e); (q eq k) || ((q ne null) && (q equals k)) }) return e + val hashes = _hashes + val keys = _keys + while ({ g = hashes(e); g != 0}) { + if (g == h && { val q = keys(e); (q eq k) || ((q ne null) && (q equals k)) }) return e x += 1 e = (e + 2*(x+1)*x - 3) & mask } diff --git a/src/reflect/scala/reflect/io/ZipArchive.scala b/src/reflect/scala/reflect/io/ZipArchive.scala index f17f46822e69..8f891ffcab47 100644 --- a/src/reflect/scala/reflect/io/ZipArchive.scala +++ b/src/reflect/scala/reflect/io/ZipArchive.scala @@ -108,19 +108,19 @@ abstract class ZipArchive(override val file: JFile, release: Option[String]) ext } } - private def ensureDir(dirs: mutable.Map[String, DirEntry], path: String, zipEntry: ZipEntry): DirEntry = { + private def ensureDir(dirs: java.util.Map[String, DirEntry], path: String, zipEntry: ZipEntry): DirEntry = { dirs get path match { - case Some(v) => v - case None => + case null => val parent = ensureDir(dirs, dirName(path), null) val dir = new DirEntry(path) parent.entries(baseName(path)) = dir - dirs(path) = dir + dirs.put(path, dir) dir + case v => v } } - protected def getDir(dirs: mutable.Map[String, DirEntry], entry: ZipEntry): DirEntry = { + protected def getDir(dirs: java.util.Map[String, DirEntry], entry: ZipEntry): DirEntry = { if (entry.isDirectory) ensureDir(dirs, entry.getName, entry) else ensureDir(dirs, dirName(entry.getName), null) } @@ -172,10 +172,10 @@ final class FileZipArchive(file: JFile, release: Option[String]) extends ZipArch override def sizeOption: Option[Int] = Some(zipEntry.getSize.toInt) } - private[this] val dirs = mutable.HashMap[String, DirEntry]() + private[this] val dirs = new java.util.HashMap[String, DirEntry]() lazy val root: DirEntry = { val root = new DirEntry("/") - dirs("/") = root + dirs.put("/", root) val zipFile = openZipFile() val enum = zipFile.entries() @@ -209,7 +209,7 @@ final class FileZipArchive(file: JFile, release: Option[String]) extends ZipArch root } - lazy val allDirs: mutable.HashMap[String, DirEntry] = { root; dirs } + lazy val allDirs: java.util.Map[String, DirEntry] = { root; dirs } def iterator: Iterator[Entry] = root.iterator @@ -234,7 +234,8 @@ final class FileZipArchive(file: JFile, release: Option[String]) extends ZipArch final class URLZipArchive(val url: URL) extends ZipArchive(null) { def iterator: Iterator[Entry] = { val root = new DirEntry("/") - val dirs = mutable.HashMap[String, DirEntry]("" -> root) + val dirs = new java.util.HashMap[String, DirEntry]() + dirs.put("", root) val in = new ZipInputStream(new ByteArrayInputStream(Streamable.bytes(input))) closeables ::= in @@ -307,7 +308,8 @@ final class URLZipArchive(val url: URL) extends ZipArchive(null) { final class ManifestResources(val url: URL) extends ZipArchive(null) { def iterator = { val root = new DirEntry("/") - val dirs = mutable.HashMap[String, DirEntry]("" -> root) + val dirs = new java.util.HashMap[String, DirEntry] + dirs.put("", root) val manifest = new Manifest(input) closeables ::= input diff --git a/test/junit/scala/tools/nsc/classpath/AggregateClassPathTest.scala b/test/junit/scala/tools/nsc/classpath/AggregateClassPathTest.scala index 8b784142c555..6e5f9bce928b 100644 --- a/test/junit/scala/tools/nsc/classpath/AggregateClassPathTest.scala +++ b/test/junit/scala/tools/nsc/classpath/AggregateClassPathTest.scala @@ -21,12 +21,12 @@ import scala.tools.nsc.util.ClassPath class AggregateClassPathTest { private abstract class TestClassPathBase extends ClassPath { - override private[nsc] def hasPackage(pkg: String) = true - override def packages(inPackage: String): Seq[PackageEntry] = unsupported - override def sources(inPackage: String): Seq[SourceFileEntry] = unsupported - override def classes(inPackage: String): Seq[ClassFileEntry] = unsupported + override private[nsc] def hasPackage(pkg: PackageName) = true + override def packages(inPackage: PackageName): Seq[PackageEntry] = unsupported + override def sources(inPackage: PackageName): Seq[SourceFileEntry] = unsupported + override def classes(inPackage: PackageName): Seq[ClassFileEntry] = unsupported - override def list(inPackage: String): ClassPathEntries = unsupported + override def list(inPackage: PackageName): ClassPathEntries = unsupported override def findClassFile(name: String): Option[AbstractFile] = unsupported override def asClassPathStrings: Seq[String] = unsupported @@ -36,30 +36,30 @@ class AggregateClassPathTest { private case class TestClassPath(virtualPath: String, classesInPackage: EntryNamesInPackage*) extends TestClassPathBase { - override def classes(inPackage: String): Seq[ClassFileEntry] = + override def classes(inPackage: PackageName): Seq[ClassFileEntry] = for { entriesWrapper <- classesInPackage if entriesWrapper.inPackage == inPackage name <- entriesWrapper.names - } yield classFileEntry(virtualPath, inPackage, name) + } yield classFileEntry(virtualPath, inPackage.dottedString, name) - override def sources(inPackage: String): Seq[SourceFileEntry] = Nil + override def sources(inPackage: PackageName): Seq[SourceFileEntry] = Nil // we'll ignore packages - override def list(inPackage: String): ClassPathEntries = ClassPathEntries(Nil, classes(inPackage)) + override def list(inPackage: PackageName): ClassPathEntries = ClassPathEntries(Nil, classes(inPackage)) } private case class TestSourcePath(virtualPath: String, sourcesInPackage: EntryNamesInPackage*) extends TestClassPathBase { - override def sources(inPackage: String): Seq[SourceFileEntry] = + override def sources(inPackage: PackageName): Seq[SourceFileEntry] = for { entriesWrapper <- sourcesInPackage if entriesWrapper.inPackage == inPackage name <- entriesWrapper.names - } yield sourceFileEntry(virtualPath, inPackage, name) + } yield sourceFileEntry(virtualPath, inPackage.dottedString, name) - override def classes(inPackage: String): Seq[ClassFileEntry] = Nil + override def classes(inPackage: PackageName): Seq[ClassFileEntry] = Nil // we'll ignore packages - override def list(inPackage: String): ClassPathEntries = ClassPathEntries(Nil, sources(inPackage)) + override def list(inPackage: PackageName): ClassPathEntries = ClassPathEntries(Nil, sources(inPackage)) } private case class EntryNamesInPackage(inPackage: String)(val names: String*)