Skip to content

Commit 710e700

Browse files
authored
Merge branch 'master' into fix-hashcode
2 parents aa2522c + d73c8e4 commit 710e700

File tree

18 files changed

+298
-93
lines changed

18 files changed

+298
-93
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/core/classfile/ClassfileParser.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ class ClassfileParser(
661661
for (entry <- innerClasses.values) {
662662
// create a new class member for immediate inner classes
663663
if (entry.outerName == currentClassName) {
664-
val file = ctx.platform.classPath.findSourceFile(entry.externalName.toString) getOrElse {
664+
val file = ctx.platform.classPath.findBinaryFile(entry.externalName.toString) getOrElse {
665665
throw new AssertionError(entry.externalName)
666666
}
667667
enterClassAndModule(entry, file, entry.jflags)

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/transform/PatternMatcher.scala

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -848,26 +848,21 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {
848848

849849
val nextBinder = afterTest.asTerm
850850

851-
def needsOuterTest(patType: Type, selType: Type, currentOwner: Symbol): Boolean = {
851+
def outerTestNeeded(implicit ctx: Context): Boolean = {
852852
// See the test for SI-7214 for motivation for dealias. Later `treeCondStrategy#outerTest`
853853
// generates an outer test based on `patType.prefix` with automatically dealises.
854-
patType.dealias match {
855-
case tref @ TypeRef(pre, name) =>
856-
(pre ne NoPrefix) && tref.symbol.isClass &&
857-
ExplicitOuter.needsOuterIfReferenced(tref.symbol.asClass)
854+
expectedTp.dealias match {
855+
case tref @ TypeRef(pre: SingletonType, name) =>
856+
val s = tref
857+
s.symbol.isClass &&
858+
ExplicitOuter.needsOuterIfReferenced(s.symbol.asClass)
858859
case _ =>
859860
false
860861
}
861862
}
862863

863864
override lazy val introducedRebindings = NoRebindings
864865

865-
def outerTestNeeded = {
866-
val np = expectedTp.normalizedPrefix
867-
val ts = np.termSymbol
868-
(ts ne NoSymbol) && needsOuterTest(expectedTp, testedBinder.info, ctx.owner)
869-
}
870-
871866
// the logic to generate the run-time test that follows from the fact that
872867
// a `prevBinder` is expected to have type `expectedTp`
873868
// the actual tree-generation logic is factored out, since the analyses generate Cond(ition)s rather than Trees

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/src/dotty/tools/io/ClassPath.scala

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -240,22 +240,16 @@ abstract class ClassPath {
240240
def findClass(name: String): Option[AnyClassRep] =
241241
name.splitWhere(_ == '.', doDropIndex = true) match {
242242
case Some((pkg, rest)) =>
243-
val rep = packages find (_.name == pkg) flatMap (_ findClass rest)
244-
rep map {
245-
case x: ClassRep => x
246-
case x => throw new FatalError("Unexpected ClassRep '%s' found searching for name '%s'".format(x, name))
247-
}
243+
packages find (_.name == pkg) flatMap (_ findClass rest)
248244
case _ =>
249245
classes find (_.name == name)
250246
}
251247

252-
def findSourceFile(name: String): Option[AbstractFile] =
253-
findClass(name) match {
254-
case Some(ClassRep(Some(x: AbstractFile), _)) => Some(x)
255-
case _ => None
256-
}
248+
def findBinaryFile(name: String): Option[AbstractFile] =
249+
findClass(name).flatMap(_.binary)
257250

258251
def sortString = join(split(asClasspathString).sorted: _*)
252+
259253
override def equals(that: Any) = that match {
260254
case x: ClassPath => this.sortString == x.sortString
261255
case _ => false

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: 54 additions & 21 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

@@ -920,9 +954,8 @@ trait ParallelTesting { self =>
920954
private def compilationTargets(sourceDir: JFile): (List[JFile], List[JFile]) =
921955
sourceDir.listFiles.foldLeft((List.empty[JFile], List.empty[JFile])) { case ((dirs, files), f) =>
922956
if (f.isDirectory) (f :: dirs, files)
923-
else if (f.getName.endsWith(".check")) (dirs, files)
924-
else if (f.getName.endsWith(".flags")) (dirs, files)
925-
else (dirs, f :: files)
957+
else if (isSourceFile(f)) (dirs, f :: files)
958+
else (dirs, files)
926959
}
927960

928961
/** Gets the name of the calling method via reflection.

0 commit comments

Comments
 (0)