aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2017-03-31 17:46:38 +0200
committerGitHub <noreply@github.com>2017-03-31 17:46:38 +0200
commitd73c8e42ca526ff2c53a17ddd1fa87044dd5bbca (patch)
tree071a4f66c7ec5201e0897ce6b666161f556e2695
parent2fceb2dcd7280883e6a3c2beec9190148a5d975b (diff)
parented10ef0208f794060b5351cc601a915177e0a1c5 (diff)
downloaddotty-d73c8e42ca526ff2c53a17ddd1fa87044dd5bbca.tar.gz
dotty-d73c8e42ca526ff2c53a17ddd1fa87044dd5bbca.tar.bz2
dotty-d73c8e42ca526ff2c53a17ddd1fa87044dd5bbca.zip
Merge pull request #2154 from dotty-staging/topic/fix-#2151
Fix #2151: don't die for wrong number of typeargs applied
-rw-r--r--.gitignore1
-rw-r--r--compiler/src/dotty/tools/dotc/core/Decorators.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/util/DiffUtil.scala19
-rw-r--r--compiler/test/dotty/tools/dotc/CompilationTests.scala2
-rw-r--r--compiler/test/dotty/tools/dotc/ParallelSummaryReport.java12
-rw-r--r--compiler/test/dotty/tools/dotc/ParallelTesting.scala70
-rw-r--r--compiler/test/dotty/tools/dotc/reporting/TestReporter.scala66
-rw-r--r--tests/neg/i2151.scala6
9 files changed, 119 insertions, 61 deletions
diff --git a/.gitignore b/.gitignore
index 9842e0c6b..170cf4823 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,6 +44,7 @@ scala-scala
out/
build/
!out/.keep
+testlogs/
# Ignore build-file
.packages
diff --git a/compiler/src/dotty/tools/dotc/core/Decorators.scala b/compiler/src/dotty/tools/dotc/core/Decorators.scala
index f8267072e..0e8ae196a 100644
--- a/compiler/src/dotty/tools/dotc/core/Decorators.scala
+++ b/compiler/src/dotty/tools/dotc/core/Decorators.scala
@@ -103,7 +103,7 @@ object Decorators {
* as long as `xs`.
*/
def zipWithConserve[U](ys: List[U])(f: (T, U) => T): List[T] =
- if (xs.isEmpty) xs
+ if (xs.isEmpty || ys.isEmpty) Nil
else {
val x1 = f(xs.head, ys.head)
val xs1 = xs.tail.zipWithConserve(ys.tail)(f)
diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala
index 17eb8d39b..91e65ab66 100644
--- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala
+++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala
@@ -21,7 +21,7 @@ trait MessageRendering {
* @return string stripped of ANSI escape codes
*/
def stripColor(str: String): String =
- str.replaceAll("\u001B\\[[;\\d]*m", "")
+ str.replaceAll("\u001b\\[.*?m", "")
/** When inlining a method call, if there's an error we'd like to get the
* outer context and the `pos` at which the call was inlined.
diff --git a/compiler/src/dotty/tools/dotc/util/DiffUtil.scala b/compiler/src/dotty/tools/dotc/util/DiffUtil.scala
index b55aee719..6f7df13a6 100644
--- a/compiler/src/dotty/tools/dotc/util/DiffUtil.scala
+++ b/compiler/src/dotty/tools/dotc/util/DiffUtil.scala
@@ -58,8 +58,25 @@ object DiffUtil {
(fnd, exp, totalChange.toDouble / (expected.length + found.length))
}
- def mkColoredCodeDiff(code: String, lastCode: String, printDiffDel: Boolean): String = {
+ def mkColoredLineDiff(expected: String, actual: String): String = {
+ val tokens = splitTokens(expected, Nil).toArray
+ val lastTokens = splitTokens(actual, Nil).toArray
+
+ val diff = hirschberg(lastTokens, tokens)
+ " |SOF\n" + diff.collect {
+ case Unmodified(str) =>
+ " |" + str
+ case Inserted(str) =>
+ ADDITION_COLOR + "e |" + str + ANSI_DEFAULT
+ case Modified(old, str) =>
+ DELETION_COLOR + "a |" + old + "\ne |" + ADDITION_COLOR + str + ANSI_DEFAULT
+ case Deleted(str) =>
+ DELETION_COLOR + "\na |" + str + ANSI_DEFAULT
+ }.mkString + "\n |EOF"
+ }
+
+ def mkColoredCodeDiff(code: String, lastCode: String, printDiffDel: Boolean): String = {
val tokens = splitTokens(code, Nil).toArray
val lastTokens = splitTokens(lastCode, Nil).toArray
diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala
index 788e30aa3..742b93fae 100644
--- a/compiler/test/dotty/tools/dotc/CompilationTests.scala
+++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala
@@ -12,7 +12,7 @@ import scala.util.matching.Regex
class CompilationTests extends ParallelSummaryReport with ParallelTesting {
import CompilationTests._
- def isInteractive: Boolean = !sys.env.contains("DRONE")
+ def isInteractive: Boolean = ParallelSummaryReport.isInteractive
def testFilter: Option[Regex] = sys.props.get("dotty.partest.filter").map(r => new Regex(r))
diff --git a/compiler/test/dotty/tools/dotc/ParallelSummaryReport.java b/compiler/test/dotty/tools/dotc/ParallelSummaryReport.java
index 9214e7d25..5608b3656 100644
--- a/compiler/test/dotty/tools/dotc/ParallelSummaryReport.java
+++ b/compiler/test/dotty/tools/dotc/ParallelSummaryReport.java
@@ -11,7 +11,9 @@ import dotty.tools.dotc.reporting.TestReporter$;
* this class
*/
public class ParallelSummaryReport {
- private static TestReporter rep = TestReporter.reporter(-1);
+ public final static boolean isInteractive = !System.getenv().containsKey("DRONE");
+
+ private static TestReporter rep = TestReporter.reporter(System.out, -1);
private static ArrayDeque<String> failedTests = new ArrayDeque<>();
private static ArrayDeque<String> reproduceInstructions = new ArrayDeque<>();
private static int passed;
@@ -34,7 +36,7 @@ public class ParallelSummaryReport {
}
@BeforeClass public final static void setup() {
- rep = TestReporter.reporter(-1);
+ rep = TestReporter.reporter(System.out, -1);
failedTests = new ArrayDeque<>();
reproduceInstructions = new ArrayDeque<>();
}
@@ -54,7 +56,8 @@ public class ParallelSummaryReport {
.map(x -> " " + x)
.forEach(rep::echo);
- rep.flushToStdErr();
+ // If we're compiling locally, we don't need reproduce instructions
+ if (isInteractive) rep.flushToStdErr();
rep.echo("");
@@ -62,6 +65,9 @@ public class ParallelSummaryReport {
.stream()
.forEach(rep::echo);
+ // If we're on the CI, we want everything
+ if (!isInteractive) rep.flushToStdErr();
+
if (failed > 0) rep.flushToFile();
}
}
diff --git a/compiler/test/dotty/tools/dotc/ParallelTesting.scala b/compiler/test/dotty/tools/dotc/ParallelTesting.scala
index a81eb4d3a..2b20887e3 100644
--- a/compiler/test/dotty/tools/dotc/ParallelTesting.scala
+++ b/compiler/test/dotty/tools/dotc/ParallelTesting.scala
@@ -51,6 +51,16 @@ trait ParallelTesting { self =>
def outDir: JFile
def flags: Array[String]
+
+ def title: String = self match {
+ case self: JointCompilationSource =>
+ if (self.files.length > 1) name
+ else self.files.head.getPath
+
+ case self: SeparateCompilationSource =>
+ self.dir.getPath
+ }
+
/** Adds the flags specified in `newFlags0` if they do not already exist */
def withFlags(newFlags0: String*) = {
val newFlags = newFlags0.toArray
@@ -69,7 +79,11 @@ trait ParallelTesting { self =>
val maxLen = 80
var lineLen = 0
- sb.append(s"\n\nTest compiled with $errors error(s) and $warnings warning(s), the test can be reproduced by running:")
+ sb.append(
+ s"""|
+ |Test '$title' compiled with $errors error(s) and $warnings warning(s),
+ |the test can be reproduced by running:""".stripMargin
+ )
sb.append("\n\n./bin/dotc ")
flags.foreach { arg =>
if (lineLen > maxLen) {
@@ -160,6 +174,8 @@ trait ParallelTesting { self =>
* according to the implementing class "neg", "run" or "pos".
*/
private abstract class Test(testSources: List[TestSource], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean) {
+ protected final val realStdout = System.out
+ protected final val realStderr = System.err
/** Actual compilation run logic, the test behaviour is defined here */
protected def compilationRunnable(testSource: TestSource): Runnable
@@ -178,10 +194,10 @@ trait ParallelTesting { self =>
val sourceCount = filteredSources.length
private[this] var _errorCount = 0
- def errorCount: Int = synchronized { _errorCount }
+ def errorCount: Int = _errorCount
private[this] var _testSourcesCompiled = 0
- private def testSourcesCompiled : Int = synchronized { _testSourcesCompiled }
+ private def testSourcesCompiled: Int = _testSourcesCompiled
/** Complete the current compilation with the amount of errors encountered */
protected final def registerCompilation(errors: Int) = synchronized {
@@ -214,7 +230,7 @@ trait ParallelTesting { self =>
/** Prints to `System.err` if we're not suppressing all output */
protected def echo(msg: String): Unit =
- if (!suppressAllOutput) System.err.println(msg)
+ if (!suppressAllOutput) realStderr.println(msg)
/** A single `Runnable` that prints a progress bar for the curent `Test` */
private def createProgressMonitor: Runnable = new Runnable {
@@ -224,17 +240,19 @@ trait ParallelTesting { self =>
while (tCompiled < sourceCount) {
val timestamp = (System.currentTimeMillis - start) / 1000
val progress = (tCompiled.toDouble / sourceCount * 40).toInt
- print(
+
+ realStdout.print(
"[" + ("=" * (math.max(progress - 1, 0))) +
(if (progress > 0) ">" else "") +
(" " * (39 - progress)) +
s"] compiling ($tCompiled/$sourceCount, ${timestamp}s)\r"
)
+
Thread.sleep(100)
tCompiled = testSourcesCompiled
}
// println, otherwise no newline and cursor at start of line
- println(
+ realStdout.println(
s"[=======================================] compiled ($sourceCount/$sourceCount, " +
s"${(System.currentTimeMillis - start) / 1000}s) "
)
@@ -245,7 +263,10 @@ trait ParallelTesting { self =>
* if it did, the test should automatically fail.
*/
protected def tryCompile(testSource: TestSource)(op: => Unit): Unit =
- try op catch {
+ try {
+ if (!isInteractive) realStdout.println(s"Testing ${testSource.title}")
+ op
+ } catch {
case NonFatal(e) => {
// if an exception is thrown during compilation, the complete test
// run should fail
@@ -295,8 +316,10 @@ trait ParallelTesting { self =>
Runtime.getRuntime.exec(fullArgs).waitFor() == 0
} else true
- val reporter = TestReporter.parallelReporter(this, logLevel =
- if (suppressErrors || suppressAllOutput) ERROR + 1 else ERROR)
+ val reporter =
+ TestReporter.reporter(realStdout, logLevel =
+ if (suppressErrors || suppressAllOutput) ERROR + 1 else ERROR)
+
val driver =
if (times == 1) new Driver { def newCompiler(implicit ctx: Context) = new Compiler }
else new Driver {
@@ -339,8 +362,12 @@ trait ParallelTesting { self =>
}
pool.shutdown()
- if (!pool.awaitTermination(10, TimeUnit.MINUTES))
+ if (!pool.awaitTermination(20, TimeUnit.MINUTES)) {
+ pool.shutdownNow()
+ System.setOut(realStdout)
+ System.setErr(realStderr)
throw new TimeoutException("Compiling targets timed out")
+ }
if (didFail) {
reportFailed()
@@ -403,8 +430,6 @@ trait ParallelTesting { self =>
import java.net.{ URL, URLClassLoader }
val printStream = new ByteArrayOutputStream
- val oldOut = System.out
- val oldErr = System.err
try {
// Do classloading magic and running here:
@@ -412,7 +437,7 @@ trait ParallelTesting { self =>
val cls = ucl.loadClass("Test")
val meth = cls.getMethod("main", classOf[Array[String]])
- self.synchronized {
+ synchronized {
try {
val ps = new PrintStream(printStream)
System.setOut(ps)
@@ -422,9 +447,13 @@ trait ParallelTesting { self =>
meth.invoke(null, Array("jvm")) // partest passes at least "jvm" as an arg
}
}
- } finally {
- System.setOut(oldOut)
- System.setErr(oldErr)
+ System.setOut(realStdout)
+ System.setErr(realStderr)
+ } catch {
+ case t: Throwable =>
+ System.setOut(realStdout)
+ System.setErr(realStderr)
+ throw t
}
}
}
@@ -447,6 +476,7 @@ trait ParallelTesting { self =>
private def verifyOutput(checkFile: JFile, dir: JFile, testSource: TestSource, warnings: Int) = {
val outputLines = runMain(dir, testSource)
val checkLines = Source.fromFile(checkFile).getLines.toArray
+ val sourceTitle = testSource.title
def linesMatch =
outputLines
@@ -456,9 +486,13 @@ trait ParallelTesting { self =>
if (outputLines.length != checkLines.length || !linesMatch) {
// Print diff to files and summary:
val diff = outputLines.zip(checkLines).map { case (act, exp) =>
- DiffUtil.mkColoredCodeDiff(exp, act, true)
+ DiffUtil.mkColoredLineDiff(exp, act)
}.mkString("\n")
- val msg = s"\nOutput from run test '$checkFile' did not match expected, output:\n$diff\n"
+
+ val msg =
+ s"""|Output from '$sourceTitle' did not match check file.
+ |Diff ('e' is expected, 'a' is actual):
+ |""".stripMargin + diff + "\n"
echo(msg)
addFailureInstruction(msg)
diff --git a/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala
index 521cf9576..5641240a7 100644
--- a/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala
+++ b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala
@@ -2,7 +2,7 @@ package dotty.tools
package dotc
package reporting
-import java.io.{ PrintWriter, File => JFile, FileOutputStream }
+import java.io.{ PrintStream, PrintWriter, File => JFile, FileOutputStream }
import java.text.SimpleDateFormat
import java.util.Date
@@ -25,10 +25,16 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M
protected final val _messageBuf = mutable.ArrayBuffer.empty[String]
final def flushToFile(): Unit =
- _messageBuf.iterator.foreach(filePrintln)
+ _messageBuf
+ .iterator
+ .map(_.replaceAll("\u001b\\[.*?m", ""))
+ .foreach(filePrintln)
final def flushToStdErr(): Unit =
- _messageBuf.iterator.foreach(System.err.println)
+ _messageBuf
+ .iterator
+ .map(_.replaceAll("\u001b\\[.*?m", ""))
+ .foreach(System.err.println)
final def inlineInfo(pos: SourcePosition): String =
if (pos.exists) {
@@ -75,10 +81,11 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M
}
object TestReporter {
- private[this] val logWriter = {
+ private[this] lazy val logWriter = {
val df = new SimpleDateFormat("yyyy-MM-dd-HH:mm")
val timestamp = df.format(new Date)
- new PrintWriter(new FileOutputStream(new JFile(s"../tests-$timestamp.log"), true))
+ new JFile("../testlogs").mkdirs()
+ new PrintWriter(new FileOutputStream(new JFile(s"../testlogs/tests-$timestamp.log"), true))
}
def writeToLog(str: String) = {
@@ -86,38 +93,25 @@ object TestReporter {
logWriter.flush()
}
- def parallelReporter(lock: AnyRef, logLevel: Int): TestReporter = new TestReporter(
- new PrintWriter(Console.err, true),
- str => lock.synchronized {
- logWriter.println(str)
- logWriter.flush()
- },
- logLevel
- )
-
- def reporter(logLevel: Int): TestReporter = new TestReporter(
- new PrintWriter(Console.err, true),
- writeToLog,
- logLevel
- )
-
- def simplifiedReporter(writer: PrintWriter): TestReporter = new TestReporter(
- writer,
- writeToLog,
- WARNING
- ) {
- /** Prints the message with the given position indication in a simplified manner */
- override def printMessageAndPos(m: MessageContainer, extra: String)(implicit ctx: Context): Unit = {
- val msg = s"${m.pos.line + 1}: " + m.contained.kind + extra
- val extraInfo = inlineInfo(m.pos)
-
- writer.println(msg)
- _messageBuf.append(msg)
-
- if (extraInfo.nonEmpty) {
- writer.println(extraInfo)
- _messageBuf.append(extraInfo)
+ def reporter(ps: PrintStream, logLevel: Int): TestReporter =
+ new TestReporter(new PrintWriter(ps, true), writeToLog, logLevel)
+
+ def simplifiedReporter(writer: PrintWriter): TestReporter = {
+ val rep = new TestReporter(writer, writeToLog, WARNING) {
+ /** Prints the message with the given position indication in a simplified manner */
+ override def printMessageAndPos(m: MessageContainer, extra: String)(implicit ctx: Context): Unit = {
+ val msg = s"${m.pos.line + 1}: " + m.contained.kind + extra
+ val extraInfo = inlineInfo(m.pos)
+
+ writer.println(msg)
+ _messageBuf.append(msg)
+
+ if (extraInfo.nonEmpty) {
+ writer.println(extraInfo)
+ _messageBuf.append(extraInfo)
+ }
}
}
+ rep
}
}
diff --git a/tests/neg/i2151.scala b/tests/neg/i2151.scala
new file mode 100644
index 000000000..1ae034c02
--- /dev/null
+++ b/tests/neg/i2151.scala
@@ -0,0 +1,6 @@
+trait Test {
+ type Nil = [K] => K
+ type StrangeCons[H, Tail <: [H, A] => H] = Tail[H, H]
+
+ def list: StrangeCons[Int, Nil] // error
+}