summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala47
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala29
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala76
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala83
-rw-r--r--src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/AbsSettings.scala6
-rw-r--r--src/compiler/scala/tools/nsc/settings/MutableSettings.scala25
-rw-r--r--src/compiler/scala/tools/nsc/transform/Delambdafy.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Flatten.scala7
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala18
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala41
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala5
-rw-r--r--src/library/scala/collection/TraversableLike.scala2
-rw-r--r--src/library/scala/collection/immutable/Stream.scala24
-rw-r--r--src/library/scala/collection/immutable/StringLike.scala12
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala7
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala44
-rw-r--r--src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala66
-rw-r--r--src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala6
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala2
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ILoop.scala115
-rw-r--r--src/repl/scala/tools/nsc/interpreter/IMain.scala34
-rw-r--r--src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala23
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ReplProps.scala3
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ReplReporter.scala18
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ReplStrings.scala5
-rw-r--r--src/scaladoc/scala/tools/nsc/ScalaDoc.scala20
28 files changed, 403 insertions, 320 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala
index 0c0d726630..54d4a30553 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala
@@ -14,6 +14,13 @@ import PartialFunction._
*/
final class BCodeAsmCommon[G <: Global](val global: G) {
import global._
+ import definitions._
+
+ val ExcludedForwarderFlags = {
+ import scala.tools.nsc.symtab.Flags._
+ // Should include DEFERRED but this breaks findMember.
+ SPECIALIZED | LIFTED | PROTECTED | STATIC | EXPANDEDNAME | BridgeAndPrivateFlags | MACRO
+ }
/**
* True if `classSym` is an anonymous class or a local class. I.e., false if `classSym` is a
@@ -23,10 +30,10 @@ final class BCodeAsmCommon[G <: Global](val global: G) {
*/
def isAnonymousOrLocalClass(classSym: Symbol): Boolean = {
assert(classSym.isClass, s"not a class: $classSym")
- val res = (classSym.isAnonymousClass || !classSym.originalOwner.isClass)
- // lambda classes are always top-level classes.
- if (res) assert(!classSym.isDelambdafyFunction)
- res
+ // Here used to be an `assert(!classSym.isDelambdafyFunction)`: delambdafy lambda classes are
+ // always top-level. However, SI-8900 shows an example where the weak name-based implementation
+ // of isDelambdafyFunction failed (for a function declared in a package named "lambda").
+ classSym.isAnonymousClass || !classSym.originalOwner.isClass
}
/**
@@ -124,4 +131,36 @@ final class BCodeAsmCommon[G <: Global](val global: G) {
assert(r != NoSymbol, sym.fullLocationString)
r
})(collection.breakOut)
+
+ lazy val AnnotationRetentionPolicyModule = AnnotationRetentionPolicyAttr.companionModule
+ lazy val AnnotationRetentionPolicySourceValue = AnnotationRetentionPolicyModule.tpe.member(TermName("SOURCE"))
+ lazy val AnnotationRetentionPolicyClassValue = AnnotationRetentionPolicyModule.tpe.member(TermName("CLASS"))
+ lazy val AnnotationRetentionPolicyRuntimeValue = AnnotationRetentionPolicyModule.tpe.member(TermName("RUNTIME"))
+
+ /** Whether an annotation should be emitted as a Java annotation
+ * .initialize: if 'annot' is read from pickle, atp might be un-initialized
+ */
+ def shouldEmitAnnotation(annot: AnnotationInfo) = {
+ annot.symbol.initialize.isJavaDefined &&
+ annot.matches(ClassfileAnnotationClass) &&
+ retentionPolicyOf(annot) != AnnotationRetentionPolicySourceValue &&
+ annot.args.isEmpty
+ }
+
+ def isRuntimeVisible(annot: AnnotationInfo): Boolean = {
+ annot.atp.typeSymbol.getAnnotation(AnnotationRetentionAttr) match {
+ case Some(retentionAnnot) =>
+ retentionAnnot.assocs.contains(nme.value -> LiteralAnnotArg(Constant(AnnotationRetentionPolicyRuntimeValue)))
+ case _ =>
+ // SI-8926: if the annotation class symbol doesn't have a @RetentionPolicy annotation, the
+ // annotation is emitted with visibility `RUNTIME`
+ true
+ }
+ }
+
+ private def retentionPolicyOf(annot: AnnotationInfo): Symbol =
+ annot.atp.typeSymbol.getAnnotation(AnnotationRetentionAttr).map(_.assocs).map(assoc =>
+ assoc.collectFirst {
+ case (`nme`.value, LiteralAnnotArg(Constant(value: Symbol))) => value
+ }).flatten.getOrElse(AnnotationRetentionPolicyClassValue)
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
index 14bffd67ab..806d4b277c 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
@@ -469,6 +469,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
trait BCAnnotGen extends BCInnerClassGen {
import genASM.{ubytesToCharArray, arrEncode}
+ import bCodeAsmCommon.{shouldEmitAnnotation, isRuntimeVisible}
/*
* can-multi-thread
@@ -533,17 +534,6 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
}
}
- /* Whether an annotation should be emitted as a Java annotation
- * .initialize: if 'annot' is read from pickle, atp might be un-initialized
- *
- * must-single-thread
- */
- private def shouldEmitAnnotation(annot: AnnotationInfo) =
- annot.symbol.initialize.isJavaDefined &&
- annot.matches(definitions.ClassfileAnnotationClass) &&
- annot.args.isEmpty &&
- !annot.matches(definitions.DeprecatedAttr)
-
/*
* In general,
* must-single-thread
@@ -563,7 +553,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
for(annot <- annotations; if shouldEmitAnnotation(annot)) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
- val av = cw.visitAnnotation(descriptor(typ), true)
+ val av = cw.visitAnnotation(descriptor(typ), isRuntimeVisible(annot))
emitAssocs(av, assocs)
}
}
@@ -575,7 +565,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
for(annot <- annotations; if shouldEmitAnnotation(annot)) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
- val av = mw.visitAnnotation(descriptor(typ), true)
+ val av = mw.visitAnnotation(descriptor(typ), isRuntimeVisible(annot))
emitAssocs(av, assocs)
}
}
@@ -587,7 +577,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
for(annot <- annotations; if shouldEmitAnnotation(annot)) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
- val av = fw.visitAnnotation(descriptor(typ), true)
+ val av = fw.visitAnnotation(descriptor(typ), isRuntimeVisible(annot))
emitAssocs(av, assocs)
}
}
@@ -602,7 +592,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
annot <- annots) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
- val pannVisitor: asm.AnnotationVisitor = jmethod.visitParameterAnnotation(idx, descriptor(typ), true)
+ val pannVisitor: asm.AnnotationVisitor = jmethod.visitParameterAnnotation(idx, descriptor(typ), isRuntimeVisible(annot))
emitAssocs(pannVisitor, assocs)
}
}
@@ -625,13 +615,6 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
trait BCForwardersGen extends BCAnnotGen with BCJGenSigGen {
- // -----------------------------------------------------------------------------------------
- // Static forwarders (related to mirror classes but also present in
- // a plain class lacking companion module, for details see `isCandidateForForwarders`).
- // -----------------------------------------------------------------------------------------
-
- val ExcludedForwarderFlags = genASM.ExcludedForwarderFlags
-
/* Adds a @remote annotation, actual use unknown.
*
* Invoked from genMethod() and addForwarder().
@@ -727,7 +710,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
}
debuglog(s"Potentially conflicting names for forwarders: $conflictingNames")
- for (m <- moduleClass.info.membersBasedOnFlags(ExcludedForwarderFlags, symtab.Flags.METHOD)) {
+ for (m <- moduleClass.info.membersBasedOnFlags(bCodeAsmCommon.ExcludedForwarderFlags, symtab.Flags.METHOD)) {
if (m.isType || m.isDeferred || (m.owner eq definitions.ObjectClass) || m.isConstructor)
debuglog(s"No forwarder for '$m' from $jclassName to '$moduleClass'")
else if (conflictingNames(m.name))
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index 7c4c02c2d3..d0a12c32e5 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -20,7 +20,7 @@ import scala.annotation.tailrec
*
* Documentation at http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/2012Q2/GenASM.pdf
*/
-abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { self =>
+abstract class GenASM extends SubComponent with BytecodeWriters { self =>
import global._
import icodes._
import icodes.opcodes._
@@ -99,6 +99,63 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
}
}
+ private def isJavaEntryPoint(icls: IClass) = {
+ val sym = icls.symbol
+ def fail(msg: String, pos: Position = sym.pos) = {
+ reporter.warning(sym.pos,
+ sym.name + " has a main method with parameter type Array[String], but " + sym.fullName('.') + " will not be a runnable program.\n" +
+ " Reason: " + msg
+ // TODO: make this next claim true, if possible
+ // by generating valid main methods as static in module classes
+ // not sure what the jvm allows here
+ // + " You can still run the program by calling it as " + sym.javaSimpleName + " instead."
+ )
+ false
+ }
+ def failNoForwarder(msg: String) = {
+ fail(msg + ", which means no static forwarder can be generated.\n")
+ }
+ val possibles = if (sym.hasModuleFlag) (sym.tpe nonPrivateMember nme.main).alternatives else Nil
+ val hasApproximate = possibles exists { m =>
+ m.info match {
+ case MethodType(p :: Nil, _) => p.tpe.typeSymbol == ArrayClass
+ case _ => false
+ }
+ }
+ // At this point it's a module with a main-looking method, so either succeed or warn that it isn't.
+ hasApproximate && {
+ // Before erasure so we can identify generic mains.
+ enteringErasure {
+ val companion = sym.linkedClassOfClass
+
+ if (hasJavaMainMethod(companion))
+ failNoForwarder("companion contains its own main method")
+ else if (companion.tpe.member(nme.main) != NoSymbol)
+ // this is only because forwarders aren't smart enough yet
+ failNoForwarder("companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)")
+ else if (companion.isTrait)
+ failNoForwarder("companion is a trait")
+ // Now either succeeed, or issue some additional warnings for things which look like
+ // attempts to be java main methods.
+ else (possibles exists isJavaMainMethod) || {
+ possibles exists { m =>
+ m.info match {
+ case PolyType(_, _) =>
+ fail("main methods cannot be generic.")
+ case MethodType(params, res) =>
+ if (res.typeSymbol :: params exists (_.isAbstractType))
+ fail("main methods cannot refer to type parameters or abstract types.", m.pos)
+ else
+ isJavaMainMethod(m) || fail("main method must have exact signature (Array[String])Unit", m.pos)
+ case tp =>
+ fail("don't know what this is: " + tp, m.pos)
+ }
+ }
+ }
+ }
+ }
+ }
+
override def run() {
if (settings.debug)
@@ -807,15 +864,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
for (ThrownException(exc) <- excs.distinct)
yield javaName(exc)
- /** Whether an annotation should be emitted as a Java annotation
- * .initialize: if 'annot' is read from pickle, atp might be un-initialized
- */
- private def shouldEmitAnnotation(annot: AnnotationInfo) =
- annot.symbol.initialize.isJavaDefined &&
- annot.matches(ClassfileAnnotationClass) &&
- annot.args.isEmpty &&
- !annot.matches(DeprecatedAttr)
-
def getCurrentCUnit(): CompilationUnit
def getGenericSignature(sym: Symbol, owner: Symbol) = self.getGenericSignature(sym, owner, getCurrentCUnit())
@@ -877,7 +925,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
for(annot <- annotations; if shouldEmitAnnotation(annot)) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
- val av = cw.visitAnnotation(descriptor(typ), true)
+ val av = cw.visitAnnotation(descriptor(typ), isRuntimeVisible(annot))
emitAssocs(av, assocs)
}
}
@@ -886,7 +934,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
for(annot <- annotations; if shouldEmitAnnotation(annot)) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
- val av = mw.visitAnnotation(descriptor(typ), true)
+ val av = mw.visitAnnotation(descriptor(typ), isRuntimeVisible(annot))
emitAssocs(av, assocs)
}
}
@@ -895,7 +943,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
for(annot <- annotations; if shouldEmitAnnotation(annot)) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
- val av = fw.visitAnnotation(descriptor(typ), true)
+ val av = fw.visitAnnotation(descriptor(typ), isRuntimeVisible(annot))
emitAssocs(av, assocs)
}
}
@@ -907,7 +955,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
annot <- annots) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
- val pannVisitor: asm.AnnotationVisitor = jmethod.visitParameterAnnotation(idx, descriptor(typ), true)
+ val pannVisitor: asm.AnnotationVisitor = jmethod.visitParameterAnnotation(idx, descriptor(typ), isRuntimeVisible(annot))
emitAssocs(pannVisitor, assocs)
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala
deleted file mode 100644
index 2bcde7f7b9..0000000000
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala
+++ /dev/null
@@ -1,83 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2013 LAMP/EPFL
- * @author Jason Zaugg
- */
-
-package scala.tools.nsc
-package backend.jvm
-import scala.tools.nsc.symtab._
-
-/** Code shared between the erstwhile legacy backend (aka GenJVM)
- * and the new backend [[scala.tools.nsc.backend.jvm.GenASM]]. There should be
- * more here, but for now I'm starting with the refactorings that are either
- * straightforward to review or necessary for maintenance.
- */
-trait GenJVMASM {
- val global: Global
- import global._
- import icodes._
- import definitions._
-
- val ExcludedForwarderFlags = {
- import Flags._
- // Should include DEFERRED but this breaks findMember.
- ( SPECIALIZED | LIFTED | PROTECTED | STATIC | EXPANDEDNAME | BridgeAndPrivateFlags | MACRO )
- }
-
- protected def isJavaEntryPoint(icls: IClass) = {
- val sym = icls.symbol
- def fail(msg: String, pos: Position = sym.pos) = {
- reporter.warning(sym.pos,
- sym.name + " has a main method with parameter type Array[String], but " + sym.fullName('.') + " will not be a runnable program.\n" +
- " Reason: " + msg
- // TODO: make this next claim true, if possible
- // by generating valid main methods as static in module classes
- // not sure what the jvm allows here
- // + " You can still run the program by calling it as " + sym.javaSimpleName + " instead."
- )
- false
- }
- def failNoForwarder(msg: String) = {
- fail(msg + ", which means no static forwarder can be generated.\n")
- }
- val possibles = if (sym.hasModuleFlag) (sym.tpe nonPrivateMember nme.main).alternatives else Nil
- val hasApproximate = possibles exists { m =>
- m.info match {
- case MethodType(p :: Nil, _) => p.tpe.typeSymbol == ArrayClass
- case _ => false
- }
- }
- // At this point it's a module with a main-looking method, so either succeed or warn that it isn't.
- hasApproximate && {
- // Before erasure so we can identify generic mains.
- enteringErasure {
- val companion = sym.linkedClassOfClass
-
- if (hasJavaMainMethod(companion))
- failNoForwarder("companion contains its own main method")
- else if (companion.tpe.member(nme.main) != NoSymbol)
- // this is only because forwarders aren't smart enough yet
- failNoForwarder("companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)")
- else if (companion.isTrait)
- failNoForwarder("companion is a trait")
- // Now either succeeed, or issue some additional warnings for things which look like
- // attempts to be java main methods.
- else (possibles exists isJavaMainMethod) || {
- possibles exists { m =>
- m.info match {
- case PolyType(_, _) =>
- fail("main methods cannot be generic.")
- case MethodType(params, res) =>
- if (res.typeSymbol :: params exists (_.isAbstractType))
- fail("main methods cannot refer to type parameters or abstract types.", m.pos)
- else
- isJavaMainMethod(m) || fail("main method must have exact signature (Array[String])Unit", m.pos)
- case tp =>
- fail("don't know what this is: " + tp, m.pos)
- }
- }
- }
- }
- }
- }
-}
diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
index 0b218b711c..5bf611a7b0 100644
--- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
@@ -29,7 +29,7 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr
case INFO => null
}
- private def clabel(severity: Severity): String = {
+ protected def clabel(severity: Severity): String = {
val label0 = label(severity)
if (label0 eq null) "" else label0 + ": "
}
diff --git a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala
index 4727e6d867..060a24d8d4 100644
--- a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala
@@ -35,7 +35,11 @@ trait AbsSettings extends scala.reflect.internal.settings.AbsSettings {
case s: AbsSettings => this.userSetSettings == s.userSetSettings
case _ => false
}
- override def toString() = "Settings {\n%s}\n" format (userSetSettings map (" " + _ + "\n")).mkString
+ override def toString() = {
+ val uss = userSetSettings
+ val indent = if (uss.nonEmpty) " " * 2 else ""
+ uss.mkString(f"Settings {%n$indent", f"%n$indent", f"%n}%n")
+ }
def toConciseString = userSetSettings.mkString("(", " ", ")")
def checkDependencies =
diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
index bbe21477cb..23611bb629 100644
--- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
@@ -125,14 +125,26 @@ class MutableSettings(val errorFn: String => Unit)
case Some(cmd) => setter(cmd)(args)
}
- // if arg is of form -Xfoo:bar,baz,quux
- def parseColonArg(s: String): Option[List[String]] = {
- val (p, args) = StringOps.splitWhere(s, _ == ':', doDropIndex = true) getOrElse (return None)
-
- // any non-Nil return value means failure and we return s unmodified
- tryToSetIfExists(p, (args split ",").toList, (s: Setting) => s.tryToSetColon _)
+ // -Xfoo: clears Clearables
+ def clearIfExists(cmd: String): Option[List[String]] = lookupSetting(cmd) match {
+ case Some(c: Clearable) => c.clear() ; Some(Nil)
+ case Some(s) => s.errorAndValue(s"Missing argument to $cmd", None)
+ case None => None
}
+ // if arg is of form -Xfoo:bar,baz,quux
+ // the entire arg is consumed, so return None for failure
+ // any non-Nil return value means failure and we return s unmodified
+ def parseColonArg(s: String): Option[List[String]] =
+ if (s endsWith ":") {
+ clearIfExists(s.init)
+ } else {
+ for {
+ (p, args) <- StringOps.splitWhere(s, _ == ':', doDropIndex = true)
+ rest <- tryToSetIfExists(p, (args split ",").toList, (s: Setting) => s.tryToSetColon _)
+ } yield rest
+ }
+
// if arg is of form -Xfoo or -Xfoo bar (name = "-Xfoo")
def parseNormalArg(p: String, args: List[String]): Option[List[String]] =
tryToSetIfExists(p, args, (s: Setting) => s.tryToSet _)
@@ -532,6 +544,7 @@ class MutableSettings(val errorFn: String => Unit)
def prepend(s: String) = prependPath.value = join(s, prependPath.value)
def append(s: String) = appendPath.value = join(appendPath.value, s)
+ override def isDefault = super.isDefault && prependPath.isDefault && appendPath.isDefault
override def value = join(
prependPath.value,
super.value,
diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
index 12e7b23f48..835d338ab3 100644
--- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
+++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
@@ -260,7 +260,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
val captureProxies2 = new LinkedHashMap[Symbol, TermSymbol]
captures foreach {capture =>
- val sym = lambdaClass.newVariable(capture.name.toTermName, capture.pos, SYNTHETIC)
+ val sym = lambdaClass.newVariable(unit.freshTermName(capture.name.toString + "$"), capture.pos, SYNTHETIC)
sym setInfo capture.info
captureProxies2 += ((capture, sym))
}
diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala
index fa53ef48b5..4662ef6224 100644
--- a/src/compiler/scala/tools/nsc/transform/Flatten.scala
+++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala
@@ -77,8 +77,11 @@ abstract class Flatten extends InfoTransform {
if (sym.isTerm && !sym.isStaticModule) {
decls1 enter sym
if (sym.isModule) {
- // Nested, non-static moduls are transformed to methods.
- assert(sym.isMethod, s"Non-static $sym should have the lateMETHOD flag from RefChecks")
+ // In theory, we could assert(sym.isMethod), because nested, non-static moduls are
+ // transformed to methods (lateMETHOD flag added in RefChecks). But this requires
+ // forcing sym.info (see comment on isModuleNotMethod), which forces stub symbols
+ // too eagerly (SI-8907).
+
// Note that module classes are not entered into the 'decls' of the ClassInfoType
// of the outer class, only the module symbols are. So the current loop does
// not visit module classes. Therefore we set the LIFTED flag here for module
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
index a8852a3ff3..21e90b1d78 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
@@ -172,7 +172,6 @@ trait TreeAndTypeAnalysis extends Debugging {
// a type is "uncheckable" (for exhaustivity) if we don't statically know its subtypes (i.e., it's unsealed)
// we consider tuple types with at least one component of a checkable type as a checkable type
def uncheckableType(tp: Type): Boolean = {
- def tupleComponents(tp: Type) = tp.normalize.typeArgs
val checkable = (
(isTupleType(tp) && tupleComponents(tp).exists(tp => !uncheckableType(tp)))
|| enumerateSubtypes(tp).nonEmpty)
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala
index 1974befb45..3abec521df 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala
@@ -550,8 +550,24 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging {
case _ => false
}
val suppression = Suppression(suppressExhaustive, supressUnreachable)
+ val hasSwitchAnnotation = treeInfo.isSwitchAnnotation(tpt.tpe)
// matches with two or fewer cases need not apply for switchiness (if-then-else will do)
- val requireSwitch = treeInfo.isSwitchAnnotation(tpt.tpe) && casesNoSubstOnly.lengthCompare(2) > 0
+ // `case 1 | 2` is considered as two cases.
+ def exceedsTwoCasesOrAlts = {
+ // avoids traversing the entire list if there are more than 3 elements
+ def lengthMax3[T](l: List[T]): Int = l match {
+ case a :: b :: c :: _ => 3
+ case cases =>
+ cases.map({
+ case AlternativesTreeMaker(_, alts, _) :: _ => lengthMax3(alts)
+ case c => 1
+ }).sum
+ }
+ lengthMax3(casesNoSubstOnly) > 2
+ }
+ val requireSwitch = hasSwitchAnnotation && exceedsTwoCasesOrAlts
+ if (hasSwitchAnnotation && !requireSwitch)
+ reporter.warning(scrut.pos, "matches with two cases or fewer are emitted using if-then-else instead of switch")
(suppression, requireSwitch)
case _ =>
(Suppression.NoSuppression, false)
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 20e462bbce..866ca37303 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -885,22 +885,31 @@ trait ContextErrors {
val WrongNumber, NoParams, ArgsDoNotConform = Value
}
- private def issueAmbiguousTypeErrorUnlessErroneous(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String): Unit =
- if (!(pre.isErroneous || sym1.isErroneous || sym2.isErroneous)) {
- if (sym1.hasDefault && sym2.hasDefault && sym1.enclClass == sym2.enclClass) {
- val methodName = nme.defaultGetterToMethod(sym1.name)
- context.issueAmbiguousError(AmbiguousTypeError(sym1.enclClass.pos,
- "in "+ sym1.enclClass +", multiple overloaded alternatives of " + methodName +
- " define default arguments"))
- } else {
- context.issueAmbiguousError(AmbiguousTypeError(pos,
- ("ambiguous reference to overloaded definition,\n" +
- "both " + sym1 + sym1.locationString + " of type " + pre.memberType(sym1) +
- "\nand " + sym2 + sym2.locationString + " of type " + pre.memberType(sym2) +
- "\nmatch " + rest)
- ))
- }
- }
+ private def issueAmbiguousTypeErrorUnlessErroneous(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String): Unit = {
+ // To avoid stack overflows (SI-8890), we MUST (at least) report when either `validTargets` OR `ambiguousSuppressed`
+ // More details:
+ // If `!context.ambiguousErrors`, `reporter.issueAmbiguousError` (which `context.issueAmbiguousError` forwards to)
+ // buffers ambiguous errors. In this case, to avoid looping, we must issue even if `!validTargets`. (TODO: why?)
+ // When not buffering (and thus reporting to the user), we shouldn't issue unless `validTargets`,
+ // otherwise we report two different errors that trace back to the same root cause,
+ // and unless `validTargets`, we don't know for sure the ambiguity is real anyway.
+ val validTargets = !(pre.isErroneous || sym1.isErroneous || sym2.isErroneous)
+ val ambiguousBuffered = !context.ambiguousErrors
+ if (validTargets || ambiguousBuffered)
+ context.issueAmbiguousError(
+ if (sym1.hasDefault && sym2.hasDefault && sym1.enclClass == sym2.enclClass) {
+ val methodName = nme.defaultGetterToMethod(sym1.name)
+ AmbiguousTypeError(sym1.enclClass.pos,
+ s"in ${sym1.enclClass}, multiple overloaded alternatives of $methodName define default arguments")
+
+ } else {
+ AmbiguousTypeError(pos,
+ "ambiguous reference to overloaded definition,\n" +
+ s"both ${sym1.fullLocationString} of type ${pre.memberType(sym1)}\n" +
+ s"and ${sym2.fullLocationString} of type ${pre.memberType(sym2)}\n" +
+ s"match $rest")
+ })
+ }
def AccessError(tree: Tree, sym: Symbol, ctx: Context, explanation: String): AbsTypeError =
AccessError(tree, sym, ctx.enclClass.owner.thisType, ctx.enclClass.owner, explanation)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index b498d9e667..aae2d24b32 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1726,7 +1726,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if ((clazz isNonBottomSubClass ClassfileAnnotationClass) && (clazz != ClassfileAnnotationClass)) {
if (!clazz.owner.isPackageClass)
context.error(clazz.pos, "inner classes cannot be classfile annotations")
- else restrictionWarning(cdef.pos, unit,
+ // Ignore @SerialVersionUID, because it is special-cased and handled completely differently.
+ // It only extends ClassfileAnnotationClass instead of StaticAnnotation to get the enforcement
+ // of constant argument values "for free". Related to SI-7041.
+ else if (clazz != SerialVersionUIDAttr) restrictionWarning(cdef.pos, unit,
"""|subclassing Classfile does not
|make your annotation visible at runtime. If that is what
|you want, you must write the annotation class in Java.""".stripMargin)
diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala
index a8731a51b1..d3a7db6968 100644
--- a/src/library/scala/collection/TraversableLike.scala
+++ b/src/library/scala/collection/TraversableLike.scala
@@ -253,7 +253,7 @@ trait TraversableLike[+A, +Repr] extends Any
b.result
}
- private[scala] def filterImpl(p: A => Boolean, isFlipped: Boolean): Repr = {
+ private def filterImpl(p: A => Boolean, isFlipped: Boolean): Repr = {
val b = newBuilder
for (x <- this)
if (p(x) != isFlipped) b += x
diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala
index 91a4e1c43d..714d5117d3 100644
--- a/src/library/scala/collection/immutable/Stream.scala
+++ b/src/library/scala/collection/immutable/Stream.scala
@@ -499,16 +499,6 @@ self =>
)
else super.flatMap(f)(bf)
- override private[scala] def filterImpl(p: A => Boolean, isFlipped: Boolean): Stream[A] = {
- // optimization: drop leading prefix of elems for which f returns false
- // var rest = this dropWhile (!p(_)) - forget DRY principle - GC can't collect otherwise
- var rest = this
- while (!rest.isEmpty && p(rest.head) == isFlipped) rest = rest.tail
- // private utility func to avoid `this` on stack (would be needed for the lazy arg)
- if (rest.nonEmpty) Stream.filteredTail(rest, p, isFlipped)
- else Stream.Empty
- }
-
/** Returns all the elements of this `Stream` that satisfy the predicate `p`
* in a new `Stream` - i.e., it is still a lazy data structure. The order of
* the elements is preserved
@@ -522,7 +512,15 @@ self =>
* // produces
* }}}
*/
- override def filter(p: A => Boolean): Stream[A] = filterImpl(p, isFlipped = false) // This override is only left in 2.11 because of binary compatibility, see PR #3925
+ override def filter(p: A => Boolean): Stream[A] = {
+ // optimization: drop leading prefix of elems for which f returns false
+ // var rest = this dropWhile (!p(_)) - forget DRY principle - GC can't collect otherwise
+ var rest = this
+ while (!rest.isEmpty && !p(rest.head)) rest = rest.tail
+ // private utility func to avoid `this` on stack (would be needed for the lazy arg)
+ if (rest.nonEmpty) Stream.filteredTail(rest, p)
+ else Stream.Empty
+ }
override final def withFilter(p: A => Boolean): StreamWithFilter = new StreamWithFilter(p)
@@ -1286,8 +1284,8 @@ object Stream extends SeqFactory[Stream] {
else cons(start, range(start + step, end, step))
}
- private[immutable] def filteredTail[A](stream: Stream[A], p: A => Boolean, isFlipped: Boolean) = {
- cons(stream.head, stream.tail.filterImpl(p, isFlipped))
+ private[immutable] def filteredTail[A](stream: Stream[A], p: A => Boolean) = {
+ cons(stream.head, stream.tail filter p)
}
private[immutable] def collectedTail[A, B, That](head: B, stream: Stream[A], pf: PartialFunction[A, B], bf: CanBuildFrom[Stream[A], B, That]) = {
diff --git a/src/library/scala/collection/immutable/StringLike.scala b/src/library/scala/collection/immutable/StringLike.scala
index 738b294ce6..bf93a38f55 100644
--- a/src/library/scala/collection/immutable/StringLike.scala
+++ b/src/library/scala/collection/immutable/StringLike.scala
@@ -135,23 +135,29 @@ self =>
def linesIterator: Iterator[String] =
linesWithSeparators map (line => new WrappedString(line).stripLineEnd)
- /** Returns this string with first character converted to upper case */
+ /** Returns this string with first character converted to upper case.
+ * If the first character of the string is capitalized, it is returned unchanged.
+ */
def capitalize: String =
if (toString == null) null
else if (toString.length == 0) ""
+ else if (toString.charAt(0).isUpper) toString
else {
val chars = toString.toCharArray
chars(0) = chars(0).toUpper
new String(chars)
}
- /** Returns this string with the given `prefix` stripped. */
+ /** Returns this string with the given `prefix` stripped. If this string does not
+ * start with `prefix`, it is returned unchanged.
+ */
def stripPrefix(prefix: String) =
if (toString.startsWith(prefix)) toString.substring(prefix.length)
else toString
/** Returns this string with the given `suffix` stripped. If this string does not
- * end with `suffix`, it is returned unchanged. */
+ * end with `suffix`, it is returned unchanged.
+ */
def stripSuffix(suffix: String) =
if (toString.endsWith(suffix)) toString.substring(0, toString.length() - suffix.length)
else toString
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index f5662b47c2..666a3a5e64 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -653,6 +653,7 @@ trait Definitions extends api.StandardDefinitions {
// tends to change the course of events by forcing types.
def isFunctionType(tp: Type) = isFunctionTypeDirect(tp.dealiasWiden)
def isTupleType(tp: Type) = isTupleTypeDirect(tp.dealiasWiden)
+ def tupleComponents(tp: Type) = tp.dealiasWiden.typeArgs
lazy val ProductRootClass: ClassSymbol = requiredClass[scala.Product]
def Product_productArity = getMemberMethod(ProductRootClass, nme.productArity)
@@ -837,7 +838,7 @@ trait Definitions extends api.StandardDefinitions {
def typeOfMemberNamedApply(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.apply)(IntTpe))
def typeOfMemberNamedDrop(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.drop)(IntTpe))
def typesOfSelectors(tp: Type) =
- if (isTupleType(tp)) tp.typeArgs
+ if (isTupleType(tp)) tupleComponents(tp)
else getterMemberTypes(tp, productSelectors(tp))
// SI-8128 Still using the type argument of the base type at Seq/Option if this is an old-style (2.10 compatible)
@@ -1089,6 +1090,10 @@ trait Definitions extends api.StandardDefinitions {
lazy val ClassfileAnnotationClass = requiredClass[scala.annotation.ClassfileAnnotation]
lazy val StaticAnnotationClass = requiredClass[scala.annotation.StaticAnnotation]
+ // Java retention annotations
+ lazy val AnnotationRetentionAttr = requiredClass[java.lang.annotation.Retention]
+ lazy val AnnotationRetentionPolicyAttr = requiredClass[java.lang.annotation.RetentionPolicy]
+
// Annotations
lazy val BridgeClass = requiredClass[scala.annotation.bridge]
lazy val ElidableMethodClass = requiredClass[scala.annotation.elidable]
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 3296b2322f..70fb9dfa8e 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -734,31 +734,31 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def hasGetter = isTerm && nme.isLocalName(name)
- /** A little explanation for this confusing situation.
- * Nested modules which have no static owner when ModuleDefs
- * are eliminated (refchecks) are given the lateMETHOD flag,
- * which makes them appear as methods after refchecks.
- * Here's an example where one can see all four of FF FT TF TT
- * for (isStatic, isMethod) at various phases.
+ /**
+ * Nested modules which have no static owner when ModuleDefs are eliminated (refchecks) are
+ * given the lateMETHOD flag, which makes them appear as methods after refchecks.
+ *
+ * Note: the lateMETHOD flag is added lazily in the info transformer of the RefChecks phase.
+ * This means that forcing the `sym.info` may change the value of `sym.isMethod`. Forcing the
+ * info is in the responsability of the caller. Doing it eagerly here was tried (0ccdb151f) but
+ * has proven to lead to bugs (SI-8907).
*
- * trait A1 { case class Quux() }
- * object A2 extends A1 { object Flax }
- * // -- namer object Quux in trait A1
- * // -M flatten object Quux in trait A1
- * // S- flatten object Flax in object A2
- * // -M posterasure object Quux in trait A1
- * // -M jvm object Quux in trait A1
- * // SM jvm object Quux in object A2
+ * Here's an example where one can see all four of FF FT TF TT for (isStatic, isMethod) at
+ * various phases.
*
- * So "isModuleNotMethod" exists not for its achievement in
- * brevity, but to encapsulate the relevant condition.
+ * trait A1 { case class Quux() }
+ * object A2 extends A1 { object Flax }
+ * // -- namer object Quux in trait A1
+ * // -M flatten object Quux in trait A1
+ * // S- flatten object Flax in object A2
+ * // -M posterasure object Quux in trait A1
+ * // -M jvm object Quux in trait A1
+ * // SM jvm object Quux in object A2
+ *
+ * So "isModuleNotMethod" exists not for its achievement in brevity, but to encapsulate the
+ * relevant condition.
*/
- def isModuleNotMethod = {
- if (isModule) {
- if (phase.refChecked) this.info // force completion to make sure lateMETHOD is there.
- !isMethod
- } else false
- }
+ def isModuleNotMethod = isModule && !isMethod
// After RefChecks, the `isStatic` check is mostly redundant: all non-static modules should
// be methods (and vice versa). There's a corner case on the vice-versa with mixed-in module
diff --git a/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala b/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala
index 10a8b4c812..30dcbc21ca 100644
--- a/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala
+++ b/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala
@@ -5,16 +5,16 @@
package scala
package reflect.internal.util
-import scala.reflect.io.AbstractFile
+import scala.collection.{ mutable, immutable }
+import scala.reflect.io.{ AbstractFile, Streamable }
+import java.net.{ URL, URLConnection, URLStreamHandler }
import java.security.cert.Certificate
import java.security.{ ProtectionDomain, CodeSource }
-import java.net.{ URL, URLConnection, URLStreamHandler }
-import scala.collection.{ mutable, immutable }
+import java.util.{ Collections => JCollections, Enumeration => JEnumeration }
-/**
- * A class loader that loads files from a {@link scala.tools.nsc.io.AbstractFile}.
+/** A class loader that loads files from a {@link scala.tools.nsc.io.AbstractFile}.
*
- * @author Lex Spoon
+ * @author Lex Spoon
*/
class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader)
extends ClassLoader(parent)
@@ -22,7 +22,7 @@ class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader)
{
protected def classNameToPath(name: String): String =
if (name endsWith ".class") name
- else name.replace('.', '/') + ".class"
+ else s"${name.replace('.', '/')}.class"
protected def findAbstractFile(name: String): AbstractFile = {
var file: AbstractFile = root
@@ -56,35 +56,25 @@ class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader)
file
}
- // parent delegation in JCL uses getResource; so either add parent.getResAsStream
- // or implement findResource, which we do here as a study in scarlet (my complexion
- // after looking at CLs and URLs)
- override def findResource(name: String): URL = findAbstractFile(name) match {
+ override protected def findClass(name: String): Class[_] = {
+ val bytes = classBytes(name)
+ if (bytes.length == 0)
+ throw new ClassNotFoundException(name)
+ else
+ defineClass(name, bytes, 0, bytes.length, protectionDomain)
+ }
+ override protected def findResource(name: String): URL = findAbstractFile(name) match {
case null => null
- case file => new URL(null, "repldir:" + file.path, new URLStreamHandler {
+ case file => new URL(null, s"memory:${file.path}", new URLStreamHandler {
override def openConnection(url: URL): URLConnection = new URLConnection(url) {
- override def connect() { }
+ override def connect() = ()
override def getInputStream = file.input
}
})
}
-
- // this inverts delegation order: super.getResAsStr calls parent.getRes if we fail
- override def getResourceAsStream(name: String) = findAbstractFile(name) match {
- case null => super.getResourceAsStream(name)
- case file => file.input
- }
- // ScalaClassLoader.classBytes uses getResAsStream, so we'll try again before delegating
- override def classBytes(name: String): Array[Byte] = findAbstractFile(classNameToPath(name)) match {
- case null => super.classBytes(name)
- case file => file.toByteArray
- }
- override def findClass(name: String): Class[_] = {
- val bytes = classBytes(name)
- if (bytes.length == 0)
- throw new ClassNotFoundException(name)
- else
- defineClass(name, bytes, 0, bytes.length, protectionDomain)
+ override protected def findResources(name: String): JEnumeration[URL] = findResource(name) match {
+ case null => JCollections.enumeration(JCollections.emptyList[URL]) //JCollections.emptyEnumeration[URL]
+ case url => JCollections.enumeration(JCollections.singleton(url))
}
lazy val protectionDomain = {
@@ -106,15 +96,13 @@ class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader)
throw new UnsupportedOperationException()
}
- override def getPackage(name: String): Package = {
- findAbstractDir(name) match {
- case null => super.getPackage(name)
- case file => packages.getOrElseUpdate(name, {
- val ctor = classOf[Package].getDeclaredConstructor(classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[URL], classOf[ClassLoader])
- ctor.setAccessible(true)
- ctor.newInstance(name, null, null, null, null, null, null, null, this)
- })
- }
+ override def getPackage(name: String): Package = findAbstractDir(name) match {
+ case null => super.getPackage(name)
+ case file => packages.getOrElseUpdate(name, {
+ val ctor = classOf[Package].getDeclaredConstructor(classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[URL], classOf[ClassLoader])
+ ctor.setAccessible(true)
+ ctor.newInstance(name, null, null, null, null, null, null, null, this)
+ })
}
override def getPackages(): Array[Package] =
diff --git a/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala b/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala
index 63ea6e2c49..41011f6c6b 100644
--- a/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala
+++ b/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala
@@ -53,8 +53,10 @@ trait ScalaClassLoader extends JClassLoader {
}
/** An InputStream representing the given class name, or null if not found. */
- def classAsStream(className: String) =
- getResourceAsStream(className.replaceAll("""\.""", "/") + ".class")
+ def classAsStream(className: String) = getResourceAsStream {
+ if (className endsWith ".class") className
+ else s"${className.replace('.', '/')}.class" // classNameToPath
+ }
/** Run the main method of a class to be loaded by this classloader */
def run(objectName: String, arguments: Seq[String]) {
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index dcd262c288..18a3c5d63f 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -360,6 +360,8 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
definitions.AnnotationClass
definitions.ClassfileAnnotationClass
definitions.StaticAnnotationClass
+ definitions.AnnotationRetentionAttr
+ definitions.AnnotationRetentionPolicyAttr
definitions.BridgeClass
definitions.ElidableMethodClass
definitions.ImplicitNotFoundClass
diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
index 6197aea93d..6e18682494 100644
--- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
@@ -75,6 +75,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
def history = in.history
// classpath entries added via :cp
+ @deprecated("Use reset, replay or require to update class path", since = "2.11")
var addedClasspath: String = ""
/** A reverse list of commands to replay if the user requests a :replay */
@@ -207,7 +208,6 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
/** Standard commands **/
lazy val standardCommands = List(
- cmd("cp", "<path>", "add a jar or directory to the classpath", addClasspath),
cmd("edit", "<id>|<line>", "edit history", editCommand),
cmd("help", "[command]", "print this summary or command-specific help", helpCommand),
historyCommand,
@@ -220,11 +220,12 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
cmd("paste", "[-raw] [path]", "enter paste mode or paste a file", pasteCommand),
nullary("power", "enable power user mode", powerCmd),
nullary("quit", "exit the interpreter", () => Result(keepRunning = false, None)),
- nullary("replay", "reset execution and replay all previous commands", replay),
- nullary("reset", "reset the repl to its initial state, forgetting all session entries", resetCommand),
+ cmd("replay", "[options]", "reset the repl and replay all previous commands", replayCommand),
+ //cmd("require", "<path>", "add a jar or directory to the classpath", require), // TODO
+ cmd("reset", "[options]", "reset the repl to its initial state, forgetting all session entries", resetCommand),
cmd("save", "<path>", "save replayable session to a file", saveCommand),
shCommand,
- cmd("settings", "[+|-]<options>", "+enable/-disable flags, set compiler options", changeSettings),
+ cmd("settings", "<options>", "update compiler options, if possible; see reset", changeSettings),
nullary("silent", "disable/enable automatic printing of results", verbosity),
cmd("type", "[-v] <expr>", "display the type of an expression without evaluating it", typeCommand),
cmd("kind", "[-v] <expr>", "display the kind of expression's type", kindCommand),
@@ -304,57 +305,23 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
intp.lastWarnings foreach { case (pos, msg) => intp.reporter.warning(pos, msg) }
}
- private def changeSettings(args: String): Result = {
- def showSettings() = {
- for (s <- settings.userSetSettings.toSeq.sorted) echo(s.toString)
- }
- def updateSettings() = {
- // put aside +flag options
- val (pluses, rest) = (args split "\\s+").toList partition (_.startsWith("+"))
- val tmps = new Settings
- val (ok, leftover) = tmps.processArguments(rest, processAll = true)
- if (!ok) echo("Bad settings request.")
- else if (leftover.nonEmpty) echo("Unprocessed settings.")
- else {
- // boolean flags set-by-user on tmp copy should be off, not on
- val offs = tmps.userSetSettings filter (_.isInstanceOf[Settings#BooleanSetting])
- val (minuses, nonbools) = rest partition (arg => offs exists (_ respondsTo arg))
- // update non-flags
- settings.processArguments(nonbools, processAll = true)
- // also snag multi-value options for clearing, e.g. -Ylog: and -language:
- for {
- s <- settings.userSetSettings
- if s.isInstanceOf[Settings#MultiStringSetting] || s.isInstanceOf[Settings#PhasesSetting]
- if nonbools exists (arg => arg.head == '-' && arg.last == ':' && (s respondsTo arg.init))
- } s match {
- case c: Clearable => c.clear()
- case _ =>
- }
- def update(bs: Seq[String], name: String=>String, setter: Settings#Setting=>Unit) = {
- for (b <- bs)
- settings.lookupSetting(name(b)) match {
- case Some(s) =>
- if (s.isInstanceOf[Settings#BooleanSetting]) setter(s)
- else echo(s"Not a boolean flag: $b")
- case _ =>
- echo(s"Not an option: $b")
- }
- }
- update(minuses, identity, _.tryToSetFromPropertyValue("false")) // turn off
- update(pluses, "-" + _.drop(1), _.tryToSet(Nil)) // turn on
- }
- }
- if (args.isEmpty) showSettings() else updateSettings()
+ private def changeSettings(line: String): Result = {
+ def showSettings() = for (s <- settings.userSetSettings.toSeq.sorted) echo(s.toString)
+ if (line.isEmpty) showSettings() else { updateSettings(line) ; () }
+ }
+ private def updateSettings(line: String) = {
+ val (ok, rest) = settings.processArguments(words(line), processAll = false)
+ ok && rest.isEmpty
}
private def javapCommand(line: String): Result = {
if (javap == null)
- ":javap unavailable, no tools.jar at %s. Set JDK_HOME.".format(jdkHome)
+ s":javap unavailable, no tools.jar at $jdkHome. Set JDK_HOME."
else if (line == "")
":javap [-lcsvp] [path1 path2 ...]"
else
javap(words(line)) foreach { res =>
- if (res.isError) return "Failed: " + res.value
+ if (res.isError) return s"Failed: ${res.value}"
else res.show()
}
}
@@ -445,8 +412,14 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
}
private def readOneLine() = {
+ import scala.io.AnsiColor.{ MAGENTA, RESET }
out.flush()
- in readLine prompt
+ in readLine (
+ if (replProps.colorOk)
+ MAGENTA + prompt + RESET
+ else
+ prompt
+ )
}
/** The main read-eval-print loop for the repl. It calls
@@ -472,8 +445,16 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
}
/** create a new interpreter and replay the given commands */
- def replay() {
- reset()
+ def replayCommand(line: String): Unit = {
+ def run(destructive: Boolean): Unit = {
+ if (destructive) createInterpreter() else reset()
+ replay()
+ }
+ if (line.isEmpty) run(destructive = false)
+ else if (updateSettings(line)) run(destructive = true)
+ }
+ /** Announces as it replays. */
+ def replay(): Unit = {
if (replayCommandStack.isEmpty)
echo("Nothing to replay.")
else for (cmd <- replayCommands) {
@@ -482,21 +463,28 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
echo("")
}
}
- def resetCommand() {
- echo("Resetting interpreter state.")
- if (replayCommandStack.nonEmpty) {
- echo("Forgetting this session history:\n")
- replayCommands foreach echo
- echo("")
- replayCommandStack = Nil
+ /** `reset` the interpreter in an attempt to start fresh.
+ * Supplying settings creates a new compiler.
+ */
+ def resetCommand(line: String): Unit = {
+ def run(destructive: Boolean): Unit = {
+ echo("Resetting interpreter state.")
+ if (replayCommandStack.nonEmpty) {
+ echo("Forgetting this session history:\n")
+ replayCommands foreach echo
+ echo("")
+ replayCommandStack = Nil
+ }
+ if (intp.namedDefinedTerms.nonEmpty)
+ echo("Forgetting all expression results and named terms: " + intp.namedDefinedTerms.mkString(", "))
+ if (intp.definedTypes.nonEmpty)
+ echo("Forgetting defined types: " + intp.definedTypes.mkString(", "))
+ if (destructive) createInterpreter() else reset()
}
- if (intp.namedDefinedTerms.nonEmpty)
- echo("Forgetting all expression results and named terms: " + intp.namedDefinedTerms.mkString(", "))
- if (intp.definedTypes.nonEmpty)
- echo("Forgetting defined types: " + intp.definedTypes.mkString(", "))
-
- reset()
+ if (line.isEmpty) run(destructive = false)
+ else if (updateSettings(line)) run(destructive = true)
}
+ /** Resets without announcements. */
def reset() {
intp.reset()
unleashAndSetPhase()
@@ -619,6 +607,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
else File(filename).printlnAll(replayCommands: _*)
)
+ @deprecated("Use reset, replay or require to update class path", since = "2.11")
def addClasspath(arg: String): Unit = {
val f = File(arg).normalize
if (f.exists) {
diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala
index 6e30b73e0e..20b5a79aaa 100644
--- a/src/repl/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala
@@ -295,22 +295,38 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
def originalPath(name: Name): String = typerOp path name
def originalPath(sym: Symbol): String = typerOp path sym
def flatPath(sym: Symbol): String = flatOp shift sym.javaClassName
+
def translatePath(path: String) = {
val sym = if (path endsWith "$") symbolOfTerm(path.init) else symbolOfIdent(path)
sym.toOption map flatPath
}
+
+ /** If path represents a class resource in the default package,
+ * see if the corresponding symbol has a class file that is a REPL artifact
+ * residing at a different resource path. Translate X.class to $line3/$read$$iw$$iw$X.class.
+ */
+ def translateSimpleResource(path: String): Option[String] = {
+ if (!(path contains '/') && (path endsWith ".class")) {
+ val name = path stripSuffix ".class"
+ val sym = if (name endsWith "$") symbolOfTerm(name.init) else symbolOfIdent(name)
+ def pathOf(s: String) = s"${s.replace('.', '/')}.class"
+ sym.toOption map (s => pathOf(flatPath(s)))
+ } else {
+ None
+ }
+ }
def translateEnclosingClass(n: String) = symbolOfTerm(n).enclClass.toOption map flatPath
+ /** If unable to find a resource foo.class, try taking foo as a symbol in scope
+ * and use its java class name as a resource to load.
+ *
+ * $intp.classLoader classBytes "Bippy" or $intp.classLoader getResource "Bippy.class" just work.
+ */
private class TranslatingClassLoader(parent: ClassLoader) extends util.AbstractFileClassLoader(replOutput.dir, parent) {
- /** Overridden here to try translating a simple name to the generated
- * class name if the original attempt fails. This method is used by
- * getResourceAsStream as well as findClass.
- */
- override protected def findAbstractFile(name: String): AbstractFile =
- super.findAbstractFile(name) match {
- case null if _initializeComplete => translatePath(name) map (super.findAbstractFile(_)) orNull
- case file => file
- }
+ override protected def findAbstractFile(name: String): AbstractFile = super.findAbstractFile(name) match {
+ case null if _initializeComplete => translateSimpleResource(name) map super.findAbstractFile orNull
+ case file => file
+ }
}
private def makeClassLoader(): util.AbstractFileClassLoader =
new TranslatingClassLoader(parentClassLoader match {
diff --git a/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala
index a37cdc2ec8..bcba7b6dfd 100644
--- a/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala
+++ b/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala
@@ -102,6 +102,18 @@ trait MemberHandlers {
class GenericHandler(member: Tree) extends MemberHandler(member)
+ import scala.io.AnsiColor.{ BOLD, BLUE, GREEN, RESET }
+
+ def color(c: String, s: String) =
+ if (replProps.colorOk) string2code(BOLD) + string2code(c) + s + string2code(RESET)
+ else s
+
+ def colorName(s: String) =
+ color(BLUE, string2code(s))
+
+ def colorType(s: String) =
+ color(GREEN, string2code(s))
+
class ValHandler(member: ValDef) extends MemberDefHandler(member) {
val maxStringElements = 1000 // no need to mkString billions of elements
override def definesValue = true
@@ -119,15 +131,20 @@ trait MemberHandlers {
if (replProps.vids) s"""" + f"@$${System.identityHashCode($path)}%8x" + """"
else ""
- """ + "%s%s: %s = " + %s""".format(string2code(prettyName), vidString, string2code(req typeOf name), resultString)
+ val nameString = colorName(prettyName) + vidString
+ val typeString = colorType(req typeOf name)
+ s""" + "$nameString: $typeString = " + $resultString"""
}
}
}
class DefHandler(member: DefDef) extends MemberDefHandler(member) {
override def definesValue = flattensToEmpty(member.vparamss) // true if 0-arity
- override def resultExtractionCode(req: Request) =
- if (mods.isPublic) codegenln(name, ": ", req.typeOf(name)) else ""
+ override def resultExtractionCode(req: Request) = {
+ val nameString = colorName(name)
+ val typeString = colorType(req typeOf name)
+ if (mods.isPublic) s""" + "$nameString: $typeString\\n"""" else ""
+ }
}
abstract class MacroHandler(member: DefDef) extends MemberDefHandler(member) {
diff --git a/src/repl/scala/tools/nsc/interpreter/ReplProps.scala b/src/repl/scala/tools/nsc/interpreter/ReplProps.scala
index 36e6dbbccc..8c4faf7278 100644
--- a/src/repl/scala/tools/nsc/interpreter/ReplProps.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ReplProps.scala
@@ -13,6 +13,9 @@ class ReplProps {
private def bool(name: String) = BooleanProp.keyExists(name)
private def int(name: String) = IntProp(name)
+ // This property is used in TypeDebugging. Let's recycle it.
+ val colorOk = bool("scala.color")
+
val info = bool("scala.repl.info")
val debug = bool("scala.repl.debug")
val trace = bool("scala.repl.trace")
diff --git a/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala b/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala
index 88372334d6..e6f5a4089e 100644
--- a/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala
@@ -32,6 +32,24 @@ class ReplReporter(intp: IMain) extends ConsoleReporter(intp.settings, Console.i
override def warning(pos: Position, msg: String): Unit = withoutTruncating(super.warning(pos, msg))
override def error(pos: Position, msg: String): Unit = withoutTruncating(super.error(pos, msg))
+ import scala.io.AnsiColor.{ RED, YELLOW, RESET }
+
+ def severityColor(severity: Severity): String = severity match {
+ case ERROR => RED
+ case WARNING => YELLOW
+ case INFO => RESET
+ }
+
+ override def print(pos: Position, msg: String, severity: Severity) {
+ val prefix = (
+ if (replProps.colorOk)
+ severityColor(severity) + clabel(severity) + RESET
+ else
+ clabel(severity)
+ )
+ printMessage(pos, prefix + msg)
+ }
+
override def printMessage(msg: String) {
// Avoiding deadlock if the compiler starts logging before
// the lazy val is complete.
diff --git a/src/repl/scala/tools/nsc/interpreter/ReplStrings.scala b/src/repl/scala/tools/nsc/interpreter/ReplStrings.scala
index 43da5c6f12..1664546cab 100644
--- a/src/repl/scala/tools/nsc/interpreter/ReplStrings.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ReplStrings.scala
@@ -28,5 +28,8 @@ trait ReplStrings {
def any2stringOf(x: Any, maxlen: Int) =
"scala.runtime.ScalaRunTime.replStringOf(%s, %s)".format(x, maxlen)
- def words(s: String) = (s.trim split "\\s+" filterNot (_ == "")).toList
+ // no escaped or nested quotes
+ private[this] val inquotes = """(['"])(.*?)\1""".r
+ def unquoted(s: String) = s match { case inquotes(_, w) => w ; case _ => s }
+ def words(s: String) = (s.trim split "\\s+" filterNot (_ == "") map unquoted).toList
}
diff --git a/src/scaladoc/scala/tools/nsc/ScalaDoc.scala b/src/scaladoc/scala/tools/nsc/ScalaDoc.scala
index 52a0c20a11..32a6ba0ce3 100644
--- a/src/scaladoc/scala/tools/nsc/ScalaDoc.scala
+++ b/src/scaladoc/scala/tools/nsc/ScalaDoc.scala
@@ -18,14 +18,10 @@ class ScalaDoc {
val versionMsg = "Scaladoc %s -- %s".format(Properties.versionString, Properties.copyrightString)
def process(args: Array[String]): Boolean = {
- var reporter: ConsoleReporter = null
+ var reporter: ScalaDocReporter = null
val docSettings = new doc.Settings(msg => reporter.error(FakePos("scaladoc"), msg + "\n scaladoc -help gives more information"),
msg => reporter.printMessage(msg))
- reporter = new ConsoleReporter(docSettings) {
- // need to do this so that the Global instance doesn't trash all the
- // symbols just because there was an error
- override def hasErrors = false
- }
+ reporter = new ScalaDocReporter(docSettings)
val command = new ScalaDoc.Command(args.toList, docSettings)
def hasFiles = command.files.nonEmpty || docSettings.uncompilableFiles.nonEmpty
@@ -50,12 +46,18 @@ class ScalaDoc {
}
finally reporter.printSummary()
- // not much point in returning !reporter.hasErrors when it has
- // been overridden with constant false.
- true
+ !reporter.reallyHasErrors
}
}
+class ScalaDocReporter(settings: Settings) extends ConsoleReporter(settings) {
+
+ // need to do sometimes lie so that the Global instance doesn't
+ // trash all the symbols just because there was an error
+ override def hasErrors = false
+ def reallyHasErrors = super.hasErrors
+}
+
object ScalaDoc extends ScalaDoc {
class Command(arguments: List[String], settings: doc.Settings) extends CompilerCommand(arguments, settings) {
override def cmdName = "scaladoc"