summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2014-08-26 14:49:01 +0200
committerLukas Rytz <lukas.rytz@gmail.com>2014-08-26 14:49:01 +0200
commite27d024c386c817030d872b9773171598e11dd8d (patch)
tree6070bb44e3c87be079040dbf1e25f5bb2756703a
parent771724494d4a7e73542c04e8e0b50523745fb7a8 (diff)
parent47908f19e064151140e32819c2edd9e68b34dd0c (diff)
downloadscala-e27d024c386c817030d872b9773171598e11dd8d.tar.gz
scala-e27d024c386c817030d872b9773171598e11dd8d.tar.bz2
scala-e27d024c386c817030d872b9773171598e11dd8d.zip
Merge remote-tracking branch 'upstream/2.11.x' into backports
Conflicts: src/library/scala/util/matching/Regex.scala
-rwxr-xr-xbuild.xml6
-rw-r--r--src/compiler/scala/tools/nsc/CompilationUnits.scala7
-rw-r--r--src/compiler/scala/tools/nsc/CompileServer.scala1
-rw-r--r--src/compiler/scala/tools/nsc/CompileSocket.scala3
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala13
-rw-r--r--src/compiler/scala/tools/nsc/Parsing.scala36
-rw-r--r--src/compiler/scala/tools/nsc/Properties.scala1
-rw-r--r--src/compiler/scala/tools/nsc/Reporting.scala15
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala58
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala53
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/javac/JavaScanners.scala2
-rw-r--r--src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala4
-rw-r--r--src/compiler/scala/tools/nsc/reporters/Reporter.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/TypingTransformers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala112
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala429
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala130
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala142
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala82
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala2
-rw-r--r--src/eclipse/repl/.classpath16
-rw-r--r--src/library/scala/StringContext.scala11
-rw-r--r--src/library/scala/collection/IterableProxy.scala1
-rw-r--r--src/library/scala/collection/MapProxy.scala1
-rw-r--r--src/library/scala/collection/SetProxy.scala1
-rw-r--r--src/library/scala/collection/TraversableProxy.scala1
-rw-r--r--src/library/scala/util/matching/Regex.scala414
-rw-r--r--src/reflect/scala/reflect/api/Quasiquotes.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala10
-rw-r--r--src/reflect/scala/reflect/internal/Reporting.scala3
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ILoop.scala9
-rw-r--r--src/repl/scala/tools/nsc/interpreter/IMain.scala2
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala7
-rw-r--r--test/files/jvm/innerClassAttribute/Classes_1.scala99
-rw-r--r--test/files/jvm/innerClassAttribute/JavaAnnot_1.java3
-rw-r--r--test/files/jvm/innerClassAttribute/Test.scala208
-rw-r--r--test/files/jvm/interpreter.check2
-rw-r--r--test/files/jvm/throws-annot-from-java.check2
-rw-r--r--test/files/jvm/xml05.check2
-rw-r--r--test/files/neg/macro-basic-mamdmi.check10
-rw-r--r--test/files/neg/t3909.check1
-rw-r--r--test/files/neg/t7848-interp-warn.flags2
-rw-r--r--test/files/neg/t8266-invalid-interp.check4
-rw-r--r--test/files/pos/t8013.flags2
-rw-r--r--test/files/pos/t8793.scala15
-rw-r--r--test/files/run/class-symbol-contravariant.check2
-rw-r--r--test/files/run/constant-type.check2
-rw-r--r--test/files/run/constrained-types.check2
-rw-r--r--test/files/run/kind-repl-command.check2
-rw-r--r--test/files/run/lub-visibility.check2
-rw-r--r--test/files/run/macro-bundle-repl.check2
-rw-r--r--test/files/run/macro-repl-basic.check2
-rw-r--r--test/files/run/macro-repl-dontexpand.check2
-rw-r--r--test/files/run/macro-system-properties.check2
-rw-r--r--test/files/run/reflection-equality.check2
-rw-r--r--test/files/run/reflection-magicsymbols-repl.check2
-rw-r--r--test/files/run/reflection-repl-classes.check2
-rw-r--r--test/files/run/reflection-repl-elementary.check2
-rw-r--r--test/files/run/reify-repl-fail-gracefully.check2
-rw-r--r--test/files/run/reify_newimpl_22.check2
-rw-r--r--test/files/run/reify_newimpl_23.check2
-rw-r--r--test/files/run/reify_newimpl_25.check2
-rw-r--r--test/files/run/reify_newimpl_26.check2
-rw-r--r--test/files/run/reify_newimpl_35.check2
-rw-r--r--test/files/run/repl-assign.check2
-rw-r--r--test/files/run/repl-bare-expr.check2
-rw-r--r--test/files/run/repl-colon-type.check2
-rw-r--r--test/files/run/repl-empty-package.check2
-rw-r--r--test/files/run/repl-javap-app.check6
-rw-r--r--test/files/run/repl-out-dir.check2
-rw-r--r--test/files/run/repl-parens.check2
-rw-r--r--test/files/run/repl-paste-2.check2
-rw-r--r--test/files/run/repl-paste-3.check2
-rw-r--r--test/files/run/repl-paste-4.scala2
-rw-r--r--test/files/run/repl-paste-raw.scala2
-rw-r--r--test/files/run/repl-paste.check2
-rw-r--r--test/files/run/repl-power.check2
-rw-r--r--test/files/run/repl-reset.check2
-rw-r--r--test/files/run/repl-save.scala2
-rw-r--r--test/files/run/repl-term-macros.check2
-rw-r--r--test/files/run/repl-transcript.check2
-rw-r--r--test/files/run/repl-trim-stack-trace.scala2
-rw-r--r--test/files/run/repl-type-verbose.check2
-rw-r--r--test/files/run/t3376.check2
-rw-r--r--test/files/run/t4025.check2
-rw-r--r--test/files/run/t4172.check2
-rw-r--r--test/files/run/t4216.check2
-rw-r--r--test/files/run/t4285.check2
-rw-r--r--test/files/run/t4542.check2
-rw-r--r--test/files/run/t4594-repl-settings.scala2
-rw-r--r--test/files/run/t4671.check2
-rw-r--r--test/files/run/t4710.check2
-rw-r--r--test/files/run/t5072.check2
-rw-r--r--test/files/run/t5256d.check2
-rw-r--r--test/files/run/t5535.check2
-rw-r--r--test/files/run/t5537.check2
-rw-r--r--test/files/run/t5583.check2
-rw-r--r--test/files/run/t5655.check2
-rw-r--r--test/files/run/t5789.check2
-rw-r--r--test/files/run/t6086-repl.check2
-rw-r--r--test/files/run/t6146b.check2
-rw-r--r--test/files/run/t6187.check2
-rw-r--r--test/files/run/t6273.check2
-rw-r--r--test/files/run/t6320.check2
-rw-r--r--test/files/run/t6329_repl.check2
-rw-r--r--test/files/run/t6329_repl_bug.check2
-rw-r--r--test/files/run/t6381.check2
-rw-r--r--test/files/run/t6434.check2
-rw-r--r--test/files/run/t6439.check2
-rw-r--r--test/files/run/t6507.check2
-rw-r--r--test/files/run/t6549.check2
-rw-r--r--test/files/run/t6631.scala18
-rw-r--r--test/files/run/t6937.check2
-rw-r--r--test/files/run/t7185.check2
-rw-r--r--test/files/run/t7319.check2
-rw-r--r--test/files/run/t7482a.check2
-rw-r--r--test/files/run/t7634.check2
-rw-r--r--test/files/run/t7747-repl.check2
-rw-r--r--test/files/run/t7801.check2
-rw-r--r--test/files/run/t7805-repl-i.check2
-rw-r--r--test/files/run/tpeCache-tyconCache.check2
-rw-r--r--test/junit/scala/StringContextTest.scala27
-rw-r--r--test/junit/scala/reflect/QTest.scala23
-rw-r--r--test/junit/scala/util/matching/RegexTest.scala17
131 files changed, 1383 insertions, 815 deletions
diff --git a/build.xml b/build.xml
index b7950f971c..6c750e530d 100755
--- a/build.xml
+++ b/build.xml
@@ -1440,9 +1440,13 @@ TODO:
<stopwatch name="test.junit.timer"/>
<mkdir dir="${test.junit.classes}"/>
<echo message="Note: details of failed tests will be output to ${build-junit.dir}"/>
+
+ <if><isset property="test.method" /><then><property name="test.methods" value="${test.method}" /></then></if>
<junit fork="yes" haltonfailure="yes" printsummary="on">
<classpath refid="test.junit.compiler.build.path"/>
- <batchtest fork="yes" todir="${build-junit.dir}">
+ <test fork="yes" todir="${build-junit.dir}" if="test.class" unless="test.methods" name="${test.class}" />
+ <test fork="yes" todir="${build-junit.dir}" if="test.methods" name="${test.class}" methods="${test.methods}" />
+ <batchtest fork="yes" todir="${build-junit.dir}" unless="test.class">
<fileset dir="${test.junit.classes}">
<include name="**/*Test.class"/>
</fileset>
diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala
index f23bca77cd..0a356ed7b6 100644
--- a/src/compiler/scala/tools/nsc/CompilationUnits.scala
+++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala
@@ -135,11 +135,8 @@ trait CompilationUnits { global: Global =>
@deprecated("Call global.currentRun.reporting.uncheckedWarning directly instead.", "2.11.2")
final def uncheckedWarning(pos: Position, msg: String): Unit = currentRun.reporting.uncheckedWarning(pos, msg)
- // called by ScalaDocAnalyzer, overridden by the IDE (in Reporter)
- // TODO: don't use reporter to communicate comments from parser to IDE!
- @deprecated("This method will be removed.", "2.11.2")
- final def comment(pos: Position, msg: String): Unit = reporter.comment(pos, msg)
-
+ @deprecated("This method will be removed. It does nothing.", "2.11.2")
+ final def comment(pos: Position, msg: String): Unit = {}
/** Is this about a .java source file? */
lazy val isJava = source.file.name.endsWith(".java")
diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala
index 1f3a4237eb..029e1c4629 100644
--- a/src/compiler/scala/tools/nsc/CompileServer.scala
+++ b/src/compiler/scala/tools/nsc/CompileServer.scala
@@ -152,6 +152,7 @@ class StandardCompileServer extends SocketServer {
clearCompiler()
case ex: Throwable =>
warn("Compile server encountered fatal condition: " + ex)
+ reporter.error(null, "Compile server encountered fatal condition: " + ex.getMessage)
shutdown = true
throw ex
}
diff --git a/src/compiler/scala/tools/nsc/CompileSocket.scala b/src/compiler/scala/tools/nsc/CompileSocket.scala
index c4f06b59ec..c693fbe8e2 100644
--- a/src/compiler/scala/tools/nsc/CompileSocket.scala
+++ b/src/compiler/scala/tools/nsc/CompileSocket.scala
@@ -32,7 +32,8 @@ trait HasCompileSocket {
if (isErrorMessage(line))
noErrors = false
- compileSocket.echo(line)
+ // be consistent with scalac: everything goes to stderr
+ compileSocket.warn(line)
loop()
}
try loop()
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 5bf0d8d9f7..3e72dc5e4a 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -45,7 +45,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
with Printers
with DocComments
with Positions
- with Reporting { self =>
+ with Reporting
+ with Parsing { self =>
// the mirror --------------------------------------------------
@@ -218,6 +219,14 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
/** Called from parser, which signals hereby that a method definition has been parsed. */
def signalParseProgress(pos: Position) {}
+ /** Called by ScalaDocAnalyzer when a doc comment has been parsed. */
+ def signalParsedDocComment(comment: String, pos: Position) = {
+ // TODO: this is all very borken (only works for scaladoc comments, not regular ones)
+ // --> add hooks to parser and refactor Interactive global to handle comments directly
+ // in any case don't use reporter for parser hooks
+ reporter.comment(pos, comment)
+ }
+
/** Register new context; called for every created context
*/
def registerContext(c: analyzer.Context) {
@@ -968,7 +977,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
/** A Run is a single execution of the compiler on a set of units.
*/
- class Run extends RunContextApi with RunReporting {
+ class Run extends RunContextApi with RunReporting with RunParsing {
/** Have been running into too many init order issues with Run
* during erroneous conditions. Moved all these vals up to the
* top of the file so at least they're not trivially null.
diff --git a/src/compiler/scala/tools/nsc/Parsing.scala b/src/compiler/scala/tools/nsc/Parsing.scala
new file mode 100644
index 0000000000..4dd3c3f378
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/Parsing.scala
@@ -0,0 +1,36 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2014 LAMP/EPFL, Typesafe Inc.
+ * @author Adriaan Moors
+ */
+
+package scala
+package tools.nsc
+
+import scala.reflect.internal.Positions
+import scala.tools.nsc.reporters.Reporter
+
+/** Similar to Reporting: gather global functionality specific to parsing.
+ */
+trait Parsing { self : Positions with Reporting =>
+ def currentRun: RunParsing
+
+ trait RunParsing {
+ val parsing: PerRunParsing = new PerRunParsing
+ }
+
+ class PerRunParsing {
+ // for repl
+ private[this] var incompleteHandler: (Position, String) => Unit = null
+ def withIncompleteHandler[T](handler: (Position, String) => Unit)(thunk: => T) = {
+ val saved = incompleteHandler
+ incompleteHandler = handler
+ try thunk
+ finally incompleteHandler = saved
+ }
+
+ def incompleteHandled = incompleteHandler != null
+ def incompleteInputError(pos: Position, msg: String): Unit =
+ if (incompleteHandled) incompleteHandler(pos, msg)
+ else reporter.error(pos, msg)
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/Properties.scala b/src/compiler/scala/tools/nsc/Properties.scala
index ed5fda9c3f..59fefba954 100644
--- a/src/compiler/scala/tools/nsc/Properties.scala
+++ b/src/compiler/scala/tools/nsc/Properties.scala
@@ -14,6 +14,7 @@ object Properties extends scala.util.PropertiesTrait {
// settings based on jar properties
def residentPromptString = scalaPropOrElse("resident.prompt", "\nnsc> ")
def shellPromptString = scalaPropOrElse("shell.prompt", "\nscala> ")
+ def shellInterruptedString = scalaPropOrElse("shell.interrupted", ":quit\n")
// derived values
def isEmacsShell = propOrEmpty("env.emacs") != ""
diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala
index 0263586418..b164f395fe 100644
--- a/src/compiler/scala/tools/nsc/Reporting.scala
+++ b/src/compiler/scala/tools/nsc/Reporting.scala
@@ -104,20 +104,5 @@ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions w
if (settings.fatalWarnings && reporter.hasWarnings)
reporter.error(NoPosition, "No warnings can be incurred under -Xfatal-warnings.")
}
-
- // for repl
- private[this] var incompleteHandler: (Position, String) => Unit = null
- def withIncompleteHandler[T](handler: (Position, String) => Unit)(thunk: => T) = {
- val saved = incompleteHandler
- incompleteHandler = handler
- try thunk
- finally incompleteHandler = saved
- }
-
- def incompleteHandled = incompleteHandler != null
- def incompleteInputError(pos: Position, msg: String): Unit =
- if (incompleteHandled) incompleteHandler(pos, msg)
- else reporter.error(pos, msg)
-
}
} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 883fd31dbc..8d810d456e 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -154,8 +154,8 @@ self =>
def unit = global.currentUnit
// suppress warnings; silent abort on errors
- def warning(offset: Offset, msg: String) {}
- def deprecationWarning(offset: Offset, msg: String) {}
+ def warning(offset: Offset, msg: String): Unit = ()
+ def deprecationWarning(offset: Offset, msg: String): Unit = ()
def syntaxError(offset: Offset, msg: String): Unit = throw new MalformedInput(offset, msg)
def incompleteInputError(msg: String): Unit = throw new MalformedInput(source.content.length - 1, msg)
@@ -204,13 +204,11 @@ self =>
override def newScanner() = new UnitScanner(unit, patches)
- override def warning(offset: Offset, msg: String) {
+ override def warning(offset: Offset, msg: String): Unit =
reporter.warning(o2p(offset), msg)
- }
- override def deprecationWarning(offset: Offset, msg: String) {
+ override def deprecationWarning(offset: Offset, msg: String): Unit =
currentRun.reporting.deprecationWarning(o2p(offset), msg)
- }
private var smartParsing = false
@inline private def withSmartParsing[T](body: => T): T = {
@@ -226,15 +224,15 @@ self =>
for ((offset, msg) <- syntaxErrors)
reporter.error(o2p(offset), msg)
- override def syntaxError(offset: Offset, msg: String) {
+ override def syntaxError(offset: Offset, msg: String): Unit = {
if (smartParsing) syntaxErrors += ((offset, msg))
else reporter.error(o2p(offset), msg)
}
- override def incompleteInputError(msg: String) {
+ override def incompleteInputError(msg: String): Unit = {
val offset = source.content.length - 1
if (smartParsing) syntaxErrors += ((offset, msg))
- else currentRun.reporting.incompleteInputError(o2p(offset), msg)
+ else currentRun.parsing.incompleteInputError(o2p(offset), msg)
}
/** parse unit. If there are inbalanced braces,
@@ -335,7 +333,7 @@ self =>
*/
private var inScalaPackage = false
private var currentPackage = ""
- def resetPackage() {
+ def resetPackage(): Unit = {
inScalaPackage = false
currentPackage = ""
}
@@ -514,7 +512,7 @@ self =>
finally inFunReturnType = saved
}
- protected def skip(targetToken: Token) {
+ protected def skip(targetToken: Token): Unit = {
var nparens = 0
var nbraces = 0
while (true) {
@@ -544,27 +542,25 @@ self =>
}
def warning(offset: Offset, msg: String): Unit
def incompleteInputError(msg: String): Unit
- private def syntaxError(pos: Position, msg: String, skipIt: Boolean) {
- syntaxError(pos pointOrElse in.offset, msg, skipIt)
- }
def syntaxError(offset: Offset, msg: String): Unit
- def syntaxError(msg: String, skipIt: Boolean) {
+
+ private def syntaxError(pos: Position, msg: String, skipIt: Boolean): Unit =
+ syntaxError(pos pointOrElse in.offset, msg, skipIt)
+ def syntaxError(msg: String, skipIt: Boolean): Unit =
syntaxError(in.offset, msg, skipIt)
- }
- def syntaxError(offset: Offset, msg: String, skipIt: Boolean) {
+ def syntaxError(offset: Offset, msg: String, skipIt: Boolean): Unit = {
if (offset > lastErrorOffset) {
syntaxError(offset, msg)
- // no more errors on this token.
- lastErrorOffset = in.offset
+ lastErrorOffset = in.offset // no more errors on this token.
}
if (skipIt)
skip(UNDEF)
}
- def warning(msg: String) { warning(in.offset, msg) }
+ def warning(msg: String): Unit = warning(in.offset, msg)
- def syntaxErrorOrIncomplete(msg: String, skipIt: Boolean) {
+ def syntaxErrorOrIncomplete(msg: String, skipIt: Boolean): Unit = {
if (in.token == EOF)
incompleteInputError(msg)
else
@@ -719,7 +715,7 @@ self =>
/** Convert tree to formal parameter. */
def convertToParam(tree: Tree): ValDef = atPos(tree.pos) {
- def removeAsPlaceholder(name: Name) {
+ def removeAsPlaceholder(name: Name): Unit = {
placeholderParams = placeholderParams filter (_.name != name)
}
def errorParam = makeParam(nme.ERROR, errorTypeTree setPos o2p(tree.pos.end))
@@ -1233,15 +1229,15 @@ self =>
skipIt = true)(EmptyTree)
// Like Swiss cheese, with holes
def stringCheese: Tree = atPos(in.offset) {
- val start = in.offset
+ val start = in.offset
val interpolator = in.name.encoded // ident() for INTERPOLATIONID
val partsBuf = new ListBuffer[Tree]
- val exprBuf = new ListBuffer[Tree]
+ val exprsBuf = new ListBuffer[Tree]
in.nextToken()
while (in.token == STRINGPART) {
partsBuf += literal()
- exprBuf += (
+ exprsBuf += (
if (inPattern) dropAnyBraces(pattern())
else in.token match {
case IDENTIFIER => atPos(in.offset)(Ident(ident()))
@@ -1254,11 +1250,13 @@ self =>
}
if (in.token == STRINGLIT) partsBuf += literal()
+ // Documenting that it is intentional that the ident is not rooted for purposes of virtualization
+ //val t1 = atPos(o2p(start)) { Select(Select (Ident(nme.ROOTPKG), nme.scala_), nme.StringContext) }
val t1 = atPos(o2p(start)) { Ident(nme.StringContext) }
val t2 = atPos(start) { Apply(t1, partsBuf.toList) }
t2 setPos t2.pos.makeTransparent
val t3 = Select(t2, interpolator) setPos t2.pos
- atPos(start) { Apply(t3, exprBuf.toList) }
+ atPos(start) { Apply(t3, exprsBuf.toList) }
}
if (inPattern) stringCheese
else withPlaceholders(stringCheese, isAny = true) // strinterpolator params are Any* by definition
@@ -1266,21 +1264,21 @@ self =>
/* ------------- NEW LINES ------------------------------------------------- */
- def newLineOpt() {
+ def newLineOpt(): Unit = {
if (in.token == NEWLINE) in.nextToken()
}
- def newLinesOpt() {
+ def newLinesOpt(): Unit = {
if (in.token == NEWLINE || in.token == NEWLINES)
in.nextToken()
}
- def newLineOptWhenFollowedBy(token: Offset) {
+ def newLineOptWhenFollowedBy(token: Offset): Unit = {
// note: next is defined here because current == NEWLINE
if (in.token == NEWLINE && in.next.token == token) newLineOpt()
}
- def newLineOptWhenFollowing(p: Token => Boolean) {
+ def newLineOptWhenFollowing(p: Token => Boolean): Unit = {
// note: next is defined here because current == NEWLINE
if (in.token == NEWLINE && p(in.next.token)) newLineOpt()
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index 572497ac90..9ebc94b5fc 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -113,7 +113,7 @@ trait Scanners extends ScannersCommon {
case SU | CR | LF =>
case _ => nextChar() ; skipLineComment()
}
- private def maybeOpen() {
+ private def maybeOpen(): Unit = {
putCommentChar()
if (ch == '*') {
putCommentChar()
@@ -137,7 +137,7 @@ trait Scanners extends ScannersCommon {
def skipDocComment(): Unit = skipNestedComments()
def skipBlockComment(): Unit = skipNestedComments()
- private def skipToCommentEnd(isLineComment: Boolean) {
+ private def skipToCommentEnd(isLineComment: Boolean): Unit = {
nextChar()
if (isLineComment) skipLineComment()
else {
@@ -185,7 +185,7 @@ trait Scanners extends ScannersCommon {
/** append Unicode character to "cbuf" buffer
*/
- protected def putChar(c: Char) {
+ protected def putChar(c: Char): Unit = {
// assert(cbuf.size < 10000, cbuf)
cbuf.append(c)
}
@@ -196,7 +196,7 @@ trait Scanners extends ScannersCommon {
protected def emitIdentifierDeprecationWarnings = true
/** Clear buffer and set name and token */
- private def finishNamed(idtoken: Token = IDENTIFIER) {
+ private def finishNamed(idtoken: Token = IDENTIFIER): Unit = {
name = newTermName(cbuf.toString)
cbuf.clear()
token = idtoken
@@ -215,7 +215,7 @@ trait Scanners extends ScannersCommon {
}
/** Clear buffer and set string */
- private def setStrVal() {
+ private def setStrVal(): Unit = {
strVal = cbuf.toString
cbuf.clear()
}
@@ -270,7 +270,7 @@ trait Scanners extends ScannersCommon {
/** Produce next token, filling TokenData fields of Scanner.
*/
- def nextToken() {
+ def nextToken(): Unit = {
val lastToken = token
// Adapt sepRegions according to last token
(lastToken: @switch) match {
@@ -341,7 +341,7 @@ trait Scanners extends ScannersCommon {
prev copyFrom this
val nextLastOffset = charOffset - 1
fetchToken()
- def resetOffset() {
+ def resetOffset(): Unit = {
offset = prev.offset
lastOffset = prev.lastOffset
}
@@ -399,7 +399,7 @@ trait Scanners extends ScannersCommon {
/** read next token, filling TokenData fields of Scanner.
*/
- protected final def fetchToken() {
+ protected final def fetchToken(): Unit = {
offset = charOffset - 1
(ch: @switch) match {
@@ -604,7 +604,7 @@ trait Scanners extends ScannersCommon {
// Identifiers ---------------------------------------------------------------
- private def getBackquotedIdent() {
+ private def getBackquotedIdent(): Unit = {
nextChar()
getLitChars('`')
if (ch == '`') {
@@ -664,7 +664,7 @@ trait Scanners extends ScannersCommon {
else finishNamed()
}
- private def getIdentOrOperatorRest() {
+ private def getIdentOrOperatorRest(): Unit = {
if (isIdentifierPart(ch))
getIdentRest()
else ch match {
@@ -688,9 +688,11 @@ trait Scanners extends ScannersCommon {
setStrVal()
nextChar()
token = STRINGLIT
- } else syntaxError("unclosed string literal")
+ } else unclosedStringLit()
}
+ private def unclosedStringLit(): Unit = syntaxError("unclosed string literal")
+
private def getRawStringLit(): Unit = {
if (ch == '\"') {
nextRawChar()
@@ -764,7 +766,7 @@ trait Scanners extends ScannersCommon {
if (multiLine)
incompleteInputError("unclosed multi-line string literal")
else
- syntaxError("unclosed string literal")
+ unclosedStringLit()
}
else {
putChar(ch)
@@ -857,7 +859,7 @@ trait Scanners extends ScannersCommon {
/** read fractional part and exponent of floating point number
* if one is present.
*/
- protected def getFraction() {
+ protected def getFraction(): Unit = {
token = DOUBLELIT
while ('0' <= ch && ch <= '9') {
putChar(ch)
@@ -966,14 +968,13 @@ trait Scanners extends ScannersCommon {
def floatVal: Double = floatVal(negated = false)
- def checkNoLetter() {
+ def checkNoLetter(): Unit = {
if (isIdentifierPart(ch) && ch >= ' ')
syntaxError("Invalid literal number")
}
- /** Read a number into strVal and set base
- */
- protected def getNumber() {
+ /** Read a number into strVal and set base */
+ protected def getNumber(): Unit = {
val base1 = if (base < 10) 10 else base
// Read 8,9's even if format is octal, produce a malformed number error afterwards.
// At this point, we have already read the first digit, so to tell an innocent 0 apart
@@ -1052,7 +1053,7 @@ trait Scanners extends ScannersCommon {
/** Parse character literal if current character is followed by \',
* or follow with given op and return a symbol literal token
*/
- def charLitOr(op: () => Unit) {
+ def charLitOr(op: () => Unit): Unit = {
putChar(ch)
nextChar()
if (ch == '\'') {
@@ -1068,21 +1069,19 @@ trait Scanners extends ScannersCommon {
// Errors -----------------------------------------------------------------
- /** generate an error at the given offset
- */
- def syntaxError(off: Offset, msg: String) {
+ /** generate an error at the given offset */
+ def syntaxError(off: Offset, msg: String): Unit = {
error(off, msg)
token = ERROR
}
- /** generate an error at the current token offset
- */
+ /** generate an error at the current token offset */
def syntaxError(msg: String): Unit = syntaxError(offset, msg)
def deprecationWarning(msg: String): Unit = deprecationWarning(offset, msg)
/** signal an error where the input ended in the middle of a token */
- def incompleteInputError(msg: String) {
+ def incompleteInputError(msg: String): Unit = {
incompleteInputError(offset, msg)
token = EOF
}
@@ -1134,7 +1133,7 @@ trait Scanners extends ScannersCommon {
/** Initialization method: read first char, then first token
*/
- def init() {
+ def init(): Unit = {
nextChar()
nextToken()
}
@@ -1261,7 +1260,7 @@ trait Scanners extends ScannersCommon {
override def deprecationWarning(off: Offset, msg: String) = currentRun.reporting.deprecationWarning(unit.position(off), msg)
override def error (off: Offset, msg: String) = reporter.error(unit.position(off), msg)
- override def incompleteInputError(off: Offset, msg: String) = currentRun.reporting.incompleteInputError(unit.position(off), msg)
+ override def incompleteInputError(off: Offset, msg: String) = currentRun.parsing.incompleteInputError(unit.position(off), msg)
private var bracePatches: List[BracePatch] = patches
@@ -1490,6 +1489,6 @@ trait Scanners extends ScannersCommon {
// when skimming through the source file trying to heal braces
override def emitIdentifierDeprecationWarnings = false
- override def error(offset: Offset, msg: String) {}
+ override def error(offset: Offset, msg: String): Unit = ()
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
index 64b762696e..df2073785b 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
@@ -83,7 +83,7 @@ abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParse
private def initialUnitBody(unit: CompilationUnit): Tree = {
if (unit.isJava) new JavaUnitParser(unit).parse()
- else if (currentRun.reporting.incompleteHandled) newUnitParser(unit).parse()
+ else if (currentRun.parsing.incompleteHandled) newUnitParser(unit).parse()
else newUnitParser(unit).smartParse()
}
diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
index bddcf6567c..ac86dfd665 100644
--- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
+++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
@@ -861,7 +861,7 @@ trait JavaScanners extends ast.parser.ScannersCommon {
in = new JavaCharArrayReader(unit.source.content, !settings.nouescape.value, syntaxError)
init()
def error (pos: Int, msg: String) = reporter.error(pos, msg)
- def incompleteInputError(pos: Int, msg: String) = currentRun.reporting.incompleteInputError(pos, msg)
+ def incompleteInputError(pos: Int, msg: String) = currentRun.parsing.incompleteInputError(pos, msg)
def deprecationWarning(pos: Int, msg: String) = currentRun.reporting.deprecationWarning(pos, msg)
implicit def g2p(pos: Int): Position = Position.offset(unit.source, pos)
}
diff --git a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
index 6c592ead0d..5e4914fa83 100644
--- a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
@@ -30,6 +30,7 @@ abstract class AbstractReporter extends Reporter {
private def isVerbose = settings.verbose.value
private def noWarnings = settings.nowarnings.value
private def isPromptSet = settings.prompt.value
+ private def isDebug = settings.debug
protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean) {
if (severity == INFO) {
@@ -46,7 +47,7 @@ abstract class AbstractReporter extends Reporter {
severity.count += 1
display(pos, msg, severity)
}
- else if (settings.debug) {
+ else if (isDebug) {
severity.count += 1
display(pos, "[ suppressed ] " + msg, severity)
}
@@ -57,6 +58,7 @@ abstract class AbstractReporter extends Reporter {
}
}
+
/** Logs a position and returns true if it was already logged.
* @note Two positions are considered identical for logging if they have the same point.
*/
diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala
index 5b576a547d..3d688efae1 100644
--- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala
@@ -13,8 +13,8 @@ import scala.reflect.internal.util._
* This describes the internal interface for issuing information, warnings and errors.
* The only abstract method in this class must be info0.
*
- * TODO: Move external clients (sbt/ide/partest) to reflect.internal.Reporter
- * This interface should be considered private to the compiler.
+ * TODO: Move external clients (sbt/ide/partest) to reflect.internal.Reporter,
+ * and remove this class.
*/
abstract class Reporter extends scala.reflect.internal.Reporter {
/** Informational messages. If `!force`, they may be suppressed. */
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index ec4deb6be0..54bcc9e93e 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -1133,7 +1133,7 @@ abstract class Erasure extends AddInterfaces
val tree2 = mixinTransformer.transform(tree1)
// debuglog("tree after addinterfaces: \n" + tree2)
- newTyper(rootContext(unit, tree, erasedTypes = true)).typed(tree2)
+ newTyper(rootContextPostTyper(unit, tree)).typed(tree2)
}
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala b/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
index 3feadcd9b2..dc3313e2e4 100644
--- a/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
+++ b/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
@@ -17,9 +17,9 @@ trait TypingTransformers {
abstract class TypingTransformer(unit: CompilationUnit) extends Transformer {
var localTyper: analyzer.Typer =
if (phase.erasedTypes)
- erasure.newTyper(erasure.rootContext(unit, EmptyTree, erasedTypes = true)).asInstanceOf[analyzer.Typer]
- else
- analyzer.newTyper(analyzer.rootContext(unit, EmptyTree, true))
+ erasure.newTyper(erasure.rootContextPostTyper(unit, EmptyTree)).asInstanceOf[analyzer.Typer]
+ else // TODO: AM: should some phases use a regular rootContext instead of a post-typer one??
+ analyzer.newTyper(analyzer.rootContextPostTyper(unit, EmptyTree))
protected var curTree: Tree = _
override final def atOwner[A](owner: Symbol)(trans: => A): A = atOwner(curTree, owner)(trans)
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 9715fdaf00..20e462bbce 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -27,6 +27,16 @@ trait ContextErrors {
override def toString() = "[Type error at:" + errPos + "] " + errMsg
}
+ abstract class AbsAmbiguousTypeError extends AbsTypeError
+
+ case class AmbiguousTypeError(errPos: Position, errMsg: String)
+ extends AbsAmbiguousTypeError
+
+ case class AmbiguousImplicitTypeError(underlyingTree: Tree, errMsg: String)
+ extends AbsAmbiguousTypeError {
+ def errPos = underlyingTree.pos
+ }
+
sealed abstract class TreeTypeError extends AbsTypeError {
def underlyingTree: Tree
def errPos = underlyingTree.pos
@@ -38,9 +48,6 @@ trait ContextErrors {
case class AccessTypeError(underlyingTree: Tree, errMsg: String)
extends TreeTypeError
- case class AmbiguousTypeError(errPos: Position, errMsg: String)
- extends AbsTypeError
-
case class SymbolTypeError(underlyingSym: Symbol, errMsg: String)
extends AbsTypeError {
@@ -75,8 +82,6 @@ trait ContextErrors {
s"diverging implicit expansion for type ${pt}\nstarting with ${sym.fullLocationString}"
}
- case class AmbiguousImplicitTypeError(underlyingTree: Tree, errMsg: String)
- extends TreeTypeError
case class PosAndMsgTypeError(errPos: Position, errMsg: String)
extends AbsTypeError
@@ -90,10 +95,6 @@ trait ContextErrors {
issueTypeError(SymbolTypeError(sym, msg))
}
- def issueAmbiguousTypeError(pre: Type, sym1: Symbol, sym2: Symbol, err: AmbiguousTypeError)(implicit context: Context) {
- context.issueAmbiguousError(pre, sym1, sym2, err)
- }
-
def issueTypeError(err: AbsTypeError)(implicit context: Context) { context.issue(err) }
def typeErrorMsg(found: Type, req: Type) = "type mismatch" + foundReqMsg(found, req)
@@ -123,6 +124,36 @@ trait ContextErrors {
import ErrorUtils._
+ private def MacroIncompatibleEngineError(friendlyMessage: String, internalMessage: String) = {
+ def debugDiagnostic = s"(internal diagnostic: $internalMessage)"
+ val message = if (macroDebugLite || macroDebugVerbose) s"$friendlyMessage $debugDiagnostic" else friendlyMessage
+ // TODO: clean this up! (This is a more explicit version of what the code use to do, to reveal the issue.)
+ throw new TypeError(analyzer.lastTreeToTyper.pos, message)
+ }
+
+ def MacroCantExpand210xMacrosError(internalMessage: String) =
+ MacroIncompatibleEngineError("can't expand macros compiled by previous versions of Scala", internalMessage)
+
+ def MacroCantExpandIncompatibleMacrosError(internalMessage: String) =
+ MacroIncompatibleEngineError("macro cannot be expanded, because it was compiled by an incompatible macro engine", internalMessage)
+
+ def NoImplicitFoundError(tree: Tree, param: Symbol)(implicit context: Context): Unit = {
+ def errMsg = {
+ val paramName = param.name
+ val paramTp = param.tpe
+ def evOrParam = (
+ if (paramName startsWith nme.EVIDENCE_PARAM_PREFIX)
+ "evidence parameter of type"
+ else
+ s"parameter $paramName:")
+ paramTp.typeSymbolDirect match {
+ case ImplicitNotFoundMsg(msg) => msg.format(paramName, paramTp)
+ case _ => s"could not find implicit value for $evOrParam $paramTp"
+ }
+ }
+ issueNormalTypeError(tree, errMsg)
+ }
+
trait TyperContextErrors {
self: Typer =>
@@ -141,24 +172,6 @@ trait ContextErrors {
setError(tree)
}
- def NoImplicitFoundError(tree: Tree, param: Symbol) = {
- def errMsg = {
- val paramName = param.name
- val paramTp = param.tpe
- def evOrParam = (
- if (paramName startsWith nme.EVIDENCE_PARAM_PREFIX)
- "evidence parameter of type"
- else
- s"parameter $paramName:"
- )
- paramTp.typeSymbolDirect match {
- case ImplicitNotFoundMsg(msg) => msg.format(paramName, paramTp)
- case _ => s"could not find implicit value for $evOrParam $paramTp"
- }
- }
- issueNormalTypeError(tree, errMsg)
- }
-
def AdaptTypeError(tree: Tree, found: Type, req: Type) = {
// SI-3971 unwrapping to the outermost Apply helps prevent confusion with the
// error message point.
@@ -733,17 +746,6 @@ trait ContextErrors {
NormalTypeError(expandee, "too many argument lists for " + fun)
}
- private def MacroIncompatibleEngineError(friendlyMessage: String, internalMessage: String) = {
- def debugDiagnostic = s"(internal diagnostic: $internalMessage)"
- val message = if (macroDebugLite || macroDebugVerbose) s"$friendlyMessage $debugDiagnostic" else friendlyMessage
- issueNormalTypeError(lastTreeToTyper, message)
- }
-
- def MacroCantExpand210xMacrosError(internalMessage: String) =
- MacroIncompatibleEngineError("can't expand macros compiled by previous versions of Scala", internalMessage)
-
- def MacroCantExpandIncompatibleMacrosError(internalMessage: String) =
- MacroIncompatibleEngineError("macro cannot be expanded, because it was compiled by an incompatible macro engine", internalMessage)
case object MacroExpansionException extends Exception with scala.util.control.ControlThrowable
@@ -883,19 +885,21 @@ trait ContextErrors {
val WrongNumber, NoParams, ArgsDoNotConform = Value
}
- private def ambiguousErrorMsgPos(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String) =
- if (sym1.hasDefault && sym2.hasDefault && sym1.enclClass == sym2.enclClass) {
- val methodName = nme.defaultGetterToMethod(sym1.name)
- (sym1.enclClass.pos,
- "in "+ sym1.enclClass +", multiple overloaded alternatives of " + methodName +
- " define default arguments")
- } else {
- (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 =
+ 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)
+ ))
+ }
}
def AccessError(tree: Tree, sym: Symbol, ctx: Context, explanation: String): AbsTypeError =
@@ -952,8 +956,7 @@ trait ContextErrors {
val msg0 =
"argument types " + argtpes.mkString("(", ",", ")") +
(if (pt == WildcardType) "" else " and expected result type " + pt)
- val (pos, msg) = ambiguousErrorMsgPos(tree.pos, pre, best, firstCompeting, msg0)
- issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(pos, msg))
+ issueAmbiguousTypeErrorUnlessErroneous(tree.pos, pre, best, firstCompeting, msg0)
setErrorOnLastTry(lastTry, tree)
} else setError(tree) // do not even try further attempts because they should all fail
// even if this is not the last attempt (because of the SO's possibility on the horizon)
@@ -966,8 +969,7 @@ trait ContextErrors {
}
def AmbiguousExprAlternativeError(tree: Tree, pre: Type, best: Symbol, firstCompeting: Symbol, pt: Type, lastTry: Boolean) = {
- val (pos, msg) = ambiguousErrorMsgPos(tree.pos, pre, best, firstCompeting, "expected type " + pt)
- issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(pos, msg))
+ issueAmbiguousTypeErrorUnlessErroneous(tree.pos, pre, best, firstCompeting, "expected type " + pt)
setErrorOnLastTry(lastTry, tree)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 72ca9b879a..a79f162140 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -9,6 +9,7 @@ package typechecker
import scala.collection.{ immutable, mutable }
import scala.annotation.tailrec
import scala.reflect.internal.util.shortClassOfInstance
+import scala.tools.nsc.reporters.Reporter
/**
* @author Martin Odersky
@@ -98,7 +99,7 @@ trait Contexts { self: Analyzer =>
}
- def rootContext(unit: CompilationUnit, tree: Tree = EmptyTree, erasedTypes: Boolean = false): Context = {
+ def rootContext(unit: CompilationUnit, tree: Tree = EmptyTree, throwing: Boolean = false, checking: Boolean = false): Context = {
val rootImportsContext = (startContext /: rootImports(unit))((c, sym) => c.make(gen.mkWildcardImport(sym)))
// there must be a scala.xml package when xml literals were parsed in this unit
@@ -113,18 +114,21 @@ trait Contexts { self: Analyzer =>
else rootImportsContext.make(gen.mkImport(ScalaXmlPackage, nme.TopScope, nme.dollarScope))
val c = contextWithXML.make(tree, unit = unit)
- if (erasedTypes) c.setThrowErrors() else c.setReportErrors()
- c(EnrichmentEnabled | ImplicitsEnabled) = !erasedTypes
+
+ c.initRootContext(throwing, checking)
c
}
+ def rootContextPostTyper(unit: CompilationUnit, tree: Tree = EmptyTree): Context =
+ rootContext(unit, tree, throwing = true)
+
def resetContexts() {
startContext.enclosingContextChain foreach { context =>
context.tree match {
case Import(qual, _) => qual setType singleType(qual.symbol.owner.thisType, qual.symbol)
case _ =>
}
- context.reportBuffer.clearAll()
+ context.reporter.clearAll()
}
}
@@ -178,7 +182,8 @@ trait Contexts { self: Analyzer =>
* @param _outer The next outer context.
*/
class Context private[typechecker](val tree: Tree, val owner: Symbol, val scope: Scope,
- val unit: CompilationUnit, _outer: Context) {
+ val unit: CompilationUnit, _outer: Context,
+ private[this] var _reporter: ContextReporter = new ThrowingReporter) {
private def outerIsNoContext = _outer eq null
final def outer: Context = if (outerIsNoContext) NoContext else _outer
@@ -254,8 +259,6 @@ trait Contexts { self: Analyzer =>
def macrosEnabled = this(MacrosEnabled)
def enrichmentEnabled_=(value: Boolean) = this(EnrichmentEnabled) = value
def enrichmentEnabled = this(EnrichmentEnabled)
- def checking_=(value: Boolean) = this(Checking) = value
- def checking = this(Checking)
def retyping_=(value: Boolean) = this(ReTyping) = value
def retyping = this(ReTyping)
def inSecondTry = this(SecondTry)
@@ -265,8 +268,9 @@ trait Contexts { self: Analyzer =>
def defaultModeForTyped: Mode = if (inTypeConstructorAllowed) Mode.NOmode else Mode.EXPRmode
- /** These messages are printed when issuing an error */
- var diagnostic: List[String] = Nil
+ /** To enrich error messages involving default arguments.
+ When extending the notion, group diagnostics in an object. */
+ var diagUsedDefaults: Boolean = false
/** Saved type bounds for type parameters which are narrowed in a GADT. */
var savedTypeBounds: List[(Symbol, Type)] = List()
@@ -310,7 +314,7 @@ trait Contexts { self: Analyzer =>
*/
def savingUndeterminedTypeParams[A](reportAmbiguous: Boolean = ambiguousErrors)(body: => A): A = {
withMode() {
- this(AmbiguousErrors) = reportAmbiguous
+ setAmbiguousErrors(reportAmbiguous)
val saved = extractUndetparams()
try body
finally undetparams = saved
@@ -321,54 +325,59 @@ trait Contexts { self: Analyzer =>
// Error reporting policies and buffer.
//
- private var _reportBuffer: ReportBuffer = new ReportBuffer
- /** A buffer for errors and warnings, used with `this.bufferErrors == true` */
- def reportBuffer = _reportBuffer
- /** Discard the current report buffer, and replace with an empty one */
- def useFreshReportBuffer() = _reportBuffer = new ReportBuffer
- /** Discard the current report buffer, and replace with `other` */
- def restoreReportBuffer(other: ReportBuffer) = _reportBuffer = other
-
- /** The first error, if any, in the report buffer */
- def firstError: Option[AbsTypeError] = reportBuffer.firstError
- def errors: Seq[AbsTypeError] = reportBuffer.errors
- /** Does the report buffer contain any errors? */
- def hasErrors = reportBuffer.hasErrors
-
- def reportErrors = this(ReportErrors)
- def bufferErrors = this(BufferErrors)
+ // the reporter for this context
+ def reporter: ContextReporter = _reporter
+
+ // if set, errors will not be reporter/thrown
+ def bufferErrors = reporter.isBuffering
+ def reportErrors = !bufferErrors
+
+ // whether to *report* (which is separate from buffering/throwing) ambiguity errors
def ambiguousErrors = this(AmbiguousErrors)
- def throwErrors = contextMode.inNone(ReportErrors | BufferErrors)
-
- def setReportErrors(): Unit = set(enable = ReportErrors | AmbiguousErrors, disable = BufferErrors)
- def setBufferErrors(): Unit = set(enable = BufferErrors, disable = ReportErrors | AmbiguousErrors)
- def setThrowErrors(): Unit = this(ReportErrors | AmbiguousErrors | BufferErrors) = false
- def setAmbiguousErrors(report: Boolean): Unit = this(AmbiguousErrors) = report
-
- /** Append the given errors to the report buffer */
- def updateBuffer(errors: Traversable[AbsTypeError]) = reportBuffer ++= errors
- /** Clear all errors from the report buffer */
- def flushBuffer() { reportBuffer.clearAllErrors() }
- /** Return and clear all errors from the report buffer */
- def flushAndReturnBuffer(): immutable.Seq[AbsTypeError] = {
- val current = reportBuffer.errors
- reportBuffer.clearAllErrors()
- current
- }
- /** Issue and clear all warnings from the report buffer */
- def flushAndIssueWarnings() {
- reportBuffer.warnings foreach {
- case (pos, msg) => reporter.warning(pos, msg)
+ private def setAmbiguousErrors(report: Boolean): Unit = this(AmbiguousErrors) = report
+
+ /**
+ * Try inference twice: once without views and once with views,
+ * unless views are already disabled.
+ */
+ abstract class TryTwice {
+ def tryOnce(isLastTry: Boolean): Unit
+
+ final def apply(): Unit = {
+ val doLastTry =
+ // do first try if implicits are enabled
+ if (implicitsEnabled) {
+ // We create a new BufferingReporter to
+ // distinguish errors that occurred before entering tryTwice
+ // and our first attempt in 'withImplicitsDisabled'. If the
+ // first attempt fails, we try with implicits on
+ // and the original reporter.
+ // immediate reporting of ambiguous errors is suppressed, so that they are buffered
+ inSilentMode {
+ try {
+ set(disable = ImplicitsEnabled | EnrichmentEnabled) // restored by inSilentMode
+ tryOnce(false)
+ reporter.hasErrors
+ } catch {
+ case ex: CyclicReference => throw ex
+ case ex: TypeError => true // recoverable cyclic references?
+ }
+ }
+ } else true
+
+ // do last try if try with implicits enabled failed
+ // (or if it was not attempted because they were disabled)
+ if (doLastTry)
+ tryOnce(true)
}
- reportBuffer.clearAllWarnings()
}
//
// Temporary mode adjustment
//
- @inline def withMode[T](enabled: ContextMode = NOmode, disabled: ContextMode = NOmode)(op: => T): T = {
+ @inline final def withMode[T](enabled: ContextMode = NOmode, disabled: ContextMode = NOmode)(op: => T): T = {
val saved = contextMode
set(enabled, disabled)
try op
@@ -402,12 +411,18 @@ trait Contexts { self: Analyzer =>
// See comment on FormerNonStickyModes.
@inline final def withOnlyStickyModes[T](op: => T): T = withMode(disabled = FormerNonStickyModes)(op)
- /** @return true if the `expr` evaluates to true within a silent Context that incurs no errors */
+ // inliner note: this has to be a simple method for inlining to work -- moved the `&& !reporter.hasErrors` out
@inline final def inSilentMode(expr: => Boolean): Boolean = {
- withMode() { // withMode with no arguments to restore the mode mutated by `setBufferErrors`.
- setBufferErrors()
- try expr && !hasErrors
- finally reportBuffer.clearAll()
+ val savedContextMode = contextMode
+ val savedReporter = reporter
+
+ setAmbiguousErrors(false)
+ _reporter = new BufferingReporter
+
+ try expr
+ finally {
+ contextMode = savedContextMode
+ _reporter = savedReporter
}
}
@@ -423,7 +438,8 @@ trait Contexts { self: Analyzer =>
* `Context#imports`.
*/
def make(tree: Tree = tree, owner: Symbol = owner,
- scope: Scope = scope, unit: CompilationUnit = unit): Context = {
+ scope: Scope = scope, unit: CompilationUnit = unit,
+ reporter: ContextReporter = this.reporter): Context = {
val isTemplateOrPackage = tree match {
case _: Template | _: PackageDef => true
case _ => false
@@ -446,16 +462,15 @@ trait Contexts { self: Analyzer =>
// The blank canvas
val c = if (isImport)
- new Context(tree, owner, scope, unit, this) with ImportContext
+ new Context(tree, owner, scope, unit, this, reporter) with ImportContext
else
- new Context(tree, owner, scope, unit, this)
+ new Context(tree, owner, scope, unit, this, reporter)
// Fields that are directly propagated
c.variance = variance
- c.diagnostic = diagnostic
+ c.diagUsedDefaults = diagUsedDefaults
c.openImplicits = openImplicits
c.contextMode = contextMode // note: ConstructorSuffix, a bit within `mode`, is conditionally overwritten below.
- c._reportBuffer = reportBuffer
// Fields that may take on a different value in the child
c.prefix = prefixInChild
@@ -470,22 +485,38 @@ trait Contexts { self: Analyzer =>
c
}
+ /** Use reporter (possibly buffered) for errors/warnings and enable implicit conversion **/
+ def initRootContext(throwing: Boolean = false, checking: Boolean = false): Unit = {
+ _reporter =
+ if (checking) new CheckingReporter
+ else if (throwing) new ThrowingReporter
+ else new ImmediateReporter
+
+ setAmbiguousErrors(!throwing)
+ this(EnrichmentEnabled | ImplicitsEnabled) = !throwing
+ }
+
def make(tree: Tree, owner: Symbol, scope: Scope): Context =
// TODO SI-7345 Moving this optimization into the main overload of `make` causes all tests to fail.
- // even if it is extened to check that `unit == this.unit`. Why is this?
+ // even if it is extended to check that `unit == this.unit`. Why is this?
if (tree == this.tree && owner == this.owner && scope == this.scope) this
else make(tree, owner, scope, unit)
/** Make a child context that represents a new nested scope */
- def makeNewScope(tree: Tree, owner: Symbol): Context =
- make(tree, owner, newNestedScope(scope))
+ def makeNewScope(tree: Tree, owner: Symbol, reporter: ContextReporter = this.reporter): Context =
+ make(tree, owner, newNestedScope(scope), reporter = reporter)
/** Make a child context that buffers errors and warnings into a fresh report buffer. */
def makeSilent(reportAmbiguousErrors: Boolean = ambiguousErrors, newtree: Tree = tree): Context = {
- val c = make(newtree)
- c.setBufferErrors()
+ // A fresh buffer so as not to leak errors/warnings into `this`.
+ val c = make(newtree, reporter = new BufferingReporter)
c.setAmbiguousErrors(reportAmbiguousErrors)
- c._reportBuffer = new ReportBuffer // A fresh buffer so as not to leak errors/warnings into `this`.
+ c
+ }
+
+ def makeNonSilent(newtree: Tree): Context = {
+ val c = make(newtree, reporter = reporter.makeImmediate)
+ c.setAmbiguousErrors(true)
c
}
@@ -508,7 +539,9 @@ trait Contexts { self: Analyzer =>
*/
def makeConstructorContext = {
val baseContext = enclClass.outer.nextEnclosing(!_.tree.isInstanceOf[Template])
- val argContext = baseContext.makeNewScope(tree, owner)
+ // must propagate reporter!
+ // (caught by neg/t3649 when refactoring reporting to be specified only by this.reporter and not also by this.contextMode)
+ val argContext = baseContext.makeNewScope(tree, owner, reporter = this.reporter)
argContext.contextMode = contextMode
argContext.inSelfSuperCall = true
def enterElems(c: Context) {
@@ -533,65 +566,16 @@ trait Contexts { self: Analyzer =>
// Error and warning issuance
//
- private def addDiagString(msg: String) = {
- val ds =
- if (diagnostic.isEmpty) ""
- else diagnostic.mkString("\n","\n", "")
- if (msg endsWith ds) msg else msg + ds
- }
-
- private def unitError(pos: Position, msg: String): Unit =
- if (checking) onTreeCheckerError(pos, msg) else reporter.error(pos, msg)
-
- @inline private def issueCommon(err: AbsTypeError)(pf: PartialFunction[AbsTypeError, Unit]) {
- // TODO: are errors allowed to have pos == NoPosition??
- // if not, Jason suggests doing: val pos = err.errPos.orElse( { devWarning("Que?"); context.tree.pos })
- if (settings.Yissuedebug) {
- log("issue error: " + err.errMsg)
- (new Exception).printStackTrace()
- }
- if (pf isDefinedAt err) pf(err)
- else if (bufferErrors) { reportBuffer += err }
- else throw new TypeError(err.errPos, err.errMsg)
- }
-
/** Issue/buffer/throw the given type error according to the current mode for error reporting. */
- def issue(err: AbsTypeError) {
- issueCommon(err) { case _ if reportErrors =>
- unitError(err.errPos, addDiagString(err.errMsg))
- }
- }
-
- /** Issue/buffer/throw the given implicit ambiguity error according to the current mode for error reporting. */
- def issueAmbiguousError(pre: Type, sym1: Symbol, sym2: Symbol, err: AbsTypeError) {
- issueCommon(err) { case _ if ambiguousErrors =>
- if (!pre.isErroneous && !sym1.isErroneous && !sym2.isErroneous)
- unitError(err.errPos, err.errMsg)
- }
- }
-
+ private[typechecker] def issue(err: AbsTypeError) = reporter.issue(err)(this)
/** Issue/buffer/throw the given implicit ambiguity error according to the current mode for error reporting. */
- def issueAmbiguousError(err: AbsTypeError) {
- issueCommon(err) { case _ if ambiguousErrors => unitError(err.errPos, addDiagString(err.errMsg)) }
- }
-
- /** Issue/throw the given `err` according to the current mode for error reporting. */
- def error(pos: Position, err: Throwable) =
- if (reportErrors) unitError(pos, addDiagString(err.getMessage()))
- else throw err
-
+ private[typechecker] def issueAmbiguousError(err: AbsAmbiguousTypeError) = reporter.issueAmbiguousError(err)(this)
/** Issue/throw the given error message according to the current mode for error reporting. */
- def error(pos: Position, msg: String) = {
- val msg1 = addDiagString(msg)
- if (reportErrors) unitError(pos, msg1)
- else throw new TypeError(pos, msg1)
- }
-
+ def error(pos: Position, msg: String) = reporter.error(pos, msg)
/** Issue/throw the given error message according to the current mode for error reporting. */
- def warning(pos: Position, msg: String, force: Boolean = false) {
- if (reportErrors || force) reporter.warning(pos, msg)
- else if (bufferErrors) reportBuffer += (pos -> msg)
- }
+ def warning(pos: Position, msg: String) = reporter.warning(pos, msg)
+ def echo(pos: Position, msg: String) = reporter.echo(pos, msg)
+
def deprecationWarning(pos: Position, sym: Symbol, msg: String): Unit =
currentRun.reporting.deprecationWarning(pos, sym, msg)
@@ -601,7 +585,6 @@ trait Contexts { self: Analyzer =>
def featureWarning(pos: Position, featureName: String, featureDesc: String, featureTrait: Symbol, construct: => String = "", required: Boolean): Unit =
currentRun.reporting.featureWarning(pos, featureName, featureDesc, featureTrait, construct, required)
- def echo(pos: Position, msg: String): Unit = reporter.echo(pos, msg)
// nextOuter determines which context is searched next for implicits
// (after `this`, which contributes `newImplicits` below.) In
@@ -1238,61 +1221,176 @@ trait Contexts { self: Analyzer =>
override final def toString = super.toString + " with " + s"ImportContext { $impInfo; outer.owner = ${outer.owner} }"
}
- /** A buffer for warnings and errors that are accumulated during speculative type checking. */
- final class ReportBuffer {
+ /** A reporter for use during type checking. It has multiple modes for handling errors.
+ *
+ * The default (immediate mode) is to send the error to the global reporter.
+ * When switched into buffering mode via makeBuffering, errors and warnings are buffered and not be reported
+ * (there's a special case for ambiguity errors for some reason: those are force to the reporter when context.ambiguousErrors,
+ * or else they are buffered -- TODO: can we simplify this?)
+ *
+ * When using the type checker after typers, an error results in a TypeError being thrown. TODO: get rid of this mode.
+ *
+ * To handle nested contexts, reporters share buffers. TODO: only buffer in BufferingReporter, emit immediately in ImmediateReporter
+ */
+ abstract class ContextReporter(private[this] var _errorBuffer: mutable.LinkedHashSet[AbsTypeError] = null, private[this] var _warningBuffer: mutable.LinkedHashSet[(Position, String)] = null) extends Reporter {
type Error = AbsTypeError
type Warning = (Position, String)
- private def newBuffer[A] = mutable.LinkedHashSet.empty[A] // Important to use LinkedHS for stable results.
+ def issue(err: AbsTypeError)(implicit context: Context): Unit = handleError(err.errPos, addDiagString(err.errMsg))
- // [JZ] Contexts, pre- the SI-7345 refactor, avoided allocating the buffers until needed. This
- // is replicated here out of conservatism.
- private var _errorBuffer: mutable.LinkedHashSet[Error] = _
- private def errorBuffer = {if (_errorBuffer == null) _errorBuffer = newBuffer; _errorBuffer}
- def errors: immutable.Seq[Error] = errorBuffer.toVector
+ protected def handleError(pos: Position, msg: String): Unit
+ protected def handleSuppressedAmbiguous(err: AbsAmbiguousTypeError): Unit = ()
+ protected def handleWarning(pos: Position, msg: String): Unit = reporter.warning(pos, msg)
- private var _warningBuffer: mutable.LinkedHashSet[Warning] = _
- private def warningBuffer = {if (_warningBuffer == null) _warningBuffer = newBuffer; _warningBuffer}
- def warnings: immutable.Seq[Warning] = warningBuffer.toVector
+ def makeImmediate: ContextReporter = this
+ def makeBuffering: ContextReporter = this
+ def isBuffering: Boolean = false
- def +=(error: AbsTypeError): this.type = {
- errorBuffer += error
- this
- }
- def ++=(errors: Traversable[AbsTypeError]): this.type = {
- errorBuffer ++= errors
- this
- }
- def +=(warning: Warning): this.type = {
- warningBuffer += warning
- this
+ /** Emit an ambiguous error according to context.ambiguousErrors
+ *
+ * - when true, use global.reporter regardless of whether we're buffering (TODO: can we change this?)
+ * - else, let this context reporter decide
+ */
+ final def issueAmbiguousError(err: AbsAmbiguousTypeError)(implicit context: Context): Unit =
+ if (context.ambiguousErrors) reporter.error(err.errPos, addDiagString(err.errMsg)) // force reporting... see TODO above
+ else handleSuppressedAmbiguous(err)
+
+ @inline final def withFreshErrorBuffer[T](expr: => T): T = {
+ val previousBuffer = _errorBuffer
+ _errorBuffer = newBuffer
+ val res = expr // expr will read _errorBuffer
+ _errorBuffer = previousBuffer
+ res
}
- def clearAll(): this.type = {
- clearAllErrors(); clearAllWarnings();
+ @inline final def propagatingErrorsTo[T](target: ContextReporter)(expr: => T): T = {
+ val res = expr // TODO: make sure we're okay skipping the try/finally overhead
+ if ((this ne target) && hasErrors) { // `this eq target` in e.g., test/files/neg/divergent-implicit.scala
+ // assert(target.errorBuffer ne _errorBuffer)
+ target ++= errors
+ // TODO: is clearAllErrors necessary? (no tests failed when dropping it)
+ // NOTE: even though `this ne target`, it may still be that `target.errorBuffer eq _errorBuffer`,
+ // so don't clear the buffer, but null out the reference so that a new one will be created when necessary (should be never??)
+ // (we should refactor error buffering to avoid mutation on shared buffers)
+ clearAllErrors()
+ }
+ res
}
- def clearAllErrors(): this.type = {
- errorBuffer.clear()
- this
- }
- def clearErrors(removeF: PartialFunction[AbsTypeError, Boolean]): this.type = {
- errorBuffer.retain(!PartialFunction.cond(_)(removeF))
- this
+ protected final def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit =
+ severity match {
+ case ERROR => handleError(pos, msg)
+ case WARNING => handleWarning(pos, msg)
+ case INFO => reporter.echo(pos, msg)
+ }
+
+ final override def hasErrors = super.hasErrors || errorBuffer.nonEmpty
+
+ // TODO: everything below should be pushed down to BufferingReporter (related to buffering)
+ // Implicit relies on this most heavily, but there you know reporter.isInstanceOf[BufferingReporter]
+ // can we encode this statically?
+
+ // have to pass in context because multiple contexts may share the same ReportBuffer
+ def reportFirstDivergentError(fun: Tree, param: Symbol, paramTp: Type)(implicit context: Context): Unit =
+ errors.collectFirst {
+ case dte: DivergentImplicitTypeError => dte
+ } match {
+ case Some(divergent) =>
+ // DivergentImplicit error has higher priority than "no implicit found"
+ // no need to issue the problem again if we are still in silent mode
+ if (context.reportErrors) {
+ context.issue(divergent.withPt(paramTp))
+ errorBuffer.retain {
+ case dte: DivergentImplicitTypeError => false
+ case _ => true
+ }
+ }
+ case _ =>
+ NoImplicitFoundError(fun, param)(context)
+ }
+
+ def retainDivergentErrorsExcept(saved: DivergentImplicitTypeError) =
+ errorBuffer.retain {
+ case err: DivergentImplicitTypeError => err ne saved
+ case _ => false
+ }
+
+ def propagateImplicitTypeErrorsTo(target: ContextReporter) = {
+ errors foreach {
+ case err@(_: DivergentImplicitTypeError | _: AmbiguousImplicitTypeError) =>
+ target.errorBuffer += err
+ case _ =>
+ }
+ // debuglog("propagateImplicitTypeErrorsTo: " + errors)
}
- def retainErrors(leaveF: PartialFunction[AbsTypeError, Boolean]): this.type = {
- errorBuffer.retain(PartialFunction.cond(_)(leaveF))
- this
+
+ protected def addDiagString(msg: String)(implicit context: Context): String = {
+ val diagUsedDefaultsMsg = "Error occurred in an application involving default arguments."
+ if (context.diagUsedDefaults && !(msg endsWith diagUsedDefaultsMsg)) msg + "\n" + diagUsedDefaultsMsg
+ else msg
}
- def clearAllWarnings(): this.type = {
- warningBuffer.clear()
- this
+
+ final def emitWarnings() = if (_warningBuffer != null) {
+ _warningBuffer foreach {
+ case (pos, msg) => reporter.warning(pos, msg)
+ }
+ _warningBuffer = null
}
- def hasErrors = errorBuffer.nonEmpty
- def firstError = errorBuffer.headOption
+ // [JZ] Contexts, pre- the SI-7345 refactor, avoided allocating the buffers until needed. This
+ // is replicated here out of conservatism.
+ private def newBuffer[A] = mutable.LinkedHashSet.empty[A] // Important to use LinkedHS for stable results.
+ final protected def errorBuffer = { if (_errorBuffer == null) _errorBuffer = newBuffer; _errorBuffer }
+ final protected def warningBuffer = { if (_warningBuffer == null) _warningBuffer = newBuffer; _warningBuffer }
+
+ final def errors: immutable.Seq[Error] = errorBuffer.toVector
+ final def warnings: immutable.Seq[Warning] = warningBuffer.toVector
+ final def firstError: Option[AbsTypeError] = errorBuffer.headOption
+
+ // TODO: remove ++= and clearAll* entirely in favor of more high-level combinators like withFreshErrorBuffer
+ final private[typechecker] def ++=(errors: Traversable[AbsTypeError]): Unit = errorBuffer ++= errors
+
+ // null references to buffers instead of clearing them,
+ // as the buffers may be shared between different reporters
+ final def clearAll(): Unit = { _errorBuffer = null; _warningBuffer = null }
+ final def clearAllErrors(): Unit = { _errorBuffer = null }
+ }
+
+ private[typechecker] class ImmediateReporter(_errorBuffer: mutable.LinkedHashSet[AbsTypeError] = null, _warningBuffer: mutable.LinkedHashSet[(Position, String)] = null) extends ContextReporter(_errorBuffer, _warningBuffer) {
+ override def makeBuffering: ContextReporter = new BufferingReporter(errorBuffer, warningBuffer)
+ protected def handleError(pos: Position, msg: String): Unit = reporter.error(pos, msg)
+ }
+
+
+ private[typechecker] class BufferingReporter(_errorBuffer: mutable.LinkedHashSet[AbsTypeError] = null, _warningBuffer: mutable.LinkedHashSet[(Position, String)] = null) extends ContextReporter(_errorBuffer, _warningBuffer) {
+ override def isBuffering = true
+
+ override def issue(err: AbsTypeError)(implicit context: Context): Unit = errorBuffer += err
+
+ // this used to throw new TypeError(pos, msg) -- buffering lets us report more errors (test/files/neg/macro-basic-mamdmi)
+ // the old throwing behavior was relied on by diagnostics in manifestOfType
+ protected def handleError(pos: Position, msg: String): Unit = errorBuffer += TypeErrorWrapper(new TypeError(pos, msg))
+ override protected def handleSuppressedAmbiguous(err: AbsAmbiguousTypeError): Unit = errorBuffer += err
+ override protected def handleWarning(pos: Position, msg: String): Unit = warningBuffer += ((pos, msg))
+
+ // TODO: emit all buffered errors, warnings
+ override def makeImmediate: ContextReporter = new ImmediateReporter(errorBuffer, warningBuffer)
}
+ /** Used after typer (specialization relies on TypeError being thrown, among other post-typer phases).
+ *
+ * TODO: get rid of it, use ImmediateReporter and a check for reporter.hasErrors where necessary
+ */
+ private[typechecker] class ThrowingReporter extends ContextReporter {
+ protected def handleError(pos: Position, msg: String): Unit = throw new TypeError(pos, msg)
+ }
+
+ /** Used during a run of [[scala.tools.nsc.typechecker.TreeCheckers]]? */
+ private[typechecker] class CheckingReporter extends ContextReporter {
+ protected def handleError(pos: Position, msg: String): Unit = onTreeCheckerError(pos, msg)
+ }
+
+
class ImportInfo(val tree: Import, val depth: Int) {
def pos = tree.pos
def posOf(sel: ImportSelector) = tree.pos withPoint sel.namePos
@@ -1385,8 +1483,6 @@ object ContextMode {
def apply(bits: Int): ContextMode = new ContextMode(bits)
final val NOmode: ContextMode = 0
- final val ReportErrors: ContextMode = 1 << 0
- final val BufferErrors: ContextMode = 1 << 1
final val AmbiguousErrors: ContextMode = 1 << 2
/** Are we in a secondary constructor after the this constructor call? */
@@ -1409,8 +1505,6 @@ object ContextMode {
/** To selectively allow enrichment in patterns, where other kinds of implicit conversions are not allowed */
final val EnrichmentEnabled: ContextMode = 1 << 8
- /** Are we in a run of [[scala.tools.nsc.typechecker.TreeCheckers]]? */
- final val Checking: ContextMode = 1 << 9
/** Are we retypechecking arguments independently from the function applied to them? See `Typer.tryTypedApply`
* TODO - iron out distinction/overlap with SecondTry.
@@ -1447,17 +1541,14 @@ object ContextMode {
PatternAlternative | StarPatterns | SuperInit | SecondTry | ReturnExpr | TypeConstructorAllowed
)
- final val DefaultMode: ContextMode = MacrosEnabled
+ final val DefaultMode: ContextMode = MacrosEnabled
private val contextModeNameMap = Map(
- ReportErrors -> "ReportErrors",
- BufferErrors -> "BufferErrors",
AmbiguousErrors -> "AmbiguousErrors",
ConstructorSuffix -> "ConstructorSuffix",
SelfSuperCall -> "SelfSuperCall",
ImplicitsEnabled -> "ImplicitsEnabled",
MacrosEnabled -> "MacrosEnabled",
- Checking -> "Checking",
ReTyping -> "ReTyping",
PatternAlternative -> "PatternAlternative",
StarPatterns -> "StarPatterns",
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 73c3e6f016..b85c8e6d42 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -71,13 +71,10 @@ trait Implicits {
typingStack.printTyping(tree, "typing implicit: %s %s".format(tree, context.undetparamsString))
val implicitSearchContext = context.makeImplicit(reportAmbiguous)
val result = new ImplicitSearch(tree, pt, isView, implicitSearchContext, pos).bestImplicit
- if (result.isFailure && saveAmbiguousDivergent && implicitSearchContext.hasErrors) {
- context.updateBuffer(implicitSearchContext.reportBuffer.errors.collect {
- case dte: DivergentImplicitTypeError => dte
- case ate: AmbiguousImplicitTypeError => ate
- })
- debuglog("update buffer: " + implicitSearchContext.reportBuffer.errors)
- }
+
+ if (result.isFailure && saveAmbiguousDivergent && implicitSearchContext.reporter.hasErrors)
+ implicitSearchContext.reporter.propagateImplicitTypeErrorsTo(context.reporter)
+
// SI-7944 undetermined type parameters that result from inference within typedImplicit land in
// `implicitSearchContext.undetparams`, *not* in `context.undetparams`
// Here, we copy them up to parent context (analogously to the way the errors are copied above),
@@ -99,7 +96,7 @@ trait Implicits {
def wrapper(inference: => SearchResult) = wrapper1(inference)
val result = wrapper(inferImplicit(tree, pt, reportAmbiguous = true, isView = isView, context = context, saveAmbiguousDivergent = !silent, pos = pos))
if (result.isFailure && !silent) {
- val err = context.firstError
+ val err = context.reporter.firstError
val errPos = err.map(_.errPos).getOrElse(pos)
val errMsg = err.map(_.errMsg).getOrElse("implicit search has failed. to find out the reason, turn on -Xlog-implicits")
onError(errPos, errMsg)
@@ -635,7 +632,7 @@ trait Implicits {
}
case _ => fallback
}
- context.firstError match { // using match rather than foreach to avoid non local return.
+ context.reporter.firstError match { // using match rather than foreach to avoid non local return.
case Some(err) =>
log("implicit adapt failed: " + err.errMsg)
return fail(err.errMsg)
@@ -658,8 +655,8 @@ trait Implicits {
}
}
- if (context.hasErrors)
- fail("hasMatchingSymbol reported error: " + context.firstError.get.errMsg)
+ if (context.reporter.hasErrors)
+ fail("hasMatchingSymbol reported error: " + context.reporter.firstError.get.errMsg)
else if (itree3.isErroneous)
fail("error typechecking implicit candidate")
else if (isLocalToCallsite && !hasMatchingSymbol(itree2))
@@ -677,7 +674,7 @@ trait Implicits {
// #2421: check that we correctly instantiated type parameters outside of the implicit tree:
checkBounds(itree3, NoPrefix, NoSymbol, undetParams, targs, "inferred ")
- context.firstError match {
+ context.reporter.firstError match {
case Some(err) =>
return fail("type parameters weren't correctly instantiated outside of the implicit tree: " + err.errMsg)
case None =>
@@ -716,7 +713,7 @@ trait Implicits {
case t => t
}
- context.firstError match {
+ context.reporter.firstError match {
case Some(err) =>
fail("typing TypeApply reported errors for the implicit tree: " + err.errMsg)
case None =>
@@ -857,13 +854,11 @@ trait Implicits {
SearchFailure
} else {
if (search.isFailure) {
- // We don't want errors that occur during checking implicit info
+ // Discard the divergentError we saved (if any), as well as all errors that are not of type DivergentImplicitTypeError
+ // We don't want errors that occur while checking the implicit info
// to influence the check of further infos, but we should retain divergent implicit errors
// (except for the one we already squirreled away)
- val saved = divergentError.getOrElse(null)
- context.reportBuffer.retainErrors {
- case err: DivergentImplicitTypeError => err ne saved
- }
+ context.reporter.retainDivergentErrorsExcept(divergentError.getOrElse(null))
}
search
}
@@ -909,7 +904,7 @@ trait Implicits {
// the first `DivergentImplicitTypeError` that is being propagated
// from a nested implicit search; this one will be
// re-issued if this level of the search fails.
- DivergentImplicitRecovery(typedFirstPending, firstPending, context.errors) match {
+ DivergentImplicitRecovery(typedFirstPending, firstPending, context.reporter.errors) match {
case sr if sr.isDivergent => Nil
case sr if sr.isFailure => rankImplicits(otherPending, acc)
case newBest =>
@@ -1146,7 +1141,7 @@ trait Implicits {
try {
val tree1 = typedPos(pos.focus)(arg)
- context.firstError match {
+ context.reporter.firstError match {
case Some(err) => processMacroExpansionError(err.errPos, err.errMsg)
case None => new SearchResult(tree1, EmptyTreeTypeSubstituter, Nil)
}
@@ -1278,19 +1273,20 @@ trait Implicits {
if (tagInScope.isEmpty) mot(tp, Nil, Nil)
else {
if (ReflectRuntimeUniverse == NoSymbol) {
- // todo. write a test for this
- context.error(pos,
+ // TODO: write a test for this (the next error message is already checked by neg/interop_typetags_without_classtags_arenot_manifests.scala)
+ // TODO: this was using context.error, and implicit search always runs in silent mode, thus it was actually throwing a TypeError
+ // with the new strategy-based reporting, a BufferingReporter buffers instead of throwing
+ // it would be good to rework this logic to fit into the regular context.error mechanism
+ throw new TypeError(pos,
sm"""to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope.
|however typetag -> manifest conversion requires Scala reflection, which is not present on the classpath.
|to proceed put scala-reflect.jar on your compilation classpath and recompile.""")
- return SearchFailure
}
if (resolveClassTag(pos, tp, allowMaterialization = true) == EmptyTree) {
- context.error(pos,
+ throw new TypeError(pos,
sm"""to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope.
|however typetag -> manifest conversion requires a class tag for the corresponding type to be present.
|to proceed add a class tag to the type `$tp` (e.g. by introducing a context bound) and recompile.""")
- return SearchFailure
}
val cm = typed(Ident(ReflectRuntimeCurrentMirror))
val internal = gen.mkAttributedSelect(gen.mkAttributedRef(ReflectRuntimeUniverse), UniverseInternal)
@@ -1346,52 +1342,66 @@ trait Implicits {
* If all fails return SearchFailure
*/
def bestImplicit: SearchResult = {
- val failstart = if (Statistics.canEnable) Statistics.startTimer(inscopeFailNanos) else null
- val succstart = if (Statistics.canEnable) Statistics.startTimer(inscopeSucceedNanos) else null
+ val stats = Statistics.canEnable
+ val failstart = if (stats) Statistics.startTimer(inscopeFailNanos) else null
+ val succstart = if (stats) Statistics.startTimer(inscopeSucceedNanos) else null
var result = searchImplicit(context.implicitss, isLocalToCallsite = true)
- if (result.isFailure) {
- if (Statistics.canEnable) Statistics.stopTimer(inscopeFailNanos, failstart)
- } else {
- if (Statistics.canEnable) Statistics.stopTimer(inscopeSucceedNanos, succstart)
- if (Statistics.canEnable) Statistics.incCounter(inscopeImplicitHits)
+ if (stats) {
+ if (result.isFailure) Statistics.stopTimer(inscopeFailNanos, failstart)
+ else {
+ Statistics.stopTimer(inscopeSucceedNanos, succstart)
+ Statistics.incCounter(inscopeImplicitHits)
+ }
}
+
if (result.isFailure) {
- val previousErrs = context.flushAndReturnBuffer()
- val failstart = if (Statistics.canEnable) Statistics.startTimer(oftypeFailNanos) else null
- val succstart = if (Statistics.canEnable) Statistics.startTimer(oftypeSucceedNanos) else null
+ val failstart = if (stats) Statistics.startTimer(oftypeFailNanos) else null
+ val succstart = if (stats) Statistics.startTimer(oftypeSucceedNanos) else null
+
+ // SI-6667, never search companions after an ambiguous error in in-scope implicits
+ val wasAmbigious = result.isAmbiguousFailure
+
+ // TODO: encapsulate
+ val previousErrs = context.reporter.errors
+ context.reporter.clearAllErrors()
- val wasAmbigious = result.isAmbiguousFailure // SI-6667, never search companions after an ambiguous error in in-scope implicits
result = materializeImplicit(pt)
+
// `materializeImplicit` does some preprocessing for `pt`
// is it only meant for manifests/tags or we need to do the same for `implicitsOfExpectedType`?
if (result.isFailure && !wasAmbigious)
result = searchImplicit(implicitsOfExpectedType, isLocalToCallsite = false)
- if (result.isFailure) {
- context.updateBuffer(previousErrs)
- if (Statistics.canEnable) Statistics.stopTimer(oftypeFailNanos, failstart)
- } else {
- if (Statistics.canEnable) Statistics.stopTimer(oftypeSucceedNanos, succstart)
- if (Statistics.canEnable) Statistics.incCounter(oftypeImplicitHits)
+ if (result.isFailure)
+ context.reporter ++= previousErrs
+
+ if (stats) {
+ if (result.isFailure) Statistics.stopTimer(oftypeFailNanos, failstart)
+ else {
+ Statistics.stopTimer(oftypeSucceedNanos, succstart)
+ Statistics.incCounter(oftypeImplicitHits)
+ }
}
}
if (result.isSuccess && isView) {
def maybeInvalidConversionError(msg: String) {
// We have to check context.ambiguousErrors even though we are calling "issueAmbiguousError"
// which ostensibly does exactly that before issuing the error. Why? I have no idea. Test is pos/t7690.
+ // AM: I would guess it's because ambiguous errors will be buffered in silent mode if they are not reported
if (context.ambiguousErrors)
context.issueAmbiguousError(AmbiguousImplicitTypeError(tree, msg))
}
pt match {
case Function1(_, out) =>
- def prohibit(sym: Symbol) = if (sym.tpe <:< out) {
- maybeInvalidConversionError(s"the result type of an implicit conversion must be more specific than ${sym.name}")
- result = SearchFailure
+ // must inline to avoid capturing result
+ def prohibit(sym: Symbol) = (sym.tpe <:< out) && {
+ maybeInvalidConversionError(s"the result type of an implicit conversion must be more specific than ${sym.name}")
+ true
}
- prohibit(AnyRefClass)
- if (settings.isScala211) prohibit(AnyValClass)
+ if (prohibit(AnyRefClass) || (settings.isScala211 && prohibit(AnyValClass)))
+ result = SearchFailure
case _ => false
}
if (settings.isScala211 && isInvalidConversionSource(pt)) {
@@ -1399,8 +1409,9 @@ trait Implicits {
result = SearchFailure
}
}
- if (result.isFailure)
- debuglog("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+implicitsOfExpectedType)
+
+ if (result.isFailure && settings.debug) // debuglog is not inlined for some reason
+ log("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+implicitsOfExpectedType)
result
}
@@ -1422,20 +1433,19 @@ trait Implicits {
val eligible = new ImplicitComputation(iss, isLocalToCallsite).eligible
eligible.toList.flatMap {
(ii: ImplicitInfo) =>
- // each ImplicitInfo contributes a distinct set of constraints (generated indirectly by typedImplicit)
- // thus, start each type var off with a fresh for every typedImplicit
- resetTVars()
- // any previous errors should not affect us now
- context.flushBuffer()
-
- val res = typedImplicit(ii, ptChecked = false, isLocalToCallsite)
- if (res.tree ne EmptyTree) List((res, tvars map (_.constr)))
- else Nil
+ // each ImplicitInfo contributes a distinct set of constraints (generated indirectly by typedImplicit)
+ // thus, start each type var off with a fresh for every typedImplicit
+ resetTVars()
+ // any previous errors should not affect us now
+ context.reporter.clearAllErrors()
+ val res = typedImplicit(ii, ptChecked = false, isLocalToCallsite)
+ if (res.tree ne EmptyTree) List((res, tvars map (_.constr)))
+ else Nil
+ }
}
- }
eligibleInfos(context.implicitss, isLocalToCallsite = true) ++
eligibleInfos(implicitsOfExpectedType, isLocalToCallsite = false)
- }
+ }
}
object ImplicitNotFoundMsg {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index a3f1da60ce..fb7651ffd6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -199,8 +199,6 @@ trait Infer extends Checkable {
def getContext = context
- def issue(err: AbsTypeError): Unit = context.issue(err)
-
def explainTypes(tp1: Type, tp2: Type) = {
if (context.reportErrors)
withDisambiguation(List(), tp1, tp2)(global.explainTypes(tp1, tp2))
@@ -781,7 +779,7 @@ trait Infer extends Checkable {
def applicableExpectingPt(pt: Type): Boolean = {
val silent = context.makeSilent(reportAmbiguousErrors = false)
val result = newTyper(silent).infer.isApplicable(undetparams, ftpe, argtpes0, pt)
- if (silent.hasErrors && !pt.isWildcard)
+ if (silent.reporter.hasErrors && !pt.isWildcard)
applicableExpectingPt(WildcardType) // second try
else
result
@@ -1266,33 +1264,36 @@ trait Infer extends Checkable {
* If no alternative matches `pt`, take the parameterless one anyway.
*/
def inferExprAlternative(tree: Tree, pt: Type): Tree = {
- def tryOurBests(pre: Type, alts: List[Symbol], isSecondTry: Boolean): Unit = {
- val alts0 = alts filter (alt => isWeaklyCompatible(pre memberType alt, pt))
- val alts1 = if (alts0.isEmpty) alts else alts0
- val bests = bestAlternatives(alts1) { (sym1, sym2) =>
- val tp1 = pre memberType sym1
- val tp2 = pre memberType sym2
-
- ( (tp2 eq ErrorType)
- || isWeaklyCompatible(tp1, pt) && !isWeaklyCompatible(tp2, pt)
- || isStrictlyMoreSpecific(tp1, tp2, sym1, sym2)
- )
- }
- // todo: missing test case for bests.isEmpty
- bests match {
- case best :: Nil => tree setSymbol best setType (pre memberType best)
- case best :: competing :: _ if alts0.nonEmpty =>
- // SI-6912 Don't give up and leave an OverloadedType on the tree.
- // Originally I wrote this as `if (secondTry) ... `, but `tryTwice` won't attempt the second try
- // unless an error is issued. We're not issuing an error, in the assumption that it would be
- // spurious in light of the erroneous expected type
- if (pt.isErroneous) setError(tree)
- else AmbiguousExprAlternativeError(tree, pre, best, competing, pt, isSecondTry)
- case _ => if (bests.isEmpty || alts0.isEmpty) NoBestExprAlternativeError(tree, pt, isSecondTry)
+ val c = context
+ class InferTwice(pre: Type, alts: List[Symbol]) extends c.TryTwice {
+ def tryOnce(isSecondTry: Boolean): Unit = {
+ val alts0 = alts filter (alt => isWeaklyCompatible(pre memberType alt, pt))
+ val alts1 = if (alts0.isEmpty) alts else alts0
+ val bests = bestAlternatives(alts1) { (sym1, sym2) =>
+ val tp1 = pre memberType sym1
+ val tp2 = pre memberType sym2
+
+ ( (tp2 eq ErrorType)
+ || isWeaklyCompatible(tp1, pt) && !isWeaklyCompatible(tp2, pt)
+ || isStrictlyMoreSpecific(tp1, tp2, sym1, sym2)
+ )
+ }
+ // todo: missing test case for bests.isEmpty
+ bests match {
+ case best :: Nil => tree setSymbol best setType (pre memberType best)
+ case best :: competing :: _ if alts0.nonEmpty =>
+ // SI-6912 Don't give up and leave an OverloadedType on the tree.
+ // Originally I wrote this as `if (secondTry) ... `, but `tryTwice` won't attempt the second try
+ // unless an error is issued. We're not issuing an error, in the assumption that it would be
+ // spurious in light of the erroneous expected type
+ if (pt.isErroneous) setError(tree)
+ else AmbiguousExprAlternativeError(tree, pre, best, competing, pt, isSecondTry)
+ case _ => if (bests.isEmpty || alts0.isEmpty) NoBestExprAlternativeError(tree, pt, isSecondTry)
+ }
}
}
tree.tpe match {
- case OverloadedType(pre, alts) => tryTwice(tryOurBests(pre, alts, _)) ; tree
+ case OverloadedType(pre, alts) => (new InferTwice(pre, alts)).apply() ; tree
case _ => tree
}
}
@@ -1370,70 +1371,41 @@ trait Infer extends Checkable {
* @pre tree.tpe is an OverloadedType.
*/
def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], argtpes0: List[Type], pt0: Type): Unit = {
- val OverloadedType(pre, alts) = tree.tpe
- var varargsStar = false
- val argtpes = argtpes0 mapConserve {
- case RepeatedType(tp) => varargsStar = true ; tp
- case tp => tp
- }
- def followType(sym: Symbol) = followApply(pre memberType sym)
- def bestForExpectedType(pt: Type, isLastTry: Boolean): Unit = {
- val applicable0 = alts filter (alt => context inSilentMode isApplicable(undetparams, followType(alt), argtpes, pt))
- val applicable = overloadsToConsiderBySpecificity(applicable0, argtpes, varargsStar)
- val ranked = bestAlternatives(applicable)((sym1, sym2) =>
- isStrictlyMoreSpecific(followType(sym1), followType(sym2), sym1, sym2)
- )
- ranked match {
- case best :: competing :: _ => AmbiguousMethodAlternativeError(tree, pre, best, competing, argtpes, pt, isLastTry) // ambiguous
- case best :: Nil => tree setSymbol best setType (pre memberType best) // success
- case Nil if pt.isWildcard => NoBestMethodAlternativeError(tree, argtpes, pt, isLastTry) // failed
- case Nil => bestForExpectedType(WildcardType, isLastTry) // failed, but retry with WildcardType
- }
- }
- // This potentially makes up to four attempts: tryTwice may execute
+ // This potentially makes up to four attempts: tryOnce may execute
// with and without views enabled, and bestForExpectedType will try again
// with pt = WildcardType if it fails with pt != WildcardType.
- tryTwice { isLastTry =>
- val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0
- debuglog(s"infer method alt ${tree.symbol} with alternatives ${alts map pre.memberType} argtpes=$argtpes pt=$pt")
- bestForExpectedType(pt, isLastTry)
- }
- }
+ val c = context
+ class InferMethodAlternativeTwice extends c.TryTwice {
+ private[this] val OverloadedType(pre, alts) = tree.tpe
+ private[this] var varargsStar = false
+ private[this] val argtpes = argtpes0 mapConserve {
+ case RepeatedType(tp) => varargsStar = true ; tp
+ case tp => tp
+ }
- /** Try inference twice, once without views and once with views,
- * unless views are already disabled.
- */
- def tryTwice(infer: Boolean => Unit): Unit = {
- if (context.implicitsEnabled) {
- val savedContextMode = context.contextMode
- var fallback = false
- context.setBufferErrors()
- // We cache the current buffer because it is impossible to
- // distinguish errors that occurred before entering tryTwice
- // and our first attempt in 'withImplicitsDisabled'. If the
- // first attempt fails we try with implicits on *and* clean
- // buffer but that would also flush any pre-tryTwice valid
- // errors, hence some manual buffer tweaking is necessary.
- val errorsToRestore = context.flushAndReturnBuffer()
- try {
- context.withImplicitsDisabled(infer(false))
- if (context.hasErrors) {
- fallback = true
- context.contextMode = savedContextMode
- context.flushBuffer()
- infer(true)
+ private def followType(sym: Symbol) = followApply(pre memberType sym)
+ // separate method to help the inliner
+ private def isAltApplicable(pt: Type)(alt: Symbol) = context inSilentMode { isApplicable(undetparams, followType(alt), argtpes, pt) && !context.reporter.hasErrors }
+ private def rankAlternatives(sym1: Symbol, sym2: Symbol) = isStrictlyMoreSpecific(followType(sym1), followType(sym2), sym1, sym2)
+ private def bestForExpectedType(pt: Type, isLastTry: Boolean): Unit = {
+ val applicable = overloadsToConsiderBySpecificity(alts filter isAltApplicable(pt), argtpes, varargsStar)
+ val ranked = bestAlternatives(applicable)(rankAlternatives)
+ ranked match {
+ case best :: competing :: _ => AmbiguousMethodAlternativeError(tree, pre, best, competing, argtpes, pt, isLastTry) // ambiguous
+ case best :: Nil => tree setSymbol best setType (pre memberType best) // success
+ case Nil if pt.isWildcard => NoBestMethodAlternativeError(tree, argtpes, pt, isLastTry) // failed
+ case Nil => bestForExpectedType(WildcardType, isLastTry) // failed, but retry with WildcardType
}
- } catch {
- case ex: CyclicReference => throw ex
- case ex: TypeError => // recoverable cyclic references
- context.contextMode = savedContextMode
- if (!fallback) infer(true) else ()
- } finally {
- context.contextMode = savedContextMode
- context.updateBuffer(errorsToRestore)
+ }
+
+ private[this] val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0
+ def tryOnce(isLastTry: Boolean): Unit = {
+ debuglog(s"infer method alt ${tree.symbol} with alternatives ${alts map pre.memberType} argtpes=$argtpes pt=$pt")
+ bestForExpectedType(pt, isLastTry)
}
}
- else infer(true)
+
+ (new InferMethodAlternativeTwice).apply()
}
/** Assign `tree` the type of all polymorphic alternatives
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 33d3432ae2..da7b8b09aa 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -226,7 +226,8 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
val Apply(_, pickledPayload) = wrapped
val payload = pickledPayload.map{ case Assign(k, v) => (unpickleAtom(k), unpickleAtom(v)) }.toMap
- import typer.TyperErrorGen._
+ // TODO: refactor error handling: fail always throws a TypeError,
+ // and uses global state (analyzer.lastTreeToTyper) to determine the position for the error
def fail(msg: String) = MacroCantExpandIncompatibleMacrosError(msg)
def unpickle[T](field: String, clazz: Class[T]): T = {
def failField(msg: String) = fail(s"$field $msg")
@@ -624,7 +625,7 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
// `macroExpandApply` is called from `adapt`, where implicit conversions are disabled
// therefore we need to re-enable the conversions back temporarily
val result = typer.context.withImplicitsEnabled(typer.typed(tree, mode, pt))
- if (result.isErrorTyped && macroDebugVerbose) println(s"$label has failed: ${typer.context.reportBuffer.errors}")
+ if (result.isErrorTyped && macroDebugVerbose) println(s"$label has failed: ${typer.context.reporter.errors}")
result
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 7bbd81118a..fdff2f3076 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -1494,8 +1494,7 @@ trait Namers extends MethodSynthesis {
case defn: MemberDef =>
val ainfos = defn.mods.annotations filterNot (_ eq null) map { ann =>
val ctx = typer.context
- val annCtx = ctx.make(ann)
- annCtx.setReportErrors()
+ val annCtx = ctx.makeNonSilent(ann)
// need to be lazy, #1782. beforeTyper to allow inferView in annotation args, SI-5892.
AnnotationInfo lazily {
enteringTyper(newTyper(annCtx) typedAnnotation ann)
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
index cf3f265f0c..da0e67a2a5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
@@ -261,7 +261,7 @@ trait PatternTypers {
def doTypedUnapply(tree: Tree, fun0: Tree, fun: Tree, args: List[Tree], mode: Mode, pt: Type): Tree = {
def duplErrTree = setError(treeCopy.Apply(tree, fun0, args))
- def duplErrorTree(err: AbsTypeError) = { issue(err); duplErrTree }
+ def duplErrorTree(err: AbsTypeError) = { context.issue(err); duplErrTree }
if (args.length > MaxTupleArity)
return duplErrorTree(TooManyArgsPatternError(fun))
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index 399a4ca8d5..743bbe53bd 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -208,8 +208,7 @@ abstract class TreeCheckers extends Analyzer {
}
def check(unit: CompilationUnit) {
informProgress("checking "+unit)
- val context = rootContext(unit)
- context.checking = true
+ val context = rootContext(unit, checking = true)
tpeOfTree.clear()
SymbolTracker.check(phase, unit)
val checker = new TreeChecker(context)
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index 7440f69e93..89b064e7c1 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -572,11 +572,11 @@ trait TypeDiagnostics {
} else f
}
def apply(tree: Tree): Tree = {
- // Error suppression will squash some of these warnings unless we circumvent it.
+ // Error suppression (in context.warning) would squash some of these warnings.
// It is presumed if you are using a -Y option you would really like to hear
- // the warnings you've requested.
+ // the warnings you've requested; thus, use reporter.warning.
if (settings.warnDeadCode && context.unit.exists && treeOK(tree) && exprOK)
- context.warning(tree.pos, "dead code following this construct", force = true)
+ reporter.warning(tree.pos, "dead code following this construct")
tree
}
@@ -629,7 +629,7 @@ trait TypeDiagnostics {
throw new FatalError("cannot redefine root "+sym)
}
case _ =>
- context0.error(ex.pos, ex)
+ context0.error(ex.pos, ex.msg)
}
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 70f44c4fc6..0621fbefe4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -155,21 +155,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
} else {
mkArg = gen.mkNamedArg // don't pass the default argument (if any) here, but start emitting named arguments for the following args
if (!param.hasDefault && !paramFailed) {
- context.reportBuffer.errors.collectFirst {
- case dte: DivergentImplicitTypeError => dte
- } match {
- case Some(divergent) =>
- // DivergentImplicit error has higher priority than "no implicit found"
- // no need to issue the problem again if we are still in silent mode
- if (context.reportErrors) {
- context.issue(divergent.withPt(paramTp))
- context.reportBuffer.clearErrors {
- case dte: DivergentImplicitTypeError => true
- }
- }
- case _ =>
- NoImplicitFoundError(fun, param)
- }
+ context.reporter.reportFirstDivergentError(fun, param, paramTp)(context)
paramFailed = true
}
/* else {
@@ -478,20 +464,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (cond) typerWithLocalContext(c)(f) else f(this)
@inline
- final def typerWithLocalContext[T](c: Context)(f: Typer => T): T = {
- val res = f(newTyper(c))
- if (c.hasErrors)
- context.updateBuffer(c.flushAndReturnBuffer())
- res
- }
-
- @inline
- final def withSavedContext[T](c: Context)(f: => T) = {
- val savedErrors = c.flushAndReturnBuffer()
- val res = f
- c.updateBuffer(savedErrors)
- res
- }
+ final def typerWithLocalContext[T](c: Context)(f: Typer => T): T =
+ c.reporter.propagatingErrorsTo(context.reporter)(f(newTyper(c)))
/** The typer for a label definition. If this is part of a template we
* first have to enter the label definition.
@@ -684,6 +658,12 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (Statistics.canEnable) Statistics.stopCounter(subtypeFailed, subtypeStart)
if (Statistics.canEnable) Statistics.stopTimer(failedSilentNanos, failedSilentStart)
}
+ @inline def wrapResult(reporter: ContextReporter, result: T) =
+ if (reporter.hasErrors) {
+ stopStats()
+ SilentTypeError(reporter.errors: _*)
+ } else SilentResultValue(result)
+
try {
if (context.reportErrors ||
reportAmbiguousErrors != context.ambiguousErrors ||
@@ -697,20 +677,17 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
context.undetparams = context1.undetparams
context.savedTypeBounds = context1.savedTypeBounds
context.namedApplyBlockInfo = context1.namedApplyBlockInfo
- if (context1.hasErrors) {
- stopStats()
- SilentTypeError(context1.errors: _*)
- } else {
- // If we have a successful result, emit any warnings it created.
- context1.flushAndIssueWarnings()
- SilentResultValue(result)
- }
+
+ // If we have a successful result, emit any warnings it created.
+ if (!context1.reporter.hasErrors)
+ context1.reporter.emitWarnings()
+
+ wrapResult(context1.reporter, result)
} else {
assert(context.bufferErrors || isPastTyper, "silent mode is not available past typer")
- withSavedContext(context){
- val res = op(this)
- val errorsToReport = context.flushAndReturnBuffer()
- if (errorsToReport.isEmpty) SilentResultValue(res) else SilentTypeError(errorsToReport.head)
+
+ context.reporter.withFreshErrorBuffer {
+ wrapResult(context.reporter, op(this))
}
}
} catch {
@@ -816,14 +793,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
// avoid throwing spurious DivergentImplicit errors
- if (context.hasErrors)
+ if (context.reporter.hasErrors)
setError(tree)
else
withCondConstrTyper(treeInfo.isSelfOrSuperConstrCall(tree))(typer1 =>
if (original != EmptyTree && pt != WildcardType) (
typer1 silent { tpr =>
val withImplicitArgs = tpr.applyImplicitArgs(tree)
- if (tpr.context.hasErrors) tree // silent will wrap it in SilentTypeError anyway
+ if (tpr.context.reporter.hasErrors) tree // silent will wrap it in SilentTypeError anyway
else tpr.typed(withImplicitArgs, mode, pt)
}
orElse { _ =>
@@ -1057,7 +1034,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val silentContext = context.makeImplicit(context.ambiguousErrors)
val res = newTyper(silentContext).typed(
new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt)
- silentContext.firstError match {
+ silentContext.reporter.firstError match {
case Some(err) => context.issue(err)
case None => return res
}
@@ -2990,7 +2967,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
ConstructorsOrderError(stat)
}
- if (treeInfo.isPureExprForWarningPurposes(result)) context.warning(stat.pos,
+ if (!isPastTyper && treeInfo.isPureExprForWarningPurposes(result)) context.warning(stat.pos,
"a pure expression does nothing in statement position; " +
"you may be omitting necessary parentheses"
)
@@ -3149,7 +3126,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def doTypedApply(tree: Tree, fun0: Tree, args: List[Tree], mode: Mode, pt: Type): Tree = {
// TODO_NMT: check the assumption that args nonEmpty
def duplErrTree = setError(treeCopy.Apply(tree, fun0, args))
- def duplErrorTree(err: AbsTypeError) = { issue(err); duplErrTree }
+ def duplErrorTree(err: AbsTypeError) = { context.issue(err); duplErrTree }
def preSelectOverloaded(fun: Tree): Tree = {
if (fun.hasSymbolField && fun.symbol.isOverloaded) {
@@ -3229,7 +3206,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
(arg1, arg1.tpe.deconst)
}.unzip
}
- if (context.hasErrors)
+ if (context.reporter.hasErrors)
setError(tree)
else {
inferMethodAlternative(fun, undetparams, argTpes, pt)
@@ -3357,8 +3334,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
duplErrTree
} else if (lencmp2 == 0) {
// useful when a default doesn't match parameter type, e.g. def f[T](x:T="a"); f[Int]()
- val note = "Error occurred in an application involving default arguments."
- if (!(context.diagnostic contains note)) context.diagnostic = note :: context.diagnostic
+ context.diagUsedDefaults = true
doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt)
} else {
rollbackNamesDefaultsOwnerChanges()
@@ -4331,7 +4307,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
c.retyping = true
try {
val res = newTyper(c).typedArgs(args, mode)
- if (c.hasErrors) None else Some(res)
+ if (c.reporter.hasErrors) None else Some(res)
} catch {
case ex: CyclicReference =>
throw ex
@@ -4395,7 +4371,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case _ => ()
}
}
- typeErrors foreach issue
+ typeErrors foreach context.issue
setError(treeCopy.Apply(tree, fun, args))
}
@@ -4449,7 +4425,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
doTypedApply(tree, fun2, args, mode, pt)
case err: SilentTypeError =>
onError({
- err.reportableErrors foreach issue
+ err.reportableErrors foreach context.issue
args foreach (arg => typed(arg, mode, ErrorType))
setError(tree)
})
@@ -4686,7 +4662,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
else
// before failing due to access, try a dynamic call.
asDynamicCall getOrElse {
- issue(accessibleError.get)
+ context.issue(accessibleError.get)
setError(tree)
}
case _ =>
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index 923297bafb..1643e0061f 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -142,7 +142,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
run.symSource(ownerClass) = NoAbstractFile // need to set file to something different from null, so that currentRun.defines works
phase = run.typerPhase // need to set a phase to something <= typerPhase, otherwise implicits in typedSelect will be disabled
globalPhase = run.typerPhase // amazing... looks like phase and globalPhase are different things, so we need to set them separately
- currentTyper.context.setReportErrors() // need to manually set context mode, otherwise typer.silent will throw exceptions
+ currentTyper.context.initRootContext() // need to manually set context mode, otherwise typer.silent will throw exceptions
reporter.reset()
val expr3 = withContext(transform(currentTyper, expr2))
diff --git a/src/eclipse/repl/.classpath b/src/eclipse/repl/.classpath
index 601a231aeb..8ff9aabfbf 100644
--- a/src/eclipse/repl/.classpath
+++ b/src/eclipse/repl/.classpath
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="src" path="repl"/>
- <classpathentry combineaccessrules="false" kind="src" path="/asm"/>
- <classpathentry kind="var" path="M2_REPO/jline/jline/2.11/jline-2.11.jar"/>
- <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/>
- <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_COMPILER_CONTAINER"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/repl/jline-2.11.jar"/>
- <classpathentry kind="output" path="build-quick-repl"/>
+ <classpathentry kind="src" path="repl"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/asm"/>
+ <classpathentry kind="var" path="M2_REPO/jline/jline/2.12/jline-2.12.jar"/>
+ <!-- <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/repl/jline-2.12.jar"/> -->
+ <classpathentry combineaccessrules="false" kind="src" path="/scala-compiler"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/scala-library"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="output" path="build-quick-repl"/>
</classpath>
diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala
index ed3b305d59..2632994a34 100644
--- a/src/library/scala/StringContext.scala
+++ b/src/library/scala/StringContext.scala
@@ -163,7 +163,7 @@ case class StringContext(parts: String*) {
*/
// The implementation is hardwired to `scala.tools.reflect.MacroImplementations.macro_StringInterpolation_f`
// Using the mechanism implemented in `scala.tools.reflect.FastTrack`
- def f(args: Any*): String = macro ???
+ def f[A >: Any](args: A*): String = macro ???
}
object StringContext {
@@ -173,8 +173,13 @@ object StringContext {
* @param str The offending string
* @param idx The index of the offending backslash character in `str`.
*/
- class InvalidEscapeException(str: String, @deprecatedName('idx) val index: Int)
- extends IllegalArgumentException("invalid escape character at index "+index+" in \""+str+"\"")
+ class InvalidEscapeException(str: String, @deprecatedName('idx) val index: Int) extends IllegalArgumentException(
+ s"""invalid escape ${
+ require(index >= 0 && index < str.length)
+ val ok = """[\b, \t, \n, \f, \r, \\, \", \']"""
+ if (index == str.length - 1) "at terminal" else s"'\\${str(index + 1)}' not one of $ok at"
+ } index $index in "$str". Use \\\\ for literal \\."""
+ )
/** Expands standard Scala escape sequences in a string.
* Escape sequences are:
diff --git a/src/library/scala/collection/IterableProxy.scala b/src/library/scala/collection/IterableProxy.scala
index 3a0e2ab115..97aa830c5a 100644
--- a/src/library/scala/collection/IterableProxy.scala
+++ b/src/library/scala/collection/IterableProxy.scala
@@ -16,4 +16,5 @@ package collection
* @version 2.8
* @since 2.8
*/
+@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3")
trait IterableProxy[+A] extends Iterable[A] with IterableProxyLike[A, Iterable[A]]
diff --git a/src/library/scala/collection/MapProxy.scala b/src/library/scala/collection/MapProxy.scala
index 941c1f5a4a..26a7c710ee 100644
--- a/src/library/scala/collection/MapProxy.scala
+++ b/src/library/scala/collection/MapProxy.scala
@@ -17,4 +17,5 @@ package collection
* @version 1.0, 21/07/2003
* @since 1
*/
+@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3")
trait MapProxy[A, +B] extends Map[A, B] with MapProxyLike[A, B, Map[A, B]]
diff --git a/src/library/scala/collection/SetProxy.scala b/src/library/scala/collection/SetProxy.scala
index f9f38f148a..e17fb215b9 100644
--- a/src/library/scala/collection/SetProxy.scala
+++ b/src/library/scala/collection/SetProxy.scala
@@ -17,4 +17,5 @@ package collection
* @author Martin Odersky
* @version 2.0, 01/01/2007
*/
+@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3")
trait SetProxy[A] extends Set[A] with SetProxyLike[A, Set[A]]
diff --git a/src/library/scala/collection/TraversableProxy.scala b/src/library/scala/collection/TraversableProxy.scala
index 65936da0e4..9eec685d10 100644
--- a/src/library/scala/collection/TraversableProxy.scala
+++ b/src/library/scala/collection/TraversableProxy.scala
@@ -21,4 +21,5 @@ package collection
* @version 2.8
* @since 2.8
*/
+@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3")
trait TraversableProxy[+A] extends Traversable[A] with TraversableProxyLike[A, Traversable[A]]
diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala
index 2e1bfb02e4..5c4e706dc1 100644
--- a/src/library/scala/util/matching/Regex.scala
+++ b/src/library/scala/util/matching/Regex.scala
@@ -6,7 +6,6 @@
** |/ **
\* */
-
/**
* This package is concerned with regular expression (regex) matching against strings,
* with the main goal of pulling out information from those matches, or replacing
@@ -28,117 +27,127 @@
* into a [[java.lang.String]].
*
*/
-package scala
-package util.matching
+package scala.util.matching
import scala.collection.AbstractIterator
import java.util.regex.{ Pattern, Matcher }
-/** This class provides methods for creating and using regular expressions.
- * It is based on the regular expressions of the JDK since 1.4.
+/** A regular expression is used to determine whether a string matches a pattern
+ * and, if it does, to extract or transform the parts that match.
*
- * Its main goal is to extract strings that match a pattern, or the subgroups
- * that make it up. For that reason, it is usually used with for comprehensions
- * and matching (see methods for examples).
+ * This class delegates to the [[java.util.regex]] package of the Java Platform.
+ * See the documentation for [[java.util.regex.Pattern]] for details about
+ * the regular expression syntax for pattern strings.
*
- * A Regex is created from a [[java.lang.String]] representation of the
- * regular expression pattern^1^. That pattern is compiled
- * during construction, so frequently used patterns should be declared outside
- * loops if performance is of concern. Possibly, they might be declared on a
- * companion object, so that they need only to be initialized once.
+ * An instance of `Regex` represents a compiled regular expression pattern.
+ * Since compilation is expensive, frequently used `Regex`es should be constructed
+ * once, outside of loops and perhaps in a companion object.
*
- * The canonical way of creating regex patterns is by using the method `r`, provided
- * on [[java.lang.String]] through an implicit conversion into
- * [[scala.collection.immutable.WrappedString]]. Using triple quotes to write these
- * strings avoids having to quote the backslash character (`\`).
+ * The canonical way to create a `Regex` is by using the method `r`, provided
+ * implicitly for strings:
*
- * Using the constructor directly, on the other hand, makes
- * it possible to declare names for subgroups in the pattern.
+ * {{{
+ * val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
+ * }}}
*
- * For example, both declarations below generate the same regex, but the second
- * one associate names with the subgroups.
+ * Since escapes are not processed in multi-line string literals, using triple quotes
+ * avoids having to escape the backslash character, so that `"\\d"` can be written `"""\d"""`.
+ *
+ * To extract the capturing groups when a `Regex` is matched, use it as
+ * an extractor in a pattern match:
*
* {{{
- * val dateP1 = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
- * val dateP2 = new scala.util.matching.Regex("""(\d\d\d\d)-(\d\d)-(\d\d)""", "year", "month", "day")
+ * "2004-01-20" match {
+ * case date(year, month, day) => s"$year was a good year for PLs."
+ * }
* }}}
*
- * There are two ways of using a `Regex` to find a pattern: calling methods on
- * Regex, such as `findFirstIn` or `findAllIn`, or using it as an extractor in a
- * pattern match.
+ * To check only whether the `Regex` matches, ignoring any groups,
+ * use a sequence wildcard:
+ *
+ * {{{
+ * "2004-01-20" match {
+ * case date(_*) => "It's a date!"
+ * }
+ * }}}
*
- * Note that, when calling `findAllIn`, the resulting [[scala.util.matching.Regex.MatchIterator]]
- * needs to be initialized (by calling `hasNext` or `next()`, or causing these to be
- * called) before information about a match can be retrieved:
+ * That works because a `Regex` extractor produces a sequence of strings.
+ * Extracting only the year from a date could also be expressed with
+ * a sequence wildcard:
*
* {{{
- * val msg = "I love Scala"
+ * "2004-01-20" match {
+ * case date(year, _*) => s"$year was a good year for PLs."
+ * }
+ * }}}
*
- * // val start = " ".r.findAllIn(msg).start // throws an IllegalStateException
+ * In a pattern match, `Regex` normally matches the entire input.
+ * However, an unanchored `Regex` finds the pattern anywhere
+ * in the input.
*
- * val matches = " ".r.findAllIn(msg)
- * matches.hasNext // initializes the matcher
- * val start = matches.start
+ * {{{
+ * val embeddedDate = date.unanchored
+ * "Date: 2004-01-20 17:25:18 GMT (10 years, 28 weeks, 5 days, 17 hours and 51 minutes ago)" match {
+ * case embeddedDate("2004", "01", "20") => "A Scala is born."
+ * }
* }}}
*
- * When Regex is used as an extractor in a pattern match, note that it
- * only succeeds if the whole text can be matched. For this reason, one usually
- * calls a method to find the matching substrings, and then use it as an extractor
- * to break match into subgroups.
+ * To find or replace matches of the pattern, use the various find and replace methods.
+ * There is a flavor of each method that produces matched strings and
+ * another that produces `Match` objects.
*
- * As an example, the above patterns can be used like this:
+ * For example, pattern matching with an unanchored `Regex`, as in the previous example,
+ * is the same as using `findFirstMatchIn`, except that the findFirst methods return an `Option`,
+ * or `None` for no match:
*
* {{{
- * val dateP1(year, month, day) = "2011-07-15"
+ * val dates = "Important dates in history: 2004-01-20, 1958-09-05, 2010-10-06, 2011-07-15"
+ * val firstDate = date findFirstIn dates getOrElse "No date found."
+ * val firstYear = for (m <- date findFirstMatchIn dates) yield m group 1
+ * }}}
*
- * // val dateP1(year, month, day) = "Date 2011-07-15" // throws an exception at runtime
+ * To find all matches:
*
- * val copyright: String = dateP1 findFirstIn "Date of this document: 2011-07-15" match {
- * case Some(dateP1(year, month, day)) => "Copyright "+year
- * case None => "No copyright"
- * }
+ * {{{
+ * val allYears = for (m <- date findAllMatchIn dates) yield m group 1
+ * }}}
*
- * val copyright: Option[String] = for {
- * dateP1(year, month, day) <- dateP1 findFirstIn "Last modified 2011-07-15"
- * } yield year
-
- * def getYears(text: String): Iterator[String] = for (dateP1(year, _, _) <- dateP1 findAllIn text) yield year
- * def getFirstDay(text: String): Option[String] = for (m <- dateP2 findFirstMatchIn text) yield m group "day"
+ * But `findAllIn` returns a special iterator of strings that can be queried for the `MatchData`
+ * of the last match:
+ *
+ * {{{
+ * val mi = date findAllIn dates
+ * val oldies = mi filter (_ => (mi group 1).toInt < 1960) map (s => s"$s: An oldie but goodie.")
* }}}
*
- * Regex does not provide a method that returns a [[scala.Boolean]]. One can
- * use [[java.lang.String]] `matches` method, or, if `Regex` is preferred,
- * either ignore the return value or test the `Option` for emptyness. For example:
+ * Note that `findAllIn` finds matches that don't overlap. (See [[findAllIn]] for more examples.)
*
* {{{
- * def hasDate(text: String): Boolean = (dateP1 findFirstIn text).nonEmpty
- * def printLinesWithDates(lines: Traversable[String]) {
- * lines foreach { line =>
- * dateP1 findFirstIn line foreach { _ => println(line) }
- * }
- * }
+ * val num = """(\d+)""".r
+ * val all = (num findAllIn "123").toList // List("123"), not List("123", "23", "3")
* }}}
*
- * There are also methods that can be used to replace the patterns
- * on a text. The substitutions can be simple replacements, or more
- * complex functions. For example:
+ * Text replacement can be performed unconditionally or as a function of the current match:
*
* {{{
- * val months = Map( 1 -> "Jan", 2 -> "Feb", 3 -> "Mar",
- * 4 -> "Apr", 5 -> "May", 6 -> "Jun",
- * 7 -> "Jul", 8 -> "Aug", 9 -> "Sep",
- * 10 -> "Oct", 11 -> "Nov", 12 -> "Dec")
- *
- * import scala.util.matching.Regex.Match
- * def reformatDate(text: String) = dateP2 replaceAllIn ( text, (m: Match) =>
- * "%s %s, %s" format (months(m group "month" toInt), m group "day", m group "year")
- * )
+ * 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" })
* }}}
*
- * You can use special pattern syntax constructs like `(?idmsux-idmsux)`¹ to switch
- * various regex compilation options like `CASE_INSENSITIVE` or `UNICODE_CASE`.
+ * Pattern matching the `Match` against the `Regex` that created it does not reapply the `Regex`.
+ * In the expression for `reformatted`, each `date` match is computed once. But it is possible to apply a
+ * `Regex` to a `Match` resulting from a different pattern:
+ *
+ * {{{
+ * val docSpree = """2011(?:-\d{2}){2}""".r
+ * val docView = date replaceAllIn (dates, _ match {
+ * case docSpree() => "Historic doc spree!"
+ * case _ => "Something else happened"
+ * })
+ * }}}
*
- * @note ¹ A detailed description is available in [[java.util.regex.Pattern]].
* @see [[java.util.regex.Pattern]]
*
* @author Thibaud Hottelier
@@ -154,9 +163,8 @@ import java.util.regex.{ Pattern, Matcher }
* 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
- * will be interpreted as an escape character, and can be used to escape the
- * dollar sign. One can use [[scala.util.matching.Regex]]'s `quoteReplacement`
- * to automatically escape these characters.
+ * will be interpreted as an escape character and can be used to escape the
+ * dollar sign. Use `Regex.quoteReplacement` to escape these characters.
*/
@SerialVersionUID(-2094783597747625537L)
class Regex private[matching](val pattern: Pattern, groupNames: String*) extends Serializable {
@@ -164,51 +172,84 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
import Regex._
- /**
- * @param regex A string representing a regular expression
- * @param groupNames A mapping from names to indices in capture groups
- */
+ /** Compile a regular expression, supplied as a string, into a pattern that
+ * can be matched against inputs.
+ *
+ * If group names are supplied, they can be used this way:
+ *
+ * {{{
+ * val namedDate = new Regex("""(\d\d\d\d)-(\d\d)-(\d\d)""", "year", "month", "day")
+ * val namedYears = for (m <- namedDate findAllMatchIn dates) yield m group "year"
+ * }}}
+ *
+ * This constructor does not support options as flags, which must be
+ * supplied as inline flags in the pattern string: `(?idmsux-idmsux)`.
+ *
+ * @param regex The regular expression to compile.
+ * @param groupNames Names of capturing groups.
+ */
def this(regex: String, groupNames: String*) = this(Pattern.compile(regex), groupNames: _*)
/** Tries to match a [[java.lang.CharSequence]].
+ *
* If the match succeeds, the result is a list of the matching
* groups (or a `null` element if a group did not match any input).
* If the pattern specifies no groups, then the result will be an empty list
* on a successful match.
*
* This method attempts to match the entire input by default; to find the next
- * matching subsequence, use an unanchored Regex.
-
+ * matching subsequence, use an unanchored `Regex`.
+ *
* For example:
*
* {{{
* val p1 = "ab*c".r
* val p1Matches = "abbbc" match {
- * case p1() => true
+ * case p1() => true // no groups
* case _ => false
* }
* val p2 = "a(b*)c".r
+ * val p2Matches = "abbbc" match {
+ * case p2(_*) => true // any groups
+ * case _ => false
+ * }
* val numberOfB = "abbbc" match {
- * case p2(b) => Some(b.length)
+ * case p2(b) => Some(b.length) // one group
* case _ => None
* }
* val p3 = "b*".r.unanchored
* val p3Matches = "abbbc" match {
- * case p3() => true
+ * case p3() => true // find the b's
* case _ => false
* }
+ * val p4 = "a(b*)(c+)".r
+ * val p4Matches = "abbbcc" match {
+ * case p4(_*) => true // multiple groups
+ * case _ => false
+ * }
+ * val allGroups = "abbbcc" match {
+ * case p4(all @ _*) => all mkString "/" // "bbb/cc"
+ * case _ => ""
+ * }
+ * val cGroup = "abbbcc" match {
+ * case p4(_, c) => c
+ * case _ => ""
+ * }
* }}}
*
* @param s The string to match
* @return The matches
*/
- def unapplySeq(s: CharSequence): Option[List[String]] = {
- val m = pattern matcher s
- if (runMatcher(m)) Some((1 to m.groupCount).toList map m.group)
- else None
+ def unapplySeq(s: CharSequence): Option[List[String]] = s match {
+ case null => None
+ case _ =>
+ val m = pattern matcher s
+ if (runMatcher(m)) Some((1 to m.groupCount).toList map m.group)
+ else None
}
/** Tries to match the String representation of a [[scala.Char]].
+ *
* If the match succeeds, the result is the first matching
* group if any groups are defined, or an empty Sequence otherwise.
*
@@ -247,13 +288,16 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
}
/** Tries to match on a [[scala.util.matching.Regex.Match]].
+ *
* A previously failed match results in None.
+ *
* If a successful match was made against the current pattern, then that result is used.
+ *
* Otherwise, this Regex is applied to the previously matched input,
* and the result of that match is used.
*/
def unapplySeq(m: Match): Option[List[String]] =
- if (m.matched == null) None
+ if (m == null || m.matched == null) None
else if (m.matcher.pattern == this.pattern) Some((1 to m.groupCount).toList map m.group)
else unapplySeq(m.matched)
@@ -274,30 +318,47 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
// @see UnanchoredRegex
protected def runMatcher(m: Matcher) = m.matches()
- /** Return all non-overlapping matches of this regexp in given character
+ /** Return all non-overlapping matches of this `Regex` in the given character
* sequence as a [[scala.util.matching.Regex.MatchIterator]],
* which is a special [[scala.collection.Iterator]] that returns the
- * matched strings, but can also be converted into a normal iterator
- * that returns objects of type [[scala.util.matching.Regex.Match]]
- * that can be queried for data such as the text that precedes the
- * match, subgroups, etc.
+ * matched strings but can also be queried for more data about the last match,
+ * such as capturing groups and start position.
+ *
+ * A `MatchIterator` can also be converted into an iterator
+ * that returns objects of type [[scala.util.matching.Regex.Match]],
+ * such as is normally returned by `findAllMatchIn`.
*
* Where potential matches overlap, the first possible match is returned,
- * followed by the next match that is completely after the first. For
- * instance, `"hat[^a]+".r` will match `hath` and `hattth` in the string
- * `"hathatthattthatttt"`.
+ * followed by the next match that follows the input consumed by the
+ * first match:
+ *
+ * {{{
+ * val hat = "hat[^a]+".r
+ * val hathaway = "hathatthattthatttt"
+ * val hats = (hat findAllIn hathaway).toList // List(hath, hattth)
+ * val pos = (hat findAllMatchIn hathaway map (_.start)).toList // List(0, 7)
+ * }}}
+ *
+ * To return overlapping matches, it is possible to formulate a regular expression
+ * with lookahead (`?=`) that does not consume the overlapping region.
+ *
+ * {{{
+ * val madhatter = "(h)(?=(at[^a]+))".r
+ * val madhats = (madhatter findAllMatchIn hathaway map {
+ * case madhatter(x,y) => s"$x$y"
+ * }).toList // List(hath, hatth, hattth, hatttt)
+ * }}}
*
- * Attempting to retrieve information about a match before initializing
- * the iterator can result in [[java.lang.IllegalStateException]]s. See
- * [[scala.util.matching.Regex.MatchIterator]] for details.
+ * Attempting to retrieve match information before performing the first match
+ * or after exhausting the iterator results in [[java.lang.IllegalStateException]].
+ * See [[scala.util.matching.Regex.MatchIterator]] for details.
*
* @param source The text to match against.
- * @return A [[scala.util.matching.Regex.MatchIterator]] of all matches.
+ * @return A [[scala.util.matching.Regex.MatchIterator]] of matched substrings.
* @example {{{for (words <- """\w+""".r findAllIn "A simple example.") yield words}}}
*/
def findAllIn(source: CharSequence) = new Regex.MatchIterator(source, this, groupNames)
-
/** Return all non-overlapping matches of this regexp in given character sequence as a
* [[scala.collection.Iterator]] of [[scala.util.matching.Regex.Match]].
*
@@ -316,8 +377,8 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
}
}
- /** Return optionally first matching string of this regexp in given character sequence,
- * or None if it does not exist.
+ /** Return an optional first matching string of this `Regex` in the given character sequence,
+ * or None if there is no match.
*
* @param source The text to match against.
* @return An [[scala.Option]] of the first matching string in the text.
@@ -328,13 +389,11 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
if (m.find) Some(m.group) else None
}
- /** Return optionally first match of this regexp in given character sequence,
+ /** Return an optional first match of this `Regex` in the given character sequence,
* or None if it does not exist.
*
- * The main difference between this method and `findFirstIn` is that the (optional) return
- * type for this is [[scala.util.matching.Regex.Match]], through which more
- * data can be obtained about the match, such as the strings that precede and follow it,
- * or subgroups.
+ * If the match is successful, the [[scala.util.matching.Regex.Match]] can be queried for
+ * more data.
*
* @param source The text to match against.
* @return A [[scala.Option]] of [[scala.util.matching.Regex.Match]] of the first matching string in the text.
@@ -345,30 +404,28 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
if (m.find) Some(new Match(source, m, groupNames)) else None
}
- /** Return optionally match of this regexp at the beginning of the
- * given character sequence, or None if regexp matches no prefix
+ /** Return an optional match of this `Regex` at the beginning of the
+ * given character sequence, or None if it matches no prefix
* of the character sequence.
*
- * The main difference from this method to `findFirstIn` is that this
- * method will not return any matches that do not begin at the start
- * of the text being matched against.
+ * Unlike `findFirstIn`, this method will only return a match at
+ * the beginning of the input.
*
* @param source The text to match against.
* @return A [[scala.Option]] of the matched prefix.
- * @example {{{"""[a-z]""".r findPrefixOf "A simple example." // returns None, since the text does not begin with a lowercase letter}}}
+ * @example {{{"""\p{Lower}""".r findPrefixOf "A simple example." // returns None, since the text does not begin with a lowercase letter}}}
*/
def findPrefixOf(source: CharSequence): Option[String] = {
val m = pattern.matcher(source)
if (m.lookingAt) Some(m.group) else None
}
- /** Return optionally match of this regexp at the beginning of the
- * given character sequence, or None if regexp matches no prefix
+ /** Return an optional match of this `Regex` at the beginning of the
+ * given character sequence, or None if it matches no prefix
* of the character sequence.
*
- * The main difference from this method to `findFirstMatchIn` is that
- * this method will not return any matches that do not begin at the
- * start of the text being matched against.
+ * Unlike `findFirstMatchIn`, this method will only return a match at
+ * the beginning of the input.
*
* @param source The text to match against.
* @return A [[scala.Option]] of the [[scala.util.matching.Regex.Match]] of the matched string.
@@ -402,7 +459,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 => m.group("month")+"/"+m.group("day"))
+ * val repl = datePattern replaceAllIn (text, m => s"${m group "month"}/${m group "day"}")
* }}}
*
* $replacementString
@@ -425,10 +482,10 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
* {{{
* import scala.util.matching.Regex._
*
- * val map = 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) => map get (m group 1) map (quoteReplacement(_))
+ * val mapper = (m: Match) => vars get (m group 1) map (quoteReplacement(_))
* val repl = varPattern replaceSomeIn (text, mapper)
* }}}
*
@@ -469,17 +526,25 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
pattern.split(toSplit)
/** Create a new Regex with the same pattern, but no requirement that
- * the entire String matches in extractor patterns. For instance, the strings
- * shown below lead to successful matches, where they would not otherwise.
+ * the entire String matches in extractor patterns.
+ *
+ * Normally, matching on `date` behaves as though the pattern were
+ * enclosed in anchors, `"^pattern$"`.
+ *
+ * The unanchored `Regex` behaves as though those anchors were removed.
+ *
+ * Note that this method does not actually strip any matchers from the pattern.
+ *
+ * Calling `anchored` returns the original `Regex`.
*
* {{{
- * val dateP1 = """(\d\d\d\d)-(\d\d)-(\d\d)""".r.unanchored
+ * val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r.unanchored
*
- * val dateP1(year, month, day) = "Date 2011-07-15"
+ * val date(year, month, day) = "Date 2011-07-15" // OK
*
* val copyright: String = "Date of this document: 2011-07-15" match {
- * case dateP1(year, month, day) => "Copyright "+year
- * case _ => "No copyright"
+ * case date(year, month, day) => s"Copyright $year" // OK
+ * case _ => "No copyright"
* }
* }}}
*
@@ -494,6 +559,10 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
override def toString = regex
}
+/** A [[Regex]] that finds the first match when used in a pattern match.
+ *
+ * @see [[Regex#unanchored]]
+ */
trait UnanchoredRegex extends Regex {
override protected def runMatcher(m: Matcher) = m.find()
override def unanchored = this
@@ -509,70 +578,79 @@ object Regex {
*/
trait MatchData {
- /** The source from where the match originated */
+ /** The source from which the match originated */
val source: CharSequence
- /** The names of the groups, or some empty sequence if one defined */
+ /** The names of the groups, or an empty sequence if none defined */
val groupNames: Seq[String]
- /** The number of subgroups in the pattern (not all of these need to match!) */
+ /** The number of capturing groups in the pattern.
+ * (For a given successful match, some of those groups may not have matched any input.)
+ */
def groupCount: Int
/** The index of the first matched character, or -1 if nothing was matched */
def start: Int
/** The index of the first matched character in group `i`,
- * or -1 if nothing was matched for that group */
+ * or -1 if nothing was matched for that group.
+ */
def start(i: Int): Int
- /** The index of the last matched character, or -1 if nothing was matched */
+ /** The index following the last matched character, or -1 if nothing was matched. */
def end: Int
/** The index following the last matched character in group `i`,
- * or -1 if nothing was matched for that group */
+ * or -1 if nothing was matched for that group.
+ */
def end(i: Int): Int
- /** The matched string, or `null` if nothing was matched */
+ /** The matched string, or `null` if nothing was matched. */
def matched: String =
if (start >= 0) source.subSequence(start, end).toString
else null
/** The matched string in group `i`,
- * or `null` if nothing was matched */
+ * or `null` if nothing was matched.
+ */
def group(i: Int): String =
if (start(i) >= 0) source.subSequence(start(i), end(i)).toString
else null
- /** All matched subgroups, i.e., not including group(0) */
+ /** All capturing groups, i.e., not including group(0). */
def subgroups: List[String] = (1 to groupCount).toList map group
/** The char sequence before first character of match,
- * or `null` if nothing was matched */
+ * or `null` if nothing was matched.
+ */
def before: CharSequence =
if (start >= 0) source.subSequence(0, start)
else null
/** The char sequence before first character of match in group `i`,
- * or `null` if nothing was matched for that group */
+ * or `null` if nothing was matched for that group.
+ */
def before(i: Int): CharSequence =
if (start(i) >= 0) source.subSequence(0, start(i))
else null
/** Returns char sequence after last character of match,
- * or `null` if nothing was matched */
+ * or `null` if nothing was matched.
+ */
def after: CharSequence =
if (end >= 0) source.subSequence(end, source.length)
else null
/** The char sequence after last character of match in group `i`,
- * or `null` if nothing was matched for that group */
+ * or `null` if nothing was matched for that group.
+ */
def after(i: Int): CharSequence =
if (end(i) >= 0) source.subSequence(end(i), source.length)
else null
private lazy val nameToIndex: Map[String, Int] = Map[String, Int]() ++ ("" :: groupNames.toList).zipWithIndex
- /** Returns the group with given name
+ /** Returns the group with given name.
*
* @param id The group name
* @return The requested group
@@ -583,24 +661,22 @@ object Regex {
case Some(index) => group(index)
}
- /** The matched string; equivalent to `matched.toString` */
+ /** The matched string; equivalent to `matched.toString`. */
override def toString = matched
-
}
- /** Provides information about a succesful match.
- */
+ /** Provides information about a successful match. */
class Match(val source: CharSequence,
private[matching] val matcher: Matcher,
val groupNames: Seq[String]) extends MatchData {
- /** The index of the first matched character */
+ /** The index of the first matched character. */
val start = matcher.start
- /** The index following the last matched character */
+ /** The index following the last matched character. */
val end = matcher.end
- /** The number of subgroups */
+ /** The number of subgroups. */
def groupCount = matcher.groupCount
private lazy val starts: Array[Int] =
@@ -608,19 +684,19 @@ object Regex {
private lazy val ends: Array[Int] =
((0 to groupCount) map matcher.end).toArray
- /** The index of the first matched character in group `i` */
+ /** The index of the first matched character in group `i`. */
def start(i: Int) = starts(i)
- /** The index following the last matched character in group `i` */
+ /** The index following the last matched character in group `i`. */
def end(i: Int) = ends(i)
/** The match itself with matcher-dependent lazy vals forced,
- * so that match is valid even once matcher is advanced
+ * so that match is valid even once matcher is advanced.
*/
def force: this.type = { starts; ends; this }
}
- /** An extractor object for Matches, yielding the matched string
+ /** An extractor object for Matches, yielding the matched string.
*
* This can be used to help writing replacer functions when you
* are not interested in match data. For example:
@@ -635,15 +711,15 @@ object Regex {
def unapply(m: Match): Some[String] = Some(m.matched)
}
- /** An extractor object that yields the groups in the match. Using an extractor
- * rather than the original regex avoids recomputing the match.
+ /** An extractor object that yields the groups in the match. Using this extractor
+ * rather than the original `Regex` ensures that the match is not recomputed.
*
* {{{
* import scala.util.matching.Regex.Groups
*
- * val datePattern = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
+ * val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
* val text = "The doc spree happened on 2011-07-15."
- * val day = datePattern replaceAllIn(text, _ match { case Groups(year, month, day) => month+"/"+day })
+ * val day = date replaceAllIn(text, _ match { case Groups(_, month, day) => s"$month/$day" })
* }}}
*/
object Groups {
@@ -672,7 +748,7 @@ object Regex {
nextSeen
}
- /** The next matched substring of `source` */
+ /** The next matched substring of `source`. */
def next(): String = {
if (!hasNext) throw new NoSuchElementException
nextSeen = false
@@ -681,28 +757,28 @@ object Regex {
override def toString = super[AbstractIterator].toString
- /** The index of the first matched character */
+ /** The index of the first matched character. */
def start: Int = matcher.start
- /** The index of the first matched character in group `i` */
+ /** The index of the first matched character in group `i`. */
def start(i: Int): Int = matcher.start(i)
- /** The index of the last matched character */
+ /** The index of the last matched character. */
def end: Int = matcher.end
- /** The index following the last matched character in group `i` */
+ /** The index following the last matched character in group `i`. */
def end(i: Int): Int = matcher.end(i)
- /** The number of subgroups */
+ /** The number of subgroups. */
def groupCount = matcher.groupCount
- /** Convert to an iterator that yields MatchData elements instead of Strings */
+ /** Convert to an iterator that yields MatchData elements instead of Strings. */
def matchData: Iterator[Match] = new AbstractIterator[Match] {
def hasNext = self.hasNext
def next = { self.next(); new Match(source, matcher, groupNames).force }
}
- /** Convert to an iterator that yields MatchData elements instead of Strings and has replacement support */
+ /** Convert to an iterator that yields MatchData elements instead of Strings and has replacement support. */
private[matching] def replacementData = new AbstractIterator[Match] with Replacement {
def matcher = self.matcher
def hasNext = self.hasNext
diff --git a/src/reflect/scala/reflect/api/Quasiquotes.scala b/src/reflect/scala/reflect/api/Quasiquotes.scala
index e905aa4153..eaae05bed5 100644
--- a/src/reflect/scala/reflect/api/Quasiquotes.scala
+++ b/src/reflect/scala/reflect/api/Quasiquotes.scala
@@ -13,7 +13,7 @@ trait Quasiquotes { self: Universe =>
protected trait api {
// implementation is hardwired to `dispatch` method of `scala.tools.reflect.quasiquotes.Quasiquotes`
// using the mechanism implemented in `scala.tools.reflect.FastTrack`
- def apply[T](args: T*): Tree = macro ???
+ def apply[A >: Any](args: A*): Tree = macro ???
def unapply(scrutinee: Any): Any = macro ???
}
object q extends api
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index bf560a21e5..02578e2038 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -836,12 +836,18 @@ trait Definitions extends api.StandardDefinitions {
def typeOfMemberNamedHead(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.head)())
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) = getterMemberTypes(tp, productSelectors(tp))
+ def typesOfSelectors(tp: Type) =
+ if (isTupleType(tp)) tp.typeArgs
+ 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)
// extractor to limit exposure to regressions like the reported problem with existentials.
// TODO fix the existential problem in the general case, see test/pending/pos/t8128.scala
private def typeArgOfBaseTypeOr(tp: Type, baseClass: Symbol)(or: => Type): Type = (tp baseType baseClass).typeArgs match {
- case x :: Nil => x
+ case x :: Nil =>
+ val x1 = x
+ val x2 = repackExistential(x1)
+ x2
case _ => or
}
diff --git a/src/reflect/scala/reflect/internal/Reporting.scala b/src/reflect/scala/reflect/internal/Reporting.scala
index 423127803e..f2de83bc5d 100644
--- a/src/reflect/scala/reflect/internal/Reporting.scala
+++ b/src/reflect/scala/reflect/internal/Reporting.scala
@@ -89,6 +89,9 @@ abstract class Reporter {
def count(severity: Severity): Int
def resetCount(severity: Severity): Unit
+ def errorCount: Int = count(ERROR)
+ def warningCount: Int = count(WARNING)
+
def hasErrors: Boolean = count(ERROR) > 0
def hasWarnings: Boolean = count(WARNING) > 0
diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
index ce0eadc04f..50c89f7442 100644
--- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
@@ -430,7 +430,14 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
import scala.concurrent.duration._
Await.ready(globalFuture, 60.seconds)
- (line ne null) && (command(line) match {
+ if (line eq null) {
+ // SI-4563: this means the console was properly interrupted (Ctrl+D usually)
+ // so we display the output message (which by default ends with
+ // a newline so as not to break the user's terminal)
+ if (in.interactive) out.print(Properties.shellInterruptedString)
+
+ false
+ } else (command(line) match {
case Result(false, _) => false
case Result(_, Some(line)) => addReplay(line) ; true
case _ => true
diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala
index 8ea8759ee5..6e30b73e0e 100644
--- a/src/repl/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala
@@ -1121,7 +1121,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
def apply(line: String): Result = debugging(s"""parse("$line")""") {
var isIncomplete = false
- currentRun.reporting.withIncompleteHandler((_, _) => isIncomplete = true) {
+ currentRun.parsing.withIncompleteHandler((_, _) => isIncomplete = true) {
reporter.reset()
val trees = newUnitParser(line).parseStats()
if (reporter.hasErrors) Error
diff --git a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala
index ccf18b76de..cbf8ff22ba 100644
--- a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala
@@ -208,7 +208,7 @@ abstract class ScaladocSyntaxAnalyzer[G <: Global](val global: G) extends Syntax
super.skipDocComment()
}
override def skipBlockComment(): Unit = {
- inDocComment = false
+ inDocComment = false // ??? this means docBuffer won't receive contents of this comment???
docBuffer = new StringBuilder("/*")
super.skipBlockComment()
}
@@ -217,9 +217,10 @@ abstract class ScaladocSyntaxAnalyzer[G <: Global](val global: G) extends Syntax
def foundStarComment(start: Int, end: Int) = try {
val str = docBuffer.toString
val pos = Position.range(unit.source, start, start, end)
- unit.comment(pos, str)
- if (inDocComment)
+ if (inDocComment) {
+ signalParsedDocComment(str, pos)
lastDoc = DocComment(str, pos)
+ }
true
} finally {
docBuffer = null
diff --git a/test/files/jvm/innerClassAttribute/Classes_1.scala b/test/files/jvm/innerClassAttribute/Classes_1.scala
new file mode 100644
index 0000000000..0875d9160c
--- /dev/null
+++ b/test/files/jvm/innerClassAttribute/Classes_1.scala
@@ -0,0 +1,99 @@
+class A1 {
+ class B
+}
+
+class A2 {
+ object B
+}
+
+object A3 {
+ class B1
+ object B2
+}
+
+class A4 {
+ def f(l: List[Int]): List[Int] = {
+ l map (_ + 1)
+ }
+}
+
+class A5 {
+ def f(): Object = {
+ object B
+ B
+ }
+}
+
+trait A6 {
+ def hui = -6
+ trait TT
+}
+
+class A7 extends A6
+
+abstract class A8 extends A6 {
+ def fish: TT
+}
+
+class A9 {
+ class brick extends annotation.StaticAnnotation
+}
+
+class A10 {
+ val a9 = new A9()
+ // there's no reference to brick in the bytecode (only in the pickle), so there's no InnerClass attribute for it.
+ @a9.brick def f = -7
+}
+
+class A11 {
+ @JavaAnnot_1.Ann def f = -8
+}
+
+object A12 {
+ object B {
+ class C
+ }
+}
+
+class A13 {
+ def oak: A12.B.C = new A12.B.C
+}
+
+class A14 {
+ def f = {
+ val x: Object = {
+ class K
+ new K
+ }
+ x
+ }
+ def g = {
+ val x: Object = new A6 { }
+ }
+}
+
+object A15 {
+ def f = {
+ class B { // static (does not have an outer pointer)
+ class C // non-static
+ }
+ }
+}
+
+class A16 {
+ val x: A6 = {
+ class U extends A6
+ new A6 { }
+ }
+
+ {
+ class V extends A6
+ new A6 { }
+ }
+}
+
+class A17 {
+ object B {
+ class C // not static, has an outer pointer.
+ }
+}
diff --git a/test/files/jvm/innerClassAttribute/JavaAnnot_1.java b/test/files/jvm/innerClassAttribute/JavaAnnot_1.java
new file mode 100644
index 0000000000..27c4d4e5d3
--- /dev/null
+++ b/test/files/jvm/innerClassAttribute/JavaAnnot_1.java
@@ -0,0 +1,3 @@
+public class JavaAnnot_1 {
+ public static @interface Ann {}
+}
diff --git a/test/files/jvm/innerClassAttribute/Test.scala b/test/files/jvm/innerClassAttribute/Test.scala
new file mode 100644
index 0000000000..6cf60ab92d
--- /dev/null
+++ b/test/files/jvm/innerClassAttribute/Test.scala
@@ -0,0 +1,208 @@
+import scala.tools.partest.BytecodeTest
+import scala.tools.asm
+import asm.tree.{ClassNode, InnerClassNode}
+import asm.{Opcodes => Flags}
+import scala.collection.JavaConverters._
+
+object Test extends BytecodeTest {
+ def assertSame(a: Any, b: Any) = {
+ assert(a == b, s"\na: $a\nb: $b")
+ }
+
+ val publicStatic = Flags.ACC_PUBLIC | Flags.ACC_STATIC
+ val publicAbstractInterface = Flags.ACC_PUBLIC | Flags.ACC_ABSTRACT | Flags.ACC_INTERFACE
+
+ def innerClassNodes(className: String): List[InnerClassNode] = {
+ loadClassNode(className).innerClasses.asScala.toList.sortBy(_.name)
+ }
+
+ final case class EnclosingMethod(name: String, descriptor: String, outerClass: String)
+ def enclosingMethod(className: String) = {
+ val n = loadClassNode(className)
+ EnclosingMethod(n.outerMethod, n.outerMethodDesc, n.outerClass)
+ }
+
+ def assertMember(node: InnerClassNode, outer: String, inner: String, name: Option[String] = None, flags: Int = Flags.ACC_PUBLIC) = {
+ assertSame(node.name, name.getOrElse(s"$outer$$$inner"))
+ assertSame(node.outerName, outer)
+ assertSame(node.innerName, inner)
+ assertSame(node.access, flags)
+ }
+
+ def assertAnonymous(node: InnerClassNode, name: String, flags: Int = Flags.ACC_PUBLIC | Flags.ACC_FINAL) = {
+ assertSame(node.name, name)
+ assertSame(node.outerName, null)
+ assertSame(node.innerName, null)
+ assertSame(node.access, flags)
+ }
+
+ def assertLocal(node: InnerClassNode, name: String, inner: String, flags: Int = Flags.ACC_PUBLIC) = {
+ assertSame(node.name, name)
+ assertSame(node.outerName, null)
+ assertSame(node.innerName, inner)
+ assertSame(node.access, flags)
+ }
+
+ def assertEnclosingMethod(enclosingMethod: EnclosingMethod, outerClass: String, name: String, descriptor: String) = {
+ assertSame(enclosingMethod.outerClass, outerClass)
+ assertSame(enclosingMethod.name, name)
+ assertSame(enclosingMethod.descriptor, descriptor)
+ }
+
+ def testA1() = {
+ val List(b1) = innerClassNodes("A1")
+ assertMember(b1, "A1", "B")
+ val List(b2) = innerClassNodes("A1$B")
+ assertMember(b2, "A1", "B")
+ }
+
+ def testA2() = {
+ val List(b1) = innerClassNodes("A2")
+ assertMember(b1, "A2", "B$")
+ val List(b2) = innerClassNodes("A2$B$")
+ assertMember(b2, "A2", "B$")
+ }
+
+ def testA3() = {
+ def t(c: String) = {
+ val List(b1, b2) = innerClassNodes(c)
+ // the outer class for classes nested inside top-level modules is not the module class, but the mirror class.
+ // this is a hack for java interop, handled in the backend. see BTypes.scala, comment on "Java Compatibility".
+ assertMember(b1, "A3", "B1", flags = publicStatic)
+ assertMember(b2, "A3", "B2$", flags = publicStatic)
+ }
+ t("A3$")
+ // the mirror class has the same inner class attributes as the module
+ // class (added when the mirror is created in the backend)
+ t("A3")
+ }
+
+ def testA4() = {
+ val List(an1) = innerClassNodes("A4")
+ assertAnonymous(an1, "A4$$anonfun$f$1")
+ val List(an2) = innerClassNodes("A4$$anonfun$f$1")
+ assertAnonymous(an2, "A4$$anonfun$f$1")
+ assertEnclosingMethod(
+ enclosingMethod("A4$$anonfun$f$1"),
+ "A4", "f", "(Lscala/collection/immutable/List;)Lscala/collection/immutable/List;")
+ }
+
+ def testA5() = {
+ val List(b1) = innerClassNodes("A5")
+ assertLocal(b1, "A5$B$2$", "B$2$")
+ val List(b2) = innerClassNodes("A5$B$2$")
+ assertLocal(b2, "A5$B$2$", "B$2$")
+ assertEnclosingMethod(
+ enclosingMethod("A5$B$2$"),
+ "A5", "f", "()Ljava/lang/Object;")
+ }
+
+ def testA6() = {
+ val List(tt1) = innerClassNodes("A6")
+ assertMember(tt1, "A6", "TT", flags = publicAbstractInterface)
+ val List() = innerClassNodes("A6$class")
+ val List(tt2) = innerClassNodes("A6$TT")
+ assertMember(tt2, "A6", "TT", flags = publicAbstractInterface)
+ }
+
+ def testA7() = {
+ val List() = innerClassNodes("A7")
+ }
+
+ def testA8() = {
+ val List(tt) = innerClassNodes("A8")
+ assertMember(tt, "A6", "TT", flags = publicAbstractInterface)
+ }
+
+ def testA10() = {
+ val List() = innerClassNodes("A10")
+ }
+
+ def testA11() = {
+ val List(ann) = innerClassNodes("A11")
+ // in the java class file, the INNERCLASS attribute has more flags (public | static | abstract | interface | annotation)
+ // the scala compiler has its own interpretation of java annotations ant their flags.. it only emits publicStatic.
+ assertMember(ann, "JavaAnnot_1", "Ann", flags = publicStatic)
+ }
+
+ def testA13() = {
+ val List(b, c) = innerClassNodes("A13")
+ assertMember(b, "A12", "B$", flags = publicStatic)
+ assertMember(c, "A12$B$", "C", name = Some("A12$B$C"), flags = publicStatic)
+ }
+
+ def testA14() = {
+ val List(anon, k) = innerClassNodes("A14")
+
+ assertLocal(k, "A14$K$1", "K$1")
+ assertEnclosingMethod(
+ enclosingMethod("A14$K$1"),
+ "A14", "f", "()Ljava/lang/Object;")
+
+ assertAnonymous(anon, "A14$$anon$1")
+ assertEnclosingMethod(
+ enclosingMethod("A14$$anon$1"),
+ "A14", "g", "()V")
+ }
+
+ def testA15() = {
+ val List(b) = innerClassNodes("A15")
+ assertLocal(b, "A15$B$3", "B$3", flags = publicStatic)
+
+ val List(_, c) = innerClassNodes("A15$B$3")
+ // TODO this is a bug in the backend, C should be a member. Instead, its outerClass is null
+ // assertMember(c, "A15$B$3", "C")
+ assertLocal(c, "A15$B$3$C", "C")
+ }
+
+ def testA16() = {
+ val List(anon1, anon2, u, v) = innerClassNodes("A16")
+ // TODO there's a bug in the backend: anon$2 has outerClass A16, but anonymous classes should have outerClass null
+ // assertAnonymous(anon1, "A16$$anon$2")
+ assertMember(anon1, "A16", null, name = Some("A16$$anon$2"), flags = Flags.ACC_PUBLIC | Flags.ACC_FINAL)
+ assertAnonymous(anon2, "A16$$anon$3")
+ // TODO this is a bug in the backend, U should not be a member, its outerClass should be null
+ // assertLocal(u, "A16$U$1", "U$1")
+ assertMember(u, "A16", "U$1")
+ assertLocal(v, "A16$V$1", "V$1")
+
+ assertEnclosingMethod(
+ enclosingMethod("A16$$anon$2"),
+ "A16", "<init>", "()V")
+ assertEnclosingMethod(
+ enclosingMethod("A16$$anon$3"),
+ "A16", "<init>", "()V")
+ // TODO this is a bug, there should be an enclosingMethod attribute in U
+ // assertEnclosingMethod(
+ // enclosingMethod("A16$U$1"),
+ // "A16", "<init>", "()V")
+ assertEnclosingMethod(
+ enclosingMethod("A16$V$1"),
+ "A16", "<init>", "()V")
+ }
+
+ def testA17() = {
+ val List(b, c) = innerClassNodes("A17$B$")
+ assertMember(b, "A17", "B$")
+ // TODO this is a bug, should not be static.
+ assertMember(c, "A17$B$", "C", name = Some("A17$B$C"), flags = publicStatic) // (should be) not static, has an outer pointer.
+ }
+
+ def show(): Unit = {
+ testA1()
+ testA2()
+ testA3()
+ testA4()
+ testA5()
+ testA6()
+ testA7()
+ testA8()
+ testA10()
+ testA11()
+ testA13()
+ testA14()
+ testA15()
+ testA16()
+ testA17()
+ }
+}
diff --git a/test/files/jvm/interpreter.check b/test/files/jvm/interpreter.check
index d124794e72..d03edb638c 100644
--- a/test/files/jvm/interpreter.check
+++ b/test/files/jvm/interpreter.check
@@ -361,7 +361,7 @@ It would fail on the following inputs: Exp(), Term()
^
f: (e: Exp)Int
-scala>
+scala> :quit
plusOne: (x: Int)Int
res0: Int = 6
res0: String = after reset
diff --git a/test/files/jvm/throws-annot-from-java.check b/test/files/jvm/throws-annot-from-java.check
index be3ba412f8..c541b26fcc 100644
--- a/test/files/jvm/throws-annot-from-java.check
+++ b/test/files/jvm/throws-annot-from-java.check
@@ -44,4 +44,4 @@ bar
tp.typeParams.isEmpty: true
throws[test.PolymorphicException[_]](classOf[test.PolymorphicException])
-scala>
+scala> :quit
diff --git a/test/files/jvm/xml05.check b/test/files/jvm/xml05.check
index 92ea995350..cad907525d 100644
--- a/test/files/jvm/xml05.check
+++ b/test/files/jvm/xml05.check
@@ -4,4 +4,4 @@ Type :help for more information.
scala> <city name="San Jos&eacute;"/>
res0: scala.xml.Elem = <city name="San Jos&eacute;"/>
-scala>
+scala> :quit
diff --git a/test/files/neg/macro-basic-mamdmi.check b/test/files/neg/macro-basic-mamdmi.check
index 61df5131cc..54743d4936 100644
--- a/test/files/neg/macro-basic-mamdmi.check
+++ b/test/files/neg/macro-basic-mamdmi.check
@@ -1,5 +1,13 @@
+Impls_Macros_Test_1.scala:33: error: macro implementation not found: foo
+(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
+ println(foo(2) + Macros.bar(2) * new Macros().quux(4))
+ ^
+Impls_Macros_Test_1.scala:33: error: macro implementation not found: bar
+(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
+ println(foo(2) + Macros.bar(2) * new Macros().quux(4))
+ ^
Impls_Macros_Test_1.scala:33: error: macro implementation not found: quux
(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
println(foo(2) + Macros.bar(2) * new Macros().quux(4))
^
-one error found
+three errors found
diff --git a/test/files/neg/t3909.check b/test/files/neg/t3909.check
index 7da0195607..052b49f855 100644
--- a/test/files/neg/t3909.check
+++ b/test/files/neg/t3909.check
@@ -1,4 +1,5 @@
t3909.scala:1: error: in object DO, multiple overloaded alternatives of m1 define default arguments
+Error occurred in an application involving default arguments.
object DO {
^
one error found
diff --git a/test/files/neg/t7848-interp-warn.flags b/test/files/neg/t7848-interp-warn.flags
index 7949c2afa2..b0d7bc25cb 100644
--- a/test/files/neg/t7848-interp-warn.flags
+++ b/test/files/neg/t7848-interp-warn.flags
@@ -1 +1 @@
--Xlint -Xfatal-warnings
+-Xlint:missing-interpolator -Xfatal-warnings
diff --git a/test/files/neg/t8266-invalid-interp.check b/test/files/neg/t8266-invalid-interp.check
index 70dd4081b0..bb2d44a80c 100644
--- a/test/files/neg/t8266-invalid-interp.check
+++ b/test/files/neg/t8266-invalid-interp.check
@@ -1,10 +1,10 @@
t8266-invalid-interp.scala:4: error: Trailing '\' escapes nothing.
f"a\",
^
-t8266-invalid-interp.scala:5: error: invalid escape character at index 1 in "a\xc"
+t8266-invalid-interp.scala:5: error: invalid escape '\x' not one of [\b, \t, \n, \f, \r, \\, \", \'] at index 1 in "a\xc". Use \\ for literal \.
f"a\xc",
^
-t8266-invalid-interp.scala:7: error: invalid escape character at index 1 in "a\vc"
+t8266-invalid-interp.scala:7: error: invalid escape '\v' not one of [\b, \t, \n, \f, \r, \\, \", \'] at index 1 in "a\vc". Use \\ for literal \.
f"a\vc"
^
three errors found
diff --git a/test/files/pos/t8013.flags b/test/files/pos/t8013.flags
index 954eaba352..3955bb6710 100644
--- a/test/files/pos/t8013.flags
+++ b/test/files/pos/t8013.flags
@@ -1 +1 @@
--Xfatal-warnings -Xlint
+-Xfatal-warnings -Xlint:-infer-any,_
diff --git a/test/files/pos/t8793.scala b/test/files/pos/t8793.scala
new file mode 100644
index 0000000000..1276155675
--- /dev/null
+++ b/test/files/pos/t8793.scala
@@ -0,0 +1,15 @@
+package regr
+
+trait F[A]
+
+class G(val a: F[_], val b: F[_])
+
+object G {
+ def unapply(g: G) = Option((g.a, g.b))
+}
+
+object H {
+ def unapply(g: G) = g match {
+ case G(a, _) => Option(a)
+ }
+}
diff --git a/test/files/run/class-symbol-contravariant.check b/test/files/run/class-symbol-contravariant.check
index 987f215bca..cbb90b52c2 100644
--- a/test/files/run/class-symbol-contravariant.check
+++ b/test/files/run/class-symbol-contravariant.check
@@ -33,4 +33,4 @@ res2: Boolean = true
scala> sym.isContravariant // was true
res3: Boolean = false
-scala>
+scala> :quit
diff --git a/test/files/run/constant-type.check b/test/files/run/constant-type.check
index 77bdf618e6..a7ba5a46c2 100644
--- a/test/files/run/constant-type.check
+++ b/test/files/run/constant-type.check
@@ -23,4 +23,4 @@ Class[String](classOf[java.lang.String])
scala> { ConstantType(Constant(s)); exitingPhase(currentRun.erasurePhase)(println(ConstantType(Constant(s)))); }
Class(classOf[java.lang.String])
-scala>
+scala> :quit
diff --git a/test/files/run/constrained-types.check b/test/files/run/constrained-types.check
index a3cd59b9fb..89a08d5ccb 100644
--- a/test/files/run/constrained-types.check
+++ b/test/files/run/constrained-types.check
@@ -148,4 +148,4 @@ scala> val x = 3 : Int @Annot(e+f+g+h) // should have a graceful error message
val x = 3 : Int @Annot(e+f+g+h) // should have a graceful error message
^
-scala>
+scala> :quit
diff --git a/test/files/run/kind-repl-command.check b/test/files/run/kind-repl-command.check
index 1c292572e6..586b2710e1 100644
--- a/test/files/run/kind-repl-command.check
+++ b/test/files/run/kind-repl-command.check
@@ -25,4 +25,4 @@ scala> :k Nonexisting
Nonexisting
^
-scala>
+scala> :quit
diff --git a/test/files/run/lub-visibility.check b/test/files/run/lub-visibility.check
index f76579412e..70734966f0 100644
--- a/test/files/run/lub-visibility.check
+++ b/test/files/run/lub-visibility.check
@@ -8,4 +8,4 @@ scala> // but reverted that for SI-5534.
scala> val x = List(List(), Vector())
x: List[scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing] with java.io.Serializable] = List(List(), Vector())
-scala>
+scala> :quit
diff --git a/test/files/run/macro-bundle-repl.check b/test/files/run/macro-bundle-repl.check
index 4a0b421606..75c5c2adda 100644
--- a/test/files/run/macro-bundle-repl.check
+++ b/test/files/run/macro-bundle-repl.check
@@ -21,4 +21,4 @@ defined term macro foo: Unit
scala> foo
-scala>
+scala> :quit
diff --git a/test/files/run/macro-repl-basic.check b/test/files/run/macro-repl-basic.check
index 86b4d472ed..fab03d1558 100644
--- a/test/files/run/macro-repl-basic.check
+++ b/test/files/run/macro-repl-basic.check
@@ -49,4 +49,4 @@ import Macros.Shmacros._
scala> println(foo(2) + Macros.bar(2) * new Macros().quux(4))
31
-scala>
+scala> :quit
diff --git a/test/files/run/macro-repl-dontexpand.check b/test/files/run/macro-repl-dontexpand.check
index 20d3b2d702..6ecc9245fa 100644
--- a/test/files/run/macro-repl-dontexpand.check
+++ b/test/files/run/macro-repl-dontexpand.check
@@ -13,4 +13,4 @@ bar2: (c: scala.reflect.macros.whitebox.Context)Nothing
scala> def foo2 = macro bar2
defined term macro foo2: Nothing
-scala>
+scala> :quit
diff --git a/test/files/run/macro-system-properties.check b/test/files/run/macro-system-properties.check
index ffbd5a8aa8..e2e2bd32b9 100644
--- a/test/files/run/macro-system-properties.check
+++ b/test/files/run/macro-system-properties.check
@@ -19,4 +19,4 @@ defined object Test
scala> object Test { class C(implicit a: Any) { GrabContext.grab } }
defined object Test
-scala>
+scala> :quit
diff --git a/test/files/run/reflection-equality.check b/test/files/run/reflection-equality.check
index 682326bc18..d60d861a90 100644
--- a/test/files/run/reflection-equality.check
+++ b/test/files/run/reflection-equality.check
@@ -48,4 +48,4 @@ res2: Boolean = true
scala> t2 <:< t1
res3: Boolean = true
-scala>
+scala> :quit
diff --git a/test/files/run/reflection-magicsymbols-repl.check b/test/files/run/reflection-magicsymbols-repl.check
index 72aef1d3be..ca8857ada4 100644
--- a/test/files/run/reflection-magicsymbols-repl.check
+++ b/test/files/run/reflection-magicsymbols-repl.check
@@ -34,4 +34,4 @@ scala.Null
scala.Nothing
scala.Singleton
-scala>
+scala> :quit
diff --git a/test/files/run/reflection-repl-classes.check b/test/files/run/reflection-repl-classes.check
index 03a6aef2b5..5ebf993a87 100644
--- a/test/files/run/reflection-repl-classes.check
+++ b/test/files/run/reflection-repl-classes.check
@@ -30,4 +30,4 @@ scala>
scala> mm(new A)
res0: Any = 1
-scala>
+scala> :quit
diff --git a/test/files/run/reflection-repl-elementary.check b/test/files/run/reflection-repl-elementary.check
index 4a223e8a24..e948c9fd61 100644
--- a/test/files/run/reflection-repl-elementary.check
+++ b/test/files/run/reflection-repl-elementary.check
@@ -4,4 +4,4 @@ Type :help for more information.
scala> scala.reflect.runtime.universe.typeOf[List[Nothing]]
res0: reflect.runtime.universe.Type = scala.List[Nothing]
-scala>
+scala> :quit
diff --git a/test/files/run/reify-repl-fail-gracefully.check b/test/files/run/reify-repl-fail-gracefully.check
index 29ccee3cc6..c9e69744d6 100644
--- a/test/files/run/reify-repl-fail-gracefully.check
+++ b/test/files/run/reify-repl-fail-gracefully.check
@@ -14,4 +14,4 @@ scala> reify
reify
^
-scala>
+scala> :quit
diff --git a/test/files/run/reify_newimpl_22.check b/test/files/run/reify_newimpl_22.check
index 1432d10127..952f384a1c 100644
--- a/test/files/run/reify_newimpl_22.check
+++ b/test/files/run/reify_newimpl_22.check
@@ -22,4 +22,4 @@ scala> {
^
2
-scala>
+scala> :quit
diff --git a/test/files/run/reify_newimpl_23.check b/test/files/run/reify_newimpl_23.check
index 217f0a98c7..b7e9bfdfbc 100644
--- a/test/files/run/reify_newimpl_23.check
+++ b/test/files/run/reify_newimpl_23.check
@@ -21,4 +21,4 @@ scala> def foo[T]{
^
foo: [T]=> Unit
-scala>
+scala> :quit
diff --git a/test/files/run/reify_newimpl_25.check b/test/files/run/reify_newimpl_25.check
index 93ad69defa..4f36ba10ee 100644
--- a/test/files/run/reify_newimpl_25.check
+++ b/test/files/run/reify_newimpl_25.check
@@ -12,4 +12,4 @@ scala> {
^
TypeTag[x.type]
-scala>
+scala> :quit
diff --git a/test/files/run/reify_newimpl_26.check b/test/files/run/reify_newimpl_26.check
index 8e0ad87bf2..681b862795 100644
--- a/test/files/run/reify_newimpl_26.check
+++ b/test/files/run/reify_newimpl_26.check
@@ -14,4 +14,4 @@ foo: [T]=> Unit
scala> foo[Int]
WeakTypeTag[scala.List[T]]
-scala>
+scala> :quit
diff --git a/test/files/run/reify_newimpl_35.check b/test/files/run/reify_newimpl_35.check
index f884d2c0d0..bd9b3a2fb1 100644
--- a/test/files/run/reify_newimpl_35.check
+++ b/test/files/run/reify_newimpl_35.check
@@ -10,4 +10,4 @@ foo: [T](implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtim
scala> println(foo)
Expr[List[Nothing]](Nil)
-scala>
+scala> :quit
diff --git a/test/files/run/repl-assign.check b/test/files/run/repl-assign.check
index bdc7793c37..faa8a93244 100644
--- a/test/files/run/repl-assign.check
+++ b/test/files/run/repl-assign.check
@@ -13,4 +13,4 @@ x: Int = 12
scala> y = 13
y: Int = 13
-scala>
+scala> :quit
diff --git a/test/files/run/repl-bare-expr.check b/test/files/run/repl-bare-expr.check
index 97ae208ff4..07cf23412f 100644
--- a/test/files/run/repl-bare-expr.check
+++ b/test/files/run/repl-bare-expr.check
@@ -47,4 +47,4 @@ Bovine.x: List[Any] = List(Ruminant(5), Cow, Moooooo)
scala> Bovine.x
res4: List[Any] = List(Ruminant(5), Cow, Moooooo)
-scala>
+scala> :quit
diff --git a/test/files/run/repl-colon-type.check b/test/files/run/repl-colon-type.check
index 1f6d3e2b39..9898027c1d 100644
--- a/test/files/run/repl-colon-type.check
+++ b/test/files/run/repl-colon-type.check
@@ -218,4 +218,4 @@ Unit
scala> :type println("side effect!")
Unit
-scala>
+scala> :quit
diff --git a/test/files/run/repl-empty-package.check b/test/files/run/repl-empty-package.check
index ecf79c2c6d..d3b75f685e 100644
--- a/test/files/run/repl-empty-package.check
+++ b/test/files/run/repl-empty-package.check
@@ -4,4 +4,4 @@ Type :help for more information.
scala> println(Bippy.bippy)
bippy!
-scala>
+scala> :quit
diff --git a/test/files/run/repl-javap-app.check b/test/files/run/repl-javap-app.check
index 1136b415d7..eb3718f44b 100644
--- a/test/files/run/repl-javap-app.check
+++ b/test/files/run/repl-javap-app.check
@@ -15,7 +15,7 @@ public final void delayedEndpoint$MyApp$1();
Start Length Slot Name Signature
0 9 0 this LMyApp$;
-scala>
+scala> :quit
#partest java7
Welcome to Scala
Type in expressions to have them evaluated.
@@ -37,7 +37,7 @@ scala> :javap -app MyApp$
line 5: 0
}
-scala>
+scala> :quit
#partest java8
Welcome to Scala
Type in expressions to have them evaluated.
@@ -60,4 +60,4 @@ scala> :javap -app MyApp$
line 5: 0
}
-scala>
+scala> :quit
diff --git a/test/files/run/repl-out-dir.check b/test/files/run/repl-out-dir.check
index 3e51c63155..c354492898 100644
--- a/test/files/run/repl-out-dir.check
+++ b/test/files/run/repl-out-dir.check
@@ -46,4 +46,4 @@ repl-out-dir-run.obj
Test$.class
Test.class
-scala>
+scala> :quit
diff --git a/test/files/run/repl-parens.check b/test/files/run/repl-parens.check
index 15f4b4524a..74d15ff93c 100644
--- a/test/files/run/repl-parens.check
+++ b/test/files/run/repl-parens.check
@@ -81,4 +81,4 @@ scala>
scala> List(1) ++ List('a')
res16: List[AnyVal] = List(1, a)
-scala>
+scala> :quit
diff --git a/test/files/run/repl-paste-2.check b/test/files/run/repl-paste-2.check
index ab3809a2e0..6ea8e2f419 100644
--- a/test/files/run/repl-paste-2.check
+++ b/test/files/run/repl-paste-2.check
@@ -58,4 +58,4 @@ scala> x.length + res5
res3: Int = 129
-scala>
+scala> :quit
diff --git a/test/files/run/repl-paste-3.check b/test/files/run/repl-paste-3.check
index 8fae61792e..23e402852f 100644
--- a/test/files/run/repl-paste-3.check
+++ b/test/files/run/repl-paste-3.check
@@ -7,4 +7,4 @@ scala> println(3)
scala> List(1,2)
res1: List[Int] = List(1, 2)
-scala>
+scala> :quit
diff --git a/test/files/run/repl-paste-4.scala b/test/files/run/repl-paste-4.scala
index 0060dc1ff6..cb0a6aa768 100644
--- a/test/files/run/repl-paste-4.scala
+++ b/test/files/run/repl-paste-4.scala
@@ -14,7 +14,7 @@ s"""|Type in expressions to have them evaluated.
|scala> Foo(new Foo)
|res0: Int = 7
|
- |scala> """
+ |scala> :quit"""
def pastie = testPath changeExtension "pastie"
}
diff --git a/test/files/run/repl-paste-raw.scala b/test/files/run/repl-paste-raw.scala
index 2953796f99..3b41254e96 100644
--- a/test/files/run/repl-paste-raw.scala
+++ b/test/files/run/repl-paste-raw.scala
@@ -15,6 +15,6 @@ s"""|Type in expressions to have them evaluated.
|scala> favoriteThing.hasString
|res0: Boolean = true
|
- |scala> """
+ |scala> :quit"""
def pastie = testPath changeExtension "pastie"
}
diff --git a/test/files/run/repl-paste.check b/test/files/run/repl-paste.check
index 97f177ddc4..171447214f 100644
--- a/test/files/run/repl-paste.check
+++ b/test/files/run/repl-paste.check
@@ -23,4 +23,4 @@ defined class Dingus
defined object Dingus
x: Int = 110
-scala>
+scala> :quit
diff --git a/test/files/run/repl-power.check b/test/files/run/repl-power.check
index 8a8ca46012..e2318c93f2 100644
--- a/test/files/run/repl-power.check
+++ b/test/files/run/repl-power.check
@@ -27,4 +27,4 @@ m: $r.treedsl.global.Literal = 10
scala> typed(m).tpe // typed is in scope
res2: $r.treedsl.global.Type = Int(10)
-scala>
+scala> :quit
diff --git a/test/files/run/repl-reset.check b/test/files/run/repl-reset.check
index ed95c7b8ff..cd7893bbc3 100644
--- a/test/files/run/repl-reset.check
+++ b/test/files/run/repl-reset.check
@@ -54,4 +54,4 @@ defined class BippyBungus
scala> { new BippyBungus ; x1 }
res2: Int = 4
-scala>
+scala> :quit
diff --git a/test/files/run/repl-save.scala b/test/files/run/repl-save.scala
index 4539790b1a..c98e6aebc3 100644
--- a/test/files/run/repl-save.scala
+++ b/test/files/run/repl-save.scala
@@ -16,7 +16,7 @@ s"""|Type in expressions to have them evaluated.
|
|scala> :save $saveto
|
- |scala> """
+ |scala> :quit"""
def saveto = testOutput / "session.repl"
override def show() = {
super.show()
diff --git a/test/files/run/repl-term-macros.check b/test/files/run/repl-term-macros.check
index 3580bfe1f1..2cd0b93cd0 100644
--- a/test/files/run/repl-term-macros.check
+++ b/test/files/run/repl-term-macros.check
@@ -37,4 +37,4 @@ defined term macro foo3: (x: Int)(y: Int)Unit
scala> foo3(2)(3)
-scala>
+scala> :quit
diff --git a/test/files/run/repl-transcript.check b/test/files/run/repl-transcript.check
index 49891af900..b0f106387b 100644
--- a/test/files/run/repl-transcript.check
+++ b/test/files/run/repl-transcript.check
@@ -35,4 +35,4 @@ scala> res6.sum + res5
res0: Int = 5273
-scala>
+scala> :quit
diff --git a/test/files/run/repl-trim-stack-trace.scala b/test/files/run/repl-trim-stack-trace.scala
index 483659146a..a53ce3b3e4 100644
--- a/test/files/run/repl-trim-stack-trace.scala
+++ b/test/files/run/repl-trim-stack-trace.scala
@@ -32,7 +32,7 @@ java.lang.Exception
at .f(<console>:7)
... 69 elided
-scala> """
+scala> :quit"""
// normalize the "elided" lines because the frame count depends on test context
lazy val elided = """(\s+\.{3} )\d+( elided)""".r
diff --git a/test/files/run/repl-type-verbose.check b/test/files/run/repl-type-verbose.check
index e37754a060..6f6b47b86d 100644
--- a/test/files/run/repl-type-verbose.check
+++ b/test/files/run/repl-type-verbose.check
@@ -187,4 +187,4 @@ PolyType(
)
)
-scala>
+scala> :quit
diff --git a/test/files/run/t3376.check b/test/files/run/t3376.check
index cc6949d326..b8fd2843f6 100644
--- a/test/files/run/t3376.check
+++ b/test/files/run/t3376.check
@@ -13,4 +13,4 @@ m2: M[Float] = mmm
scala> val m3 = new M[String]()
m3: M[String] = mmm
-scala>
+scala> :quit
diff --git a/test/files/run/t4025.check b/test/files/run/t4025.check
index 2d4f644c5a..e8c6851236 100644
--- a/test/files/run/t4025.check
+++ b/test/files/run/t4025.check
@@ -14,4 +14,4 @@ scala>
scala> def f(c: Any) = c match { case Red(_) => () }
f: (c: Any)Unit
-scala>
+scala> :quit
diff --git a/test/files/run/t4172.check b/test/files/run/t4172.check
index a748430e2e..315c1c9dbd 100644
--- a/test/files/run/t4172.check
+++ b/test/files/run/t4172.check
@@ -5,4 +5,4 @@ scala> val c = { class C { override def toString = "C" }; ((new C, new C { def f
warning: there was one feature warning; re-run with -feature for details
c: (C, C{def f: Int}) forSome { type C <: AnyRef } = (C,C)
-scala>
+scala> :quit
diff --git a/test/files/run/t4216.check b/test/files/run/t4216.check
index 091e55a0c7..e4610e87d3 100644
--- a/test/files/run/t4216.check
+++ b/test/files/run/t4216.check
@@ -34,4 +34,4 @@ res4: java.util.List[V] = [V@0]
scala> o(new V(0))
res5: java.util.List[Any] = [V@0]
-scala>
+scala> :quit
diff --git a/test/files/run/t4285.check b/test/files/run/t4285.check
index 314c8e5a35..b952cb8e1b 100644
--- a/test/files/run/t4285.check
+++ b/test/files/run/t4285.check
@@ -10,4 +10,4 @@ y: scala.collection.mutable.WrappedArray[Int] = WrappedArray(2, 4, 6, 8, 10, 12,
scala> println(y.sum)
56
-scala>
+scala> :quit
diff --git a/test/files/run/t4542.check b/test/files/run/t4542.check
index a53f31a3c7..f7716dc2f0 100644
--- a/test/files/run/t4542.check
+++ b/test/files/run/t4542.check
@@ -12,4 +12,4 @@ scala> val f = new Foo
^
f: Foo = Bippy
-scala>
+scala> :quit
diff --git a/test/files/run/t4594-repl-settings.scala b/test/files/run/t4594-repl-settings.scala
index 8b8b2e3746..4202991607 100644
--- a/test/files/run/t4594-repl-settings.scala
+++ b/test/files/run/t4594-repl-settings.scala
@@ -22,5 +22,5 @@ object Test extends SessionTest {
| ^
|b: String
|
- |scala> """
+ |scala> :quit"""
}
diff --git a/test/files/run/t4671.check b/test/files/run/t4671.check
index 0c36083759..1640dac8e4 100644
--- a/test/files/run/t4671.check
+++ b/test/files/run/t4671.check
@@ -43,4 +43,4 @@ println(s.mkString(""))
}
-scala>
+scala> :quit
diff --git a/test/files/run/t4710.check b/test/files/run/t4710.check
index 6ee7198b4b..0dd49dfbd3 100644
--- a/test/files/run/t4710.check
+++ b/test/files/run/t4710.check
@@ -5,4 +5,4 @@ scala> def method : String = { implicit def f(s: Symbol) = "" ; 'symbol }
warning: there was one feature warning; re-run with -feature for details
method: String
-scala>
+scala> :quit
diff --git a/test/files/run/t5072.check b/test/files/run/t5072.check
index ddd49c71cb..ab34e49869 100644
--- a/test/files/run/t5072.check
+++ b/test/files/run/t5072.check
@@ -7,4 +7,4 @@ defined class C
scala> Thread.currentThread.getContextClassLoader.loadClass(classOf[C].getName)
res0: Class[_] = class C
-scala>
+scala> :quit
diff --git a/test/files/run/t5256d.check b/test/files/run/t5256d.check
index d42d234386..c2b49989ab 100644
--- a/test/files/run/t5256d.check
+++ b/test/files/run/t5256d.check
@@ -25,4 +25,4 @@ scala.AnyRef {
def foo: scala.Nothing
}
-scala>
+scala> :quit
diff --git a/test/files/run/t5535.check b/test/files/run/t5535.check
index a0c87a47f4..84097ccea9 100644
--- a/test/files/run/t5535.check
+++ b/test/files/run/t5535.check
@@ -13,4 +13,4 @@ f: Int => Int = <function1>
scala> println(f(10))
11
-scala>
+scala> :quit
diff --git a/test/files/run/t5537.check b/test/files/run/t5537.check
index b9d521f301..98265ccc92 100644
--- a/test/files/run/t5537.check
+++ b/test/files/run/t5537.check
@@ -13,4 +13,4 @@ res2: List[scala.collection.immutable.List.type] = List()
scala> List[Set.type]()
res3: List[Set.type] = List()
-scala>
+scala> :quit
diff --git a/test/files/run/t5583.check b/test/files/run/t5583.check
index af96405bdd..32d285cbb3 100644
--- a/test/files/run/t5583.check
+++ b/test/files/run/t5583.check
@@ -13,4 +13,4 @@ scala> for (i <- 1 to 10) {s += i}
scala> println(s)
165
-scala>
+scala> :quit
diff --git a/test/files/run/t5655.check b/test/files/run/t5655.check
index 06c6b32599..4bbc54b641 100644
--- a/test/files/run/t5655.check
+++ b/test/files/run/t5655.check
@@ -23,4 +23,4 @@ and import x
x
^
-scala>
+scala> :quit
diff --git a/test/files/run/t5789.check b/test/files/run/t5789.check
index bcb2382559..193abfaff0 100644
--- a/test/files/run/t5789.check
+++ b/test/files/run/t5789.check
@@ -7,4 +7,4 @@ n: Int = 2
scala> () => n
res0: () => Int = <function0>
-scala>
+scala> :quit
diff --git a/test/files/run/t6086-repl.check b/test/files/run/t6086-repl.check
index 115eff5f85..b904f118e8 100644
--- a/test/files/run/t6086-repl.check
+++ b/test/files/run/t6086-repl.check
@@ -7,4 +7,4 @@ defined class X
scala> scala.reflect.runtime.universe.typeOf[X]
res0: reflect.runtime.universe.Type = X
-scala>
+scala> :quit
diff --git a/test/files/run/t6146b.check b/test/files/run/t6146b.check
index a3b09efcd9..6998873fb7 100644
--- a/test/files/run/t6146b.check
+++ b/test/files/run/t6146b.check
@@ -60,4 +60,4 @@ res2: u.Type = O.S3
scala> memType(S4, fTpe)
res3: u.Type = S4
-scala>
+scala> :quit
diff --git a/test/files/run/t6187.check b/test/files/run/t6187.check
index 0180125809..9a9e266ec6 100644
--- a/test/files/run/t6187.check
+++ b/test/files/run/t6187.check
@@ -29,4 +29,4 @@ res1: List[Int] = List(1)
scala> List("") collect { case x => x }
res2: List[String] = List("")
-scala>
+scala> :quit
diff --git a/test/files/run/t6273.check b/test/files/run/t6273.check
index bef0b227d2..3b682800df 100644
--- a/test/files/run/t6273.check
+++ b/test/files/run/t6273.check
@@ -12,4 +12,4 @@ x: String =
y = 55
"
-scala>
+scala> :quit
diff --git a/test/files/run/t6320.check b/test/files/run/t6320.check
index 013acc1c54..af7c865690 100644
--- a/test/files/run/t6320.check
+++ b/test/files/run/t6320.check
@@ -10,4 +10,4 @@ defined class Dyn
scala> new Dyn(Map("foo" -> 10)).foo[Int]
res0: Int = 10
-scala>
+scala> :quit
diff --git a/test/files/run/t6329_repl.check b/test/files/run/t6329_repl.check
index ad0bb46e5b..ebb1aace7c 100644
--- a/test/files/run/t6329_repl.check
+++ b/test/files/run/t6329_repl.check
@@ -32,4 +32,4 @@ res6: scala.reflect.ClassTag[scala.collection.immutable.Set[_]] = scala.collecti
scala> classTag[scala.collection.immutable.Set[_]]
res7: scala.reflect.ClassTag[scala.collection.immutable.Set[_]] = scala.collection.immutable.Set
-scala>
+scala> :quit
diff --git a/test/files/run/t6329_repl_bug.check b/test/files/run/t6329_repl_bug.check
index 38a8de5606..84297a629f 100644
--- a/test/files/run/t6329_repl_bug.check
+++ b/test/files/run/t6329_repl_bug.check
@@ -14,4 +14,4 @@ res0: scala.reflect.ClassTag[List[_]] = scala.collection.immutable.List[<?>]
scala> scala.reflect.classTag[List[_]]
res1: scala.reflect.ClassTag[List[_]] = scala.collection.immutable.List
-scala>
+scala> :quit
diff --git a/test/files/run/t6381.check b/test/files/run/t6381.check
index 4ed11d59ff..49c6a784ad 100644
--- a/test/files/run/t6381.check
+++ b/test/files/run/t6381.check
@@ -16,4 +16,4 @@ defined term macro pos: String
scala> pos
res0: String = class scala.reflect.internal.util.RangePosition
-scala>
+scala> :quit
diff --git a/test/files/run/t6434.check b/test/files/run/t6434.check
index f898b6b781..0a75ae2bd5 100644
--- a/test/files/run/t6434.check
+++ b/test/files/run/t6434.check
@@ -7,4 +7,4 @@ f: (x: => Int)Int
scala> f _
res0: (=> Int) => Int = <function1>
-scala>
+scala> :quit
diff --git a/test/files/run/t6439.check b/test/files/run/t6439.check
index f8d5b3a8cd..c4b7591069 100644
--- a/test/files/run/t6439.check
+++ b/test/files/run/t6439.check
@@ -70,4 +70,4 @@ defined object lookup
scala> lookup("F") // this now works as a result of changing .typeSymbol to .typeSymbolDirect in IMain#Request#definedSymbols
res0: $r.intp.global.Symbol = type F
-scala>
+scala> :quit
diff --git a/test/files/run/t6507.check b/test/files/run/t6507.check
index 3536c42381..5da4aa3a24 100644
--- a/test/files/run/t6507.check
+++ b/test/files/run/t6507.check
@@ -21,4 +21,4 @@ scala> res0
!
res1: A = A
-scala>
+scala> :quit
diff --git a/test/files/run/t6549.check b/test/files/run/t6549.check
index d5dfc5ebe8..be3445927e 100644
--- a/test/files/run/t6549.check
+++ b/test/files/run/t6549.check
@@ -25,4 +25,4 @@ m(scala.Symbol("s")).xxx: Any = 's
scala> val `"` = 0
": Int = 0
-scala>
+scala> :quit
diff --git a/test/files/run/t6631.scala b/test/files/run/t6631.scala
deleted file mode 100644
index e472b83d50..0000000000
--- a/test/files/run/t6631.scala
+++ /dev/null
@@ -1,18 +0,0 @@
-import reflect.ClassTag
-
-object Test extends App {
- def intercept[T <: Throwable : ClassTag](act: => Any) = try {
- act
- } catch {
- case x: Throwable =>
- val cls = implicitly[ClassTag[T]].runtimeClass
- assert(cls.isInstance(x), (x.getClass, x, cls).toString)
- }
- assert(s"""\f\r\n\t""" == "\f\r\n\t")
-
- import StringContext.InvalidEscapeException
- intercept[InvalidEscapeException](s"""\""")
- intercept[InvalidEscapeException](s"""\x""")
- intercept[InvalidEscapeException](s"\")
-
-}
diff --git a/test/files/run/t6937.check b/test/files/run/t6937.check
index 4729dc7006..5c5d4485b6 100644
--- a/test/files/run/t6937.check
+++ b/test/files/run/t6937.check
@@ -19,4 +19,4 @@ apiru: scala.reflect.api.Universe = <lazy>
scala> apiru.typeTag[A].in(cm)
res0: reflect.runtime.universe.TypeTag[A] = TypeTag[A]
-scala>
+scala> :quit
diff --git a/test/files/run/t7185.check b/test/files/run/t7185.check
index ebf85b731f..e4f80a8ff9 100644
--- a/test/files/run/t7185.check
+++ b/test/files/run/t7185.check
@@ -29,4 +29,4 @@ res0: Any =
}
}
-scala>
+scala> :quit
diff --git a/test/files/run/t7319.check b/test/files/run/t7319.check
index 2ac4142098..e35cfc90c0 100644
--- a/test/files/run/t7319.check
+++ b/test/files/run/t7319.check
@@ -40,4 +40,4 @@ scala> Range(1,2).toArray: Seq[_]
scala> 0
res2: Int = 0
-scala>
+scala> :quit
diff --git a/test/files/run/t7482a.check b/test/files/run/t7482a.check
index 943538f352..a21ef7b68f 100644
--- a/test/files/run/t7482a.check
+++ b/test/files/run/t7482a.check
@@ -7,4 +7,4 @@ v: java.util.ArrayList[String] = []
scala> val v: java.util.ArrayList[String] = new java.util.ArrayList[String](5)
v: java.util.ArrayList[String] = []
-scala>
+scala> :quit
diff --git a/test/files/run/t7634.check b/test/files/run/t7634.check
index aea3b94da5..9c6b8b47dd 100644
--- a/test/files/run/t7634.check
+++ b/test/files/run/t7634.check
@@ -5,4 +5,4 @@ Type :help for more information.
scala> .lines
res1: List[String] = List(shello, world.)
-scala>
+scala> :quit
diff --git a/test/files/run/t7747-repl.check b/test/files/run/t7747-repl.check
index ad924f482c..105b238d01 100644
--- a/test/files/run/t7747-repl.check
+++ b/test/files/run/t7747-repl.check
@@ -283,4 +283,4 @@ object $read extends $read {
}
res3: List[Product with Serializable] = List(BippyBups(), PuppyPups(), Bingo())
-scala>
+scala> :quit
diff --git a/test/files/run/t7801.check b/test/files/run/t7801.check
index d72060c684..e0b656b784 100644
--- a/test/files/run/t7801.check
+++ b/test/files/run/t7801.check
@@ -8,4 +8,4 @@ import g.abort
scala> class C(val a: Any) extends AnyVal
defined class C
-scala>
+scala> :quit
diff --git a/test/files/run/t7805-repl-i.check b/test/files/run/t7805-repl-i.check
index eecfff079a..7f66c06a11 100644
--- a/test/files/run/t7805-repl-i.check
+++ b/test/files/run/t7805-repl-i.check
@@ -8,4 +8,4 @@ Type :help for more information.
scala> Console println Try(8)
Success(8)
-scala>
+scala> :quit
diff --git a/test/files/run/tpeCache-tyconCache.check b/test/files/run/tpeCache-tyconCache.check
index a892f5477a..ff604819e0 100644
--- a/test/files/run/tpeCache-tyconCache.check
+++ b/test/files/run/tpeCache-tyconCache.check
@@ -16,4 +16,4 @@ res0: Boolean = true
scala> AnyRefClass.tpe eq AnyRefClass.typeConstructor
res1: Boolean = true
-scala>
+scala> :quit
diff --git a/test/junit/scala/StringContextTest.scala b/test/junit/scala/StringContextTest.scala
index 5abfe90cd1..608b82bd96 100644
--- a/test/junit/scala/StringContextTest.scala
+++ b/test/junit/scala/StringContextTest.scala
@@ -48,4 +48,31 @@ class StringContextTest {
val res = processEscapes(s)
assertEquals("Scala", res)
}
+
+ @Test def t6631_baseline() = assertEquals("\f\r\n\t", s"""\f\r\n\t""")
+
+ @Test def t6631_badEscape() = assertThrows[InvalidEscapeException] {
+ s"""\x"""
+ }
+
+ // verifying that the standard interpolators can be supplanted
+ @Test def antiHijack_?() = {
+ object AllYourStringsAreBelongToMe { case class StringContext(args: Any*) { def s(args: Any) = "!!!!" } }
+ import AllYourStringsAreBelongToMe._
+ //assertEquals("????", s"????")
+ assertEquals("!!!!", s"????") // OK to hijack core interpolator ids
+ }
+
+ @Test def fIf() = {
+ val res = f"${if (true) 2.5 else 2.5}%.2f"
+ assertEquals("2.50", res)
+ }
+ @Test def fIfNot() = {
+ val res = f"${if (false) 2.5 else 3.5}%.2f"
+ assertEquals("3.50", res)
+ }
+ @Test def fHeteroArgs() = {
+ val res = f"${3.14}%.2f rounds to ${3}%d"
+ assertEquals("3.14 rounds to 3", res)
+ }
}
diff --git a/test/junit/scala/reflect/QTest.scala b/test/junit/scala/reflect/QTest.scala
new file mode 100644
index 0000000000..24c35dc401
--- /dev/null
+++ b/test/junit/scala/reflect/QTest.scala
@@ -0,0 +1,23 @@
+
+package scala.reflect
+
+import org.junit.Test
+import org.junit.Assert._
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.tools.testing.AssertUtil._
+
+@RunWith(classOf[JUnit4])
+class QTest {
+
+ import reflect.runtime._
+ import universe._
+ @Test def qConstantsNotHomogenized() = {
+ //Apply(Select(Literal(Constant(1.0)), TermName("$plus")), List(Literal(Constant(1.0))))
+ val t = q"${1} + ${1.0}"
+ val Apply(Select(Literal(Constant(i)), TermName("$plus")), List(Literal(Constant(j)))) = t
+ assertEquals(1, i)
+ assertEquals(1.0, j)
+ }
+}
diff --git a/test/junit/scala/util/matching/RegexTest.scala b/test/junit/scala/util/matching/RegexTest.scala
index d25842cc57..5b13397d6a 100644
--- a/test/junit/scala/util/matching/RegexTest.scala
+++ b/test/junit/scala/util/matching/RegexTest.scala
@@ -27,4 +27,21 @@ class RegexTest {
assertEquals("1", x)
assertEquals("1", y)
}
+
+ @Test def t8787nullMatch() = {
+ val r = """\d+""".r
+ val s: String = null
+ val x = s match { case r() => 1 ; case _ => 2 }
+ assertEquals(2, x)
+ }
+
+ @Test def t8787nullMatcher() = {
+ val r = """(\d+):(\d+)""".r
+ val s = "1:2 3:4 5:6"
+ val z = ((r findAllMatchIn s).toList :+ null) flatMap {
+ case r(x, y) => Some((x.toInt, y.toInt))
+ case _ => None
+ }
+ assertEquals(List((1,2),(3,4),(5,6)), z)
+ }
}