Skip to content

Commit d73c8e4

Browse files
authored
Merge pull request #2154 from dotty-staging/topic/fix-#2151
Fix #2151: don't die for wrong number of typeargs applied
2 parents 2fceb2d + ed10ef0 commit d73c8e4

File tree

9 files changed

+119
-61
lines changed

9 files changed

+119
-61
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ scala-scala
4444
out/
4545
build/
4646
!out/.keep
47+
testlogs/
4748

4849
# Ignore build-file
4950
.packages

compiler/src/dotty/tools/dotc/core/Decorators.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ object Decorators {
103103
* as long as `xs`.
104104
*/
105105
def zipWithConserve[U](ys: List[U])(f: (T, U) => T): List[T] =
106-
if (xs.isEmpty) xs
106+
if (xs.isEmpty || ys.isEmpty) Nil
107107
else {
108108
val x1 = f(xs.head, ys.head)
109109
val xs1 = xs.tail.zipWithConserve(ys.tail)(f)

compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ trait MessageRendering {
2121
* @return string stripped of ANSI escape codes
2222
*/
2323
def stripColor(str: String): String =
24-
str.replaceAll("\u001B\\[[;\\d]*m", "")
24+
str.replaceAll("\u001b\\[.*?m", "")
2525

2626
/** When inlining a method call, if there's an error we'd like to get the
2727
* outer context and the `pos` at which the call was inlined.

compiler/src/dotty/tools/dotc/util/DiffUtil.scala

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,25 @@ object DiffUtil {
5858
(fnd, exp, totalChange.toDouble / (expected.length + found.length))
5959
}
6060

61-
def mkColoredCodeDiff(code: String, lastCode: String, printDiffDel: Boolean): String = {
61+
def mkColoredLineDiff(expected: String, actual: String): String = {
62+
val tokens = splitTokens(expected, Nil).toArray
63+
val lastTokens = splitTokens(actual, Nil).toArray
64+
65+
val diff = hirschberg(lastTokens, tokens)
6266

67+
" |SOF\n" + diff.collect {
68+
case Unmodified(str) =>
69+
" |" + str
70+
case Inserted(str) =>
71+
ADDITION_COLOR + "e |" + str + ANSI_DEFAULT
72+
case Modified(old, str) =>
73+
DELETION_COLOR + "a |" + old + "\ne |" + ADDITION_COLOR + str + ANSI_DEFAULT
74+
case Deleted(str) =>
75+
DELETION_COLOR + "\na |" + str + ANSI_DEFAULT
76+
}.mkString + "\n |EOF"
77+
}
78+
79+
def mkColoredCodeDiff(code: String, lastCode: String, printDiffDel: Boolean): String = {
6380
val tokens = splitTokens(code, Nil).toArray
6481
val lastTokens = splitTokens(lastCode, Nil).toArray
6582

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import scala.util.matching.Regex
1212
class CompilationTests extends ParallelSummaryReport with ParallelTesting {
1313
import CompilationTests._
1414

15-
def isInteractive: Boolean = !sys.env.contains("DRONE")
15+
def isInteractive: Boolean = ParallelSummaryReport.isInteractive
1616

1717
def testFilter: Option[Regex] = sys.props.get("dotty.partest.filter").map(r => new Regex(r))
1818

compiler/test/dotty/tools/dotc/ParallelSummaryReport.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
* this class
1212
*/
1313
public class ParallelSummaryReport {
14-
private static TestReporter rep = TestReporter.reporter(-1);
14+
public final static boolean isInteractive = !System.getenv().containsKey("DRONE");
15+
16+
private static TestReporter rep = TestReporter.reporter(System.out, -1);
1517
private static ArrayDeque<String> failedTests = new ArrayDeque<>();
1618
private static ArrayDeque<String> reproduceInstructions = new ArrayDeque<>();
1719
private static int passed;
@@ -34,7 +36,7 @@ public final static void addReproduceInstruction(String msg) {
3436
}
3537

3638
@BeforeClass public final static void setup() {
37-
rep = TestReporter.reporter(-1);
39+
rep = TestReporter.reporter(System.out, -1);
3840
failedTests = new ArrayDeque<>();
3941
reproduceInstructions = new ArrayDeque<>();
4042
}
@@ -54,14 +56,18 @@ public final static void addReproduceInstruction(String msg) {
5456
.map(x -> " " + x)
5557
.forEach(rep::echo);
5658

57-
rep.flushToStdErr();
59+
// If we're compiling locally, we don't need reproduce instructions
60+
if (isInteractive) rep.flushToStdErr();
5861

5962
rep.echo("");
6063

6164
reproduceInstructions
6265
.stream()
6366
.forEach(rep::echo);
6467

68+
// If we're on the CI, we want everything
69+
if (!isInteractive) rep.flushToStdErr();
70+
6571
if (failed > 0) rep.flushToFile();
6672
}
6773
}

compiler/test/dotty/tools/dotc/ParallelTesting.scala

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ trait ParallelTesting { self =>
5151
def outDir: JFile
5252
def flags: Array[String]
5353

54+
55+
def title: String = self match {
56+
case self: JointCompilationSource =>
57+
if (self.files.length > 1) name
58+
else self.files.head.getPath
59+
60+
case self: SeparateCompilationSource =>
61+
self.dir.getPath
62+
}
63+
5464
/** Adds the flags specified in `newFlags0` if they do not already exist */
5565
def withFlags(newFlags0: String*) = {
5666
val newFlags = newFlags0.toArray
@@ -69,7 +79,11 @@ trait ParallelTesting { self =>
6979
val maxLen = 80
7080
var lineLen = 0
7181

72-
sb.append(s"\n\nTest compiled with $errors error(s) and $warnings warning(s), the test can be reproduced by running:")
82+
sb.append(
83+
s"""|
84+
|Test '$title' compiled with $errors error(s) and $warnings warning(s),
85+
|the test can be reproduced by running:""".stripMargin
86+
)
7387
sb.append("\n\n./bin/dotc ")
7488
flags.foreach { arg =>
7589
if (lineLen > maxLen) {
@@ -160,6 +174,8 @@ trait ParallelTesting { self =>
160174
* according to the implementing class "neg", "run" or "pos".
161175
*/
162176
private abstract class Test(testSources: List[TestSource], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean) {
177+
protected final val realStdout = System.out
178+
protected final val realStderr = System.err
163179

164180
/** Actual compilation run logic, the test behaviour is defined here */
165181
protected def compilationRunnable(testSource: TestSource): Runnable
@@ -178,10 +194,10 @@ trait ParallelTesting { self =>
178194
val sourceCount = filteredSources.length
179195

180196
private[this] var _errorCount = 0
181-
def errorCount: Int = synchronized { _errorCount }
197+
def errorCount: Int = _errorCount
182198

183199
private[this] var _testSourcesCompiled = 0
184-
private def testSourcesCompiled : Int = synchronized { _testSourcesCompiled }
200+
private def testSourcesCompiled: Int = _testSourcesCompiled
185201

186202
/** Complete the current compilation with the amount of errors encountered */
187203
protected final def registerCompilation(errors: Int) = synchronized {
@@ -214,7 +230,7 @@ trait ParallelTesting { self =>
214230

215231
/** Prints to `System.err` if we're not suppressing all output */
216232
protected def echo(msg: String): Unit =
217-
if (!suppressAllOutput) System.err.println(msg)
233+
if (!suppressAllOutput) realStderr.println(msg)
218234

219235
/** A single `Runnable` that prints a progress bar for the curent `Test` */
220236
private def createProgressMonitor: Runnable = new Runnable {
@@ -224,17 +240,19 @@ trait ParallelTesting { self =>
224240
while (tCompiled < sourceCount) {
225241
val timestamp = (System.currentTimeMillis - start) / 1000
226242
val progress = (tCompiled.toDouble / sourceCount * 40).toInt
227-
print(
243+
244+
realStdout.print(
228245
"[" + ("=" * (math.max(progress - 1, 0))) +
229246
(if (progress > 0) ">" else "") +
230247
(" " * (39 - progress)) +
231248
s"] compiling ($tCompiled/$sourceCount, ${timestamp}s)\r"
232249
)
250+
233251
Thread.sleep(100)
234252
tCompiled = testSourcesCompiled
235253
}
236254
// println, otherwise no newline and cursor at start of line
237-
println(
255+
realStdout.println(
238256
s"[=======================================] compiled ($sourceCount/$sourceCount, " +
239257
s"${(System.currentTimeMillis - start) / 1000}s) "
240258
)
@@ -245,7 +263,10 @@ trait ParallelTesting { self =>
245263
* if it did, the test should automatically fail.
246264
*/
247265
protected def tryCompile(testSource: TestSource)(op: => Unit): Unit =
248-
try op catch {
266+
try {
267+
if (!isInteractive) realStdout.println(s"Testing ${testSource.title}")
268+
op
269+
} catch {
249270
case NonFatal(e) => {
250271
// if an exception is thrown during compilation, the complete test
251272
// run should fail
@@ -295,8 +316,10 @@ trait ParallelTesting { self =>
295316
Runtime.getRuntime.exec(fullArgs).waitFor() == 0
296317
} else true
297318

298-
val reporter = TestReporter.parallelReporter(this, logLevel =
299-
if (suppressErrors || suppressAllOutput) ERROR + 1 else ERROR)
319+
val reporter =
320+
TestReporter.reporter(realStdout, logLevel =
321+
if (suppressErrors || suppressAllOutput) ERROR + 1 else ERROR)
322+
300323
val driver =
301324
if (times == 1) new Driver { def newCompiler(implicit ctx: Context) = new Compiler }
302325
else new Driver {
@@ -339,8 +362,12 @@ trait ParallelTesting { self =>
339362
}
340363

341364
pool.shutdown()
342-
if (!pool.awaitTermination(10, TimeUnit.MINUTES))
365+
if (!pool.awaitTermination(20, TimeUnit.MINUTES)) {
366+
pool.shutdownNow()
367+
System.setOut(realStdout)
368+
System.setErr(realStderr)
343369
throw new TimeoutException("Compiling targets timed out")
370+
}
344371

345372
if (didFail) {
346373
reportFailed()
@@ -403,16 +430,14 @@ trait ParallelTesting { self =>
403430
import java.net.{ URL, URLClassLoader }
404431

405432
val printStream = new ByteArrayOutputStream
406-
val oldOut = System.out
407-
val oldErr = System.err
408433

409434
try {
410435
// Do classloading magic and running here:
411436
val ucl = new URLClassLoader(Array(dir.toURI.toURL))
412437
val cls = ucl.loadClass("Test")
413438
val meth = cls.getMethod("main", classOf[Array[String]])
414439

415-
self.synchronized {
440+
synchronized {
416441
try {
417442
val ps = new PrintStream(printStream)
418443
System.setOut(ps)
@@ -422,9 +447,13 @@ trait ParallelTesting { self =>
422447
meth.invoke(null, Array("jvm")) // partest passes at least "jvm" as an arg
423448
}
424449
}
425-
} finally {
426-
System.setOut(oldOut)
427-
System.setErr(oldErr)
450+
System.setOut(realStdout)
451+
System.setErr(realStderr)
452+
} catch {
453+
case t: Throwable =>
454+
System.setOut(realStdout)
455+
System.setErr(realStderr)
456+
throw t
428457
}
429458
}
430459
}
@@ -447,6 +476,7 @@ trait ParallelTesting { self =>
447476
private def verifyOutput(checkFile: JFile, dir: JFile, testSource: TestSource, warnings: Int) = {
448477
val outputLines = runMain(dir, testSource)
449478
val checkLines = Source.fromFile(checkFile).getLines.toArray
479+
val sourceTitle = testSource.title
450480

451481
def linesMatch =
452482
outputLines
@@ -456,9 +486,13 @@ trait ParallelTesting { self =>
456486
if (outputLines.length != checkLines.length || !linesMatch) {
457487
// Print diff to files and summary:
458488
val diff = outputLines.zip(checkLines).map { case (act, exp) =>
459-
DiffUtil.mkColoredCodeDiff(exp, act, true)
489+
DiffUtil.mkColoredLineDiff(exp, act)
460490
}.mkString("\n")
461-
val msg = s"\nOutput from run test '$checkFile' did not match expected, output:\n$diff\n"
491+
492+
val msg =
493+
s"""|Output from '$sourceTitle' did not match check file.
494+
|Diff ('e' is expected, 'a' is actual):
495+
|""".stripMargin + diff + "\n"
462496
echo(msg)
463497
addFailureInstruction(msg)
464498

compiler/test/dotty/tools/dotc/reporting/TestReporter.scala

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package dotty.tools
22
package dotc
33
package reporting
44

5-
import java.io.{ PrintWriter, File => JFile, FileOutputStream }
5+
import java.io.{ PrintStream, PrintWriter, File => JFile, FileOutputStream }
66
import java.text.SimpleDateFormat
77
import java.util.Date
88

@@ -25,10 +25,16 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M
2525
protected final val _messageBuf = mutable.ArrayBuffer.empty[String]
2626

2727
final def flushToFile(): Unit =
28-
_messageBuf.iterator.foreach(filePrintln)
28+
_messageBuf
29+
.iterator
30+
.map(_.replaceAll("\u001b\\[.*?m", ""))
31+
.foreach(filePrintln)
2932

3033
final def flushToStdErr(): Unit =
31-
_messageBuf.iterator.foreach(System.err.println)
34+
_messageBuf
35+
.iterator
36+
.map(_.replaceAll("\u001b\\[.*?m", ""))
37+
.foreach(System.err.println)
3238

3339
final def inlineInfo(pos: SourcePosition): String =
3440
if (pos.exists) {
@@ -75,49 +81,37 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M
7581
}
7682

7783
object TestReporter {
78-
private[this] val logWriter = {
84+
private[this] lazy val logWriter = {
7985
val df = new SimpleDateFormat("yyyy-MM-dd-HH:mm")
8086
val timestamp = df.format(new Date)
81-
new PrintWriter(new FileOutputStream(new JFile(s"../tests-$timestamp.log"), true))
87+
new JFile("../testlogs").mkdirs()
88+
new PrintWriter(new FileOutputStream(new JFile(s"../testlogs/tests-$timestamp.log"), true))
8289
}
8390

8491
def writeToLog(str: String) = {
8592
logWriter.println(str)
8693
logWriter.flush()
8794
}
8895

89-
def parallelReporter(lock: AnyRef, logLevel: Int): TestReporter = new TestReporter(
90-
new PrintWriter(Console.err, true),
91-
str => lock.synchronized {
92-
logWriter.println(str)
93-
logWriter.flush()
94-
},
95-
logLevel
96-
)
97-
98-
def reporter(logLevel: Int): TestReporter = new TestReporter(
99-
new PrintWriter(Console.err, true),
100-
writeToLog,
101-
logLevel
102-
)
103-
104-
def simplifiedReporter(writer: PrintWriter): TestReporter = new TestReporter(
105-
writer,
106-
writeToLog,
107-
WARNING
108-
) {
109-
/** Prints the message with the given position indication in a simplified manner */
110-
override def printMessageAndPos(m: MessageContainer, extra: String)(implicit ctx: Context): Unit = {
111-
val msg = s"${m.pos.line + 1}: " + m.contained.kind + extra
112-
val extraInfo = inlineInfo(m.pos)
113-
114-
writer.println(msg)
115-
_messageBuf.append(msg)
116-
117-
if (extraInfo.nonEmpty) {
118-
writer.println(extraInfo)
119-
_messageBuf.append(extraInfo)
96+
def reporter(ps: PrintStream, logLevel: Int): TestReporter =
97+
new TestReporter(new PrintWriter(ps, true), writeToLog, logLevel)
98+
99+
def simplifiedReporter(writer: PrintWriter): TestReporter = {
100+
val rep = new TestReporter(writer, writeToLog, WARNING) {
101+
/** Prints the message with the given position indication in a simplified manner */
102+
override def printMessageAndPos(m: MessageContainer, extra: String)(implicit ctx: Context): Unit = {
103+
val msg = s"${m.pos.line + 1}: " + m.contained.kind + extra
104+
val extraInfo = inlineInfo(m.pos)
105+
106+
writer.println(msg)
107+
_messageBuf.append(msg)
108+
109+
if (extraInfo.nonEmpty) {
110+
writer.println(extraInfo)
111+
_messageBuf.append(extraInfo)
112+
}
120113
}
121114
}
115+
rep
122116
}
123117
}

tests/neg/i2151.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
trait Test {
2+
type Nil = [K] => K
3+
type StrangeCons[H, Tail <: [H, A] => H] = Tail[H, H]
4+
5+
def list: StrangeCons[Int, Nil] // error
6+
}

0 commit comments

Comments
 (0)