Skip to content

Fix #2151: don't die for wrong number of typeargs applied #2154

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 31, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ scala-scala
out/
build/
!out/.keep
testlogs/

# Ignore build-file
.packages
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Decorators.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
19 changes: 18 additions & 1 deletion compiler/src/dotty/tools/dotc/util/DiffUtil.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion compiler/test/dotty/tools/dotc/CompilationTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
12 changes: 9 additions & 3 deletions compiler/test/dotty/tools/dotc/ParallelSummaryReport.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
* 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;
Expand All @@ -34,7 +36,7 @@ public final static void addReproduceInstruction(String msg) {
}

@BeforeClass public final static void setup() {
rep = TestReporter.reporter(-1);
rep = TestReporter.reporter(System.out, -1);
failedTests = new ArrayDeque<>();
reproduceInstructions = new ArrayDeque<>();
}
Expand All @@ -54,14 +56,18 @@ public final static void addReproduceInstruction(String msg) {
.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("");

reproduceInstructions
.stream()
.forEach(rep::echo);

// If we're on the CI, we want everything
if (!isInteractive) rep.flushToStdErr();

if (failed > 0) rep.flushToFile();
}
}
70 changes: 52 additions & 18 deletions compiler/test/dotty/tools/dotc/ParallelTesting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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) "
)
Expand All @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -403,16 +430,14 @@ 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:
val ucl = new URLClassLoader(Array(dir.toURI.toURL))
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)
Expand All @@ -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
}
}
}
Expand All @@ -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
Expand All @@ -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)

Expand Down
66 changes: 30 additions & 36 deletions compiler/test/dotty/tools/dotc/reporting/TestReporter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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) {
Expand Down Expand Up @@ -75,49 +81,37 @@ 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) = {
logWriter.println(str)
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to add a link to the corresponding bug report if you open one

}
}
6 changes: 6 additions & 0 deletions tests/neg/i2151.scala
Original file line number Diff line number Diff line change
@@ -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
}