Skip to content

Output other compiler errors #14339

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 6 commits into from
Jan 25, 2022
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
63 changes: 45 additions & 18 deletions compiler/test/dotty/tools/vulpix/ParallelTesting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import dotc.interfaces.Diagnostic.ERROR
import dotc.reporting.{Reporter, TestReporter}
import dotc.reporting.Diagnostic
import dotc.config.Config
import dotc.util.{DiffUtil, SourceFile, SourcePosition, Spans}
import dotc.util.{DiffUtil, SourceFile, SourcePosition, Spans, NoSourcePosition}
import io.AbstractFile
import dotty.tools.vulpix.TestConfiguration.defaultOptions

Expand Down Expand Up @@ -504,20 +504,45 @@ trait ParallelTesting extends RunnerOrchestration { self =>
reporter
}

private def parseErrors(errorsText: String, compilerVersion: String) =
val errorPattern = """.*Error: (.*\.scala):(\d+):(\d+).*""".r
errorsText.linesIterator.toSeq.collect {
case errorPattern(filePath, line, column) =>
val lineNum = line.toInt
val columnNum = column.toInt
val abstractFile = AbstractFile.getFile(filePath)
val sourceFile = SourceFile(abstractFile, Codec.UTF8)
val offset = sourceFile.lineToOffset(lineNum - 1) + columnNum - 1
val span = Spans.Span(offset)
val sourcePos = SourcePosition(sourceFile, span)

Diagnostic.Error(s"Compilation of $filePath with Scala $compilerVersion failed at line: $line, column: $column. Full error output:\n\n$errorsText\n", sourcePos)
}
private def parseErrors(errorsText: String, compilerVersion: String, pageWidth: Int) =
val errorPattern = """^.*Error: (.*\.scala):(\d+):(\d+).*""".r
val brokenClassPattern = """^class file (.*) is broken.*""".r
val warnPattern = """^.*Warning: (.*\.scala):(\d+):(\d+).*""".r
val summaryPattern = """\d+ (?:warning|error)s? found""".r
val indent = " "
var diagnostics = List.empty[Diagnostic.Error]
def barLine(start: Boolean) = s"$indent${if start then "╭" else "╰"}${"┄" * pageWidth}${if start then "╮" else "╯"}\n"
def errorLine(line: String) = s"$indent┆${String.format(s"%-${pageWidth}s", stripAnsi(line))}┆\n"
def stripAnsi(str: String): String = str.replaceAll("\u001b\\[\\d+m", "")
def addToLast(str: String): Unit =
diagnostics match
case head :: tail =>
diagnostics = Diagnostic.Error(s"${head.msg.rawMessage}$str", head.pos) :: tail
Copy link
Contributor

Choose a reason for hiding this comment

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

If we catch warnings as well, we should handle them properly too. Although I'm not sure if we really need that and if we can handle this reliably as the external compiler process might not fail if there are some warnings but no error. As far as I know, every time we want to check if a warning was raised we enable fatal warnings and check for errors instead

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added code to ignore warnings

case Nil =>
var inError = false
for line <- errorsText.linesIterator do
line match
case error @ warnPattern(filePath, line, column) =>
inError = false
case error @ errorPattern(filePath, line, column) =>
inError = true
val lineNum = line.toInt
val columnNum = column.toInt
val abstractFile = AbstractFile.getFile(filePath)
val sourceFile = SourceFile(abstractFile, Codec.UTF8)
val offset = sourceFile.lineToOffset(lineNum - 1) + columnNum - 1
val span = Spans.Span(offset)
val sourcePos = SourcePosition(sourceFile, span)
addToLast(barLine(start = false))
diagnostics ::= Diagnostic.Error(s"Compilation of $filePath with Scala $compilerVersion failed at line: $line, column: $column.\nFull error output:\n${barLine(start = true)}${errorLine(error)}", sourcePos)
case error @ brokenClassPattern(filePath) =>
inError = true
diagnostics ::= Diagnostic.Error(s"$error\nFull error output:\n${barLine(start = true)}${errorLine(error)}", NoSourcePosition)
case summaryPattern() => // Ignored
case line if inError => addToLast(errorLine(line))
case _ =>
addToLast(barLine(start = false))
diagnostics.reverse

protected def compileWithOtherCompiler(compiler: String, files: Array[JFile], flags: TestFlags, targetDir: JFile): TestReporter =
val compilerDir = getCompiler(compiler).toString
Expand All @@ -528,18 +553,20 @@ trait ParallelTesting extends RunnerOrchestration { self =>
else o
}.mkString(JFile.pathSeparator)

val pageWidth = TestConfiguration.pageWidth - 20
val flags1 = flags.copy(defaultClassPath = substituteClasspath(flags.defaultClassPath))
.withClasspath(targetDir.getPath)
.and("-d", targetDir.getPath)
.and("-pagewidth", pageWidth.toString)

val dummyStream = new PrintStream(new ByteArrayOutputStream())
val reporter = TestReporter.reporter(dummyStream, ERROR)
val reporter = TestReporter.reporter(realStdout, logLevel =
if (suppressErrors || suppressAllOutput) ERROR + 1 else ERROR)

val command = Array(compilerDir + "/bin/scalac") ++ flags1.all ++ files.map(_.getPath)
val process = Runtime.getRuntime.exec(command)
val errorsText = Source.fromInputStream(process.getErrorStream).mkString
if process.waitFor() != 0 then
val diagnostics = parseErrors(errorsText, compiler)
val diagnostics = parseErrors(errorsText, compiler, pageWidth)
diagnostics.foreach { diag =>
val context = (new ContextBase).initialCtx
reporter.report(diag)(using context)
Expand Down
4 changes: 3 additions & 1 deletion compiler/test/dotty/tools/vulpix/TestConfiguration.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import java.io.File

object TestConfiguration {

val pageWidth = 120

val noCheckOptions = Array(
"-pagewidth", "120",
"-pagewidth", pageWidth.toString,
"-color:never",
"-Xtarget", defaultTarget
)
Expand Down
5 changes: 5 additions & 0 deletions tests/neg/i14303/A_1_c3.0.0.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
def a: Int = {
3
4
}
def f: Int = match // error // error
1 change: 1 addition & 0 deletions tests/neg/i14303/B_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
def test() = f // error