From e347416476cd246d0208c7bc9bde86f3364b5327 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 7 Feb 2022 16:58:02 +0100 Subject: [PATCH 1/4] Revert "Revert "Show inlined positions with source code"" This reverts commit 4bcd23b0ba8ae7cfa79b8a12bd462246abaa0857. --- .../dotc/reporting/MessageRendering.scala | 183 +++++++++++++----- .../dotty/tools/dotc/transform/Splicer.scala | 2 +- .../src/dotty/tools/dotc/typer/Inliner.scala | 2 +- compiler/test-resources/repl/i9227 | 1 - tests/neg-macros/delegate-match-1.check | 1 - tests/neg-macros/delegate-match-2.check | 1 - tests/neg-macros/delegate-match-3.check | 1 - tests/neg-macros/i11386.check | 18 +- tests/neg-macros/i13991.check | 16 ++ tests/neg-macros/i13991/Macro_1.scala | 10 + tests/neg-macros/i13991/Test_2.scala | 6 + tests/neg-macros/i6432.check | 3 - tests/neg-macros/i6432b.check | 3 - tests/neg-macros/i6976.check | 8 +- tests/neg-macros/i9014.check | 1 - tests/neg-macros/ill-abort.check | 8 +- .../neg-macros/macro-class-not-found-1.check | 8 +- .../neg-macros/macro-class-not-found-2.check | 8 +- .../neg-macros/macros-in-same-project-6.check | 1 - tests/neg-scalajs/js-enums.check | 6 +- tests/neg/cannot-reduce-inline-match.check | 10 +- tests/neg/i11225.check | 8 +- tests/neg/i13044.check | 166 +++++++++++++--- tests/neg/i13570.check | 11 +- tests/neg/i13991.check | 15 ++ tests/neg/i13991.scala | 11 ++ tests/neg/inline-error-pos.check | 9 +- tests/neg/summonInline.check | 16 +- 28 files changed, 422 insertions(+), 111 deletions(-) create mode 100644 tests/neg-macros/i13991.check create mode 100644 tests/neg-macros/i13991/Macro_1.scala create mode 100644 tests/neg-macros/i13991/Test_2.scala create mode 100644 tests/neg/i13991.check create mode 100644 tests/neg/i13991.scala mode change 100755 => 100644 tests/neg/summonInline.check diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index f5b566f3ba60..1cc98cf75898 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -16,6 +16,8 @@ import scala.annotation.switch import scala.collection.mutable trait MessageRendering { + import Highlight.* + import Offsets.* /** Remove ANSI coloring from `str`, useful for getting real length of * strings @@ -25,15 +27,9 @@ trait MessageRendering { def stripColor(str: String): String = 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. - * - * @return a list of strings with inline locations - */ - def outer(pos: SourcePosition, prefix: String)(using Context): List[String] = - if (pos.outer.exists) - i"$prefix| This location contains code that was inlined from $pos" :: - outer(pos.outer, prefix) + /** List of all the inline calls that surround the position */ + def inlinePosStack(pos: SourcePosition): List[SourcePosition] = + if pos.outer != null && pos.outer.exists then pos :: inlinePosStack(pos.outer) else Nil /** Get the sourcelines before and after the position, as well as the offset @@ -41,15 +37,15 @@ trait MessageRendering { * * @return (lines before error, lines after error, line numbers offset) */ - def sourceLines(pos: SourcePosition, diagnosticLevel: String)(using Context): (List[String], List[String], Int) = { + private def sourceLines(pos: SourcePosition)(using Context, Level, Offset): (List[String], List[String], Int) = { assert(pos.exists && pos.source.file.exists) var maxLen = Int.MinValue def render(offsetAndLine: (Int, String)): String = { - val (offset, line) = offsetAndLine - val lineNbr = pos.source.offsetToLine(offset) - val prefix = s"${lineNbr + 1} |" + val (offset1, line) = offsetAndLine + val lineNbr = (pos.source.offsetToLine(offset1) + 1).toString + val prefix = String.format(s"%${offset - 2}s |", lineNbr) maxLen = math.max(maxLen, prefix.length) - val lnum = hl(diagnosticLevel)(" " * math.max(0, maxLen - prefix.length) + prefix) + val lnum = hl(" " * math.max(0, maxLen - prefix.length - 1) + prefix) lnum + line.stripLineEnd } @@ -77,23 +73,75 @@ trait MessageRendering { ) } - /** The column markers aligned under the error */ - def columnMarker(pos: SourcePosition, offset: Int, diagnosticLevel: String)(using Context): String = { - val prefix = " " * (offset - 1) + /** Generate box containing the report title + * + * ``` + * -- Error: source.scala --------------------- + * ``` + */ + private def boxTitle(title: String)(using Context, Level, Offset): String = + val pageWidth = ctx.settings.pageWidth.value + val line = "-" * (pageWidth - title.length - 4) + hl(s"-- $title $line") + + /** The position markers aligned under the error + * + * ``` + * | ^^^^^ + * ``` + */ + private def positionMarker(pos: SourcePosition)(using Context, Level, Offset): String = { val padding = pos.startColumnPadding - val carets = hl(diagnosticLevel) { + val carets = if (pos.startLine == pos.endLine) "^" * math.max(1, pos.endColumn - pos.startColumn) else "^" - } - s"$prefix|$padding$carets" + hl(s"$offsetBox$padding$carets") } + /** The horizontal line with the given offset + * + * ``` + * | + * ``` + */ + private def offsetBox(using Context, Level, Offset): String = + val prefix = " " * (offset - 1) + hl(s"$prefix|") + + /** The end of a box section + * + * ``` + * |--------------- + * ``` + * Or if there `soft` is true, + * ``` + * |··············· + * ``` + */ + private def newBox(soft: Boolean = false)(using Context, Level, Offset): String = + val pageWidth = ctx.settings.pageWidth.value + val prefix = " " * (offset - 1) + val line = (if soft then "·" else "-") * (pageWidth - offset) + hl(s"$prefix|$line") + + /** The end of a box section + * + * ``` + * ·---------------- + * ``` + */ + private def endBox(using Context, Level, Offset): String = + val pageWidth = ctx.settings.pageWidth.value + val prefix = " " * (offset - 1) + val line = "-" * (pageWidth - offset) + hl(s"${prefix}·$line") + /** The error message (`msg`) aligned under `pos` * * @return aligned error message */ - def errorMsg(pos: SourcePosition, msg: String, offset: Int)(using Context): String = { + private def errorMsg(pos: SourcePosition, msg: String)(using Context, Level, Offset): String = { val padding = msg.linesIterator.foldLeft(pos.startColumnPadding) { (pad, line) => val lineLength = stripColor(line).length val maxPad = math.max(0, ctx.settings.pageWidth.value - offset - lineLength) - offset @@ -103,12 +151,12 @@ trait MessageRendering { } msg.linesIterator - .map { line => " " * (offset - 1) + "|" + (if line.isEmpty then "" else padding + line) } + .map { line => offsetBox + (if line.isEmpty then "" else padding + line) } .mkString(EOL) } /** The source file path, line and column numbers from the given SourcePosition */ - def posFileStr(pos: SourcePosition): String = + protected def posFileStr(pos: SourcePosition): String = val path = pos.source.file.path if pos.exists then s"$path:${pos.line + 1}:${pos.column}" else path @@ -116,22 +164,22 @@ trait MessageRendering { * * @return separator containing error location and kind */ - def posStr(pos: SourcePosition, diagnosticLevel: String, message: Message)(using Context): String = - if (pos.source != NoSourcePosition.source) hl(diagnosticLevel)({ - val fileAndPos = posFileStr(pos.nonInlined) - val file = if fileAndPos.isEmpty || fileAndPos.endsWith(" ") then fileAndPos else s"$fileAndPos " + private def posStr(pos: SourcePosition, message: Message, diagnosticString: String)(using Context, Level, Offset): String = + if (pos.source != NoSourcePosition.source) hl({ + val realPos = pos.nonInlined + val fileAndPos = posFileStr(realPos) val errId = if (message.errorId ne ErrorMessageID.NoExplanationID) { val errorNumber = message.errorId.errorNumber s"[E${"0" * (3 - errorNumber.toString.length) + errorNumber}] " } else "" val kind = - if (message.kind == "") diagnosticLevel - else s"${message.kind} $diagnosticLevel" - val prefix = s"-- ${errId}${kind}: $file" - - prefix + - ("-" * math.max(ctx.settings.pageWidth.value - stripColor(prefix).length, 0)) + if (message.kind == "") diagnosticString + else s"${message.kind} $diagnosticString" + val title = + if fileAndPos.isEmpty then s"$errId$kind:" // this happens in dotty.tools.repl.ScriptedTests // TODO add name of source or remove `:` (and update test files) + else s"$errId$kind: $fileAndPos" + boxTitle(title) }) else "" /** Explanation rendered under "Explanation" header */ @@ -146,7 +194,7 @@ trait MessageRendering { sb.toString } - def appendFilterHelp(dia: Diagnostic, sb: mutable.StringBuilder): Unit = + private def appendFilterHelp(dia: Diagnostic, sb: mutable.StringBuilder): Unit = import dia._ val hasId = msg.errorId.errorNumber >= 0 val category = dia match { @@ -166,17 +214,34 @@ trait MessageRendering { /** The whole message rendered from `msg` */ def messageAndPos(dia: Diagnostic)(using Context): String = { import dia._ - val levelString = diagnosticLevel(dia) + val pos1 = pos.nonInlined + val inlineStack = inlinePosStack(pos).filter(_ != pos1) + val maxLineNumber = + if pos.exists then (pos1 :: inlineStack).map(_.endLine).max + 1 + else 0 + given Level = Level(level) + given Offset = Offset(maxLineNumber.toString.length + 2) val sb = mutable.StringBuilder() - val posString = posStr(pos, levelString, msg) + val posString = posStr(pos, msg, diagnosticLevel(dia)) if (posString.nonEmpty) sb.append(posString).append(EOL) if (pos.exists) { val pos1 = pos.nonInlined if (pos1.exists && pos1.source.file.exists) { - val (srcBefore, srcAfter, offset) = sourceLines(pos1, levelString) - val marker = columnMarker(pos1, offset, levelString) - val err = errorMsg(pos1, msg.message, offset) - sb.append((srcBefore ::: marker :: err :: outer(pos, " " * (offset - 1)) ::: srcAfter).mkString(EOL)) + val (srcBefore, srcAfter, offset) = sourceLines(pos1) + val marker = positionMarker(pos1) + val err = errorMsg(pos1, msg.message) + sb.append((srcBefore ::: marker :: err :: srcAfter).mkString(EOL)) + + if inlineStack.nonEmpty then + sb.append(EOL).append(newBox()) + sb.append(EOL).append(offsetBox).append(i"Inline stack trace") + for inlinedPos <- inlineStack if inlinedPos != pos1 do + val (srcBefore, srcAfter, offset) = sourceLines(inlinedPos) + val marker = positionMarker(inlinedPos) + sb.append(EOL).append(newBox(soft = true)) + sb.append(EOL).append(offsetBox).append(i"This location contains code that was inlined from $pos") + sb.append(EOL).append((srcBefore ::: marker :: srcAfter).mkString(EOL)) + sb.append(EOL).append(endBox) } else sb.append(msg.message) } @@ -186,15 +251,13 @@ trait MessageRendering { sb.toString } - def hl(diagnosticLevel: String)(str: String)(using Context): String = diagnosticLevel match { - case "Info" => Blue(str).show - case "Error" => Red(str).show - case _ => - assert(diagnosticLevel.contains("Warning")) - Yellow(str).show - } + private def hl(str: String)(using Context, Level): String = + summon[Level].value match + case interfaces.Diagnostic.ERROR => Red(str).show + case interfaces.Diagnostic.WARNING => Yellow(str).show + case interfaces.Diagnostic.INFO => Blue(str).show - def diagnosticLevel(dia: Diagnostic): String = + private def diagnosticLevel(dia: Diagnostic): String = dia match { case dia: FeatureWarning => "Feature Warning" case dia: DeprecationWarning => "Deprecation Warning" @@ -205,4 +268,28 @@ trait MessageRendering { case interfaces.Diagnostic.WARNING => "Warning" case interfaces.Diagnostic.INFO => "Info" } + +} + +private object Highlight { + opaque type Level = Int + extension (level: Level) def value: Int = level + object Level: + def apply(level: Int): Level = level +} + +/** Size of the left offset added by the box + * + * ``` + * -- Error: ... ------------ + * 4 | foo + * | ^^^ + * ^^^ // size of this offset + * ``` + */ +private object Offsets { + opaque type Offset = Int + def offset(using o: Offset): Int = o + object Offset: + def apply(level: Int): Offset = level } diff --git a/compiler/src/dotty/tools/dotc/transform/Splicer.scala b/compiler/src/dotty/tools/dotc/transform/Splicer.scala index 49b6f5564620..dcd5b8d8c4b5 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splicer.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splicer.scala @@ -49,7 +49,7 @@ object Splicer { val oldContextClassLoader = Thread.currentThread().getContextClassLoader Thread.currentThread().setContextClassLoader(classLoader) try { - val interpreter = new Interpreter(spliceExpansionPos, classLoader) + val interpreter = new Interpreter(splicePos, classLoader) // Some parts of the macro are evaluated during the unpickling performed in quotedExprToTree val interpretedExpr = interpreter.interpret[Quotes => scala.quoted.Expr[Any]](tree) diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 722e3abfec85..c99ccbd24428 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -853,7 +853,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { evidence.tpe match case fail: Implicits.SearchFailureType => val msg = evTyper.missingArgMsg(evidence, tpt.tpe, "") - errorTree(tpt, em"$msg") + errorTree(call, em"$msg") case _ => evidence return searchImplicit(callTypeArgs.head) diff --git a/compiler/test-resources/repl/i9227 b/compiler/test-resources/repl/i9227 index 45d1731dae39..40f9248898a2 100644 --- a/compiler/test-resources/repl/i9227 +++ b/compiler/test-resources/repl/i9227 @@ -3,5 +3,4 @@ scala> import scala.quoted._; inline def myMacro[T]: Unit = ${ myMacroImpl[T] }; 1 | import scala.quoted._; inline def myMacro[T]: Unit = ${ myMacroImpl[T] }; def myMacroImpl[T](using Quotes): Expr[Unit] = '{}; println(myMacro[Int]) | ^^^^^^^^^^^^ | Cannot call macro method myMacroImpl defined in the same source file - | This location contains code that was inlined from rs$line$1:1 1 error found diff --git a/tests/neg-macros/delegate-match-1.check b/tests/neg-macros/delegate-match-1.check index 6d88d021416f..93b20beba183 100644 --- a/tests/neg-macros/delegate-match-1.check +++ b/tests/neg-macros/delegate-match-1.check @@ -4,4 +4,3 @@ | ^ | AmbiguousImplicits | both value a1 in class Test1 and value a2 in class Test1 match type A - | This location contains code that was inlined from Test_2.scala:6 diff --git a/tests/neg-macros/delegate-match-2.check b/tests/neg-macros/delegate-match-2.check index 112e5ee00474..e26742452b5b 100644 --- a/tests/neg-macros/delegate-match-2.check +++ b/tests/neg-macros/delegate-match-2.check @@ -4,4 +4,3 @@ | ^ | DivergingImplicit | method a1 in class Test produces a diverging implicit search when trying to match type A - | This location contains code that was inlined from Test_2.scala:5 diff --git a/tests/neg-macros/delegate-match-3.check b/tests/neg-macros/delegate-match-3.check index 278aa92a4117..2b6fda278fda 100644 --- a/tests/neg-macros/delegate-match-3.check +++ b/tests/neg-macros/delegate-match-3.check @@ -4,4 +4,3 @@ | ^ | NoMatchingImplicits | no implicit values were found that match type A - | This location contains code that was inlined from Test_2.scala:3 diff --git a/tests/neg-macros/i11386.check b/tests/neg-macros/i11386.check index 0377ca6389db..1cce199159a5 100644 --- a/tests/neg-macros/i11386.check +++ b/tests/neg-macros/i11386.check @@ -3,11 +3,21 @@ 6 | dummy(0) // error | ^ | test - | This location contains code that was inlined from Test_2.scala:6 - | This location contains code that was inlined from Macro_1.scala:7 + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |····················································································································· + |This location contains code that was inlined from Test_2.scala:6 +7 | notNull(i) + | ^^^^^^^^^^ + ·--------------------------------------------------------------------------------------------------------------------- -- Error: tests/neg-macros/i11386/Test_2.scala:8:20 -------------------------------------------------------------------- 8 | dummy(int2String(0)) // error | ^^^^^^^^^^^^^ | test - | This location contains code that was inlined from Test_2.scala:8 - | This location contains code that was inlined from Macro_1.scala:7 + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |····················································································································· + |This location contains code that was inlined from Test_2.scala:8 +7 | notNull(i) + | ^^^^^^^^^^ + ·--------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg-macros/i13991.check b/tests/neg-macros/i13991.check new file mode 100644 index 000000000000..15f45af227e5 --- /dev/null +++ b/tests/neg-macros/i13991.check @@ -0,0 +1,16 @@ + +-- Error: tests/neg-macros/i13991/Test_2.scala:6:5 --------------------------------------------------------------------- +6 | v2 // error + | ^^ + | Error + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |····················································································································· + |This location contains code that was inlined from Test_2.scala:3 +3 | inline def v2 = InlineMac.sample("foo") + | ^^^^^ + |····················································································································· + |This location contains code that was inlined from Test_2.scala:3 +3 | inline def v2 = InlineMac.sample("foo") + | ^^^^^^^^^^^^^^^^^^^^^^^ + ·--------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg-macros/i13991/Macro_1.scala b/tests/neg-macros/i13991/Macro_1.scala new file mode 100644 index 000000000000..76cfa93cdde5 --- /dev/null +++ b/tests/neg-macros/i13991/Macro_1.scala @@ -0,0 +1,10 @@ +import scala.quoted.* + +object InlineMac: + + inline def sample(inline expr: String): Int = + ${ sampleImpl('expr) } + + def sampleImpl(expr: Expr[String])(using Quotes): Expr[Int] = + import quotes.reflect.* + report.errorAndAbort("Error", expr) diff --git a/tests/neg-macros/i13991/Test_2.scala b/tests/neg-macros/i13991/Test_2.scala new file mode 100644 index 000000000000..572ad324b129 --- /dev/null +++ b/tests/neg-macros/i13991/Test_2.scala @@ -0,0 +1,6 @@ +object Main: + def main(args: Array[String]): Unit = + inline def v2 = InlineMac.sample("foo") + inline def v1 = v2 + + v2 // error diff --git a/tests/neg-macros/i6432.check b/tests/neg-macros/i6432.check index 0e01f99be404..2ea6f3ba0300 100644 --- a/tests/neg-macros/i6432.check +++ b/tests/neg-macros/i6432.check @@ -3,14 +3,11 @@ 4 | foo"abc${"123"}xyz${"456"}fgh" // error // error // error | ^^^ | abc - | This location contains code that was inlined from Test_2.scala:4 -- Error: tests/neg-macros/i6432/Test_2.scala:4:17 --------------------------------------------------------------------- 4 | foo"abc${"123"}xyz${"456"}fgh" // error // error // error | ^^^ | xyz - | This location contains code that was inlined from Test_2.scala:4 -- Error: tests/neg-macros/i6432/Test_2.scala:4:28 --------------------------------------------------------------------- 4 | foo"abc${"123"}xyz${"456"}fgh" // error // error // error | ^^^ | fgh - | This location contains code that was inlined from Test_2.scala:4 diff --git a/tests/neg-macros/i6432b.check b/tests/neg-macros/i6432b.check index 4dd1be84fa3c..395d089c92e9 100644 --- a/tests/neg-macros/i6432b.check +++ b/tests/neg-macros/i6432b.check @@ -3,14 +3,11 @@ 4 | foo"""abc${"123"}xyz${"456"}fgh""" // error // error // error | ^^^ | abc - | This location contains code that was inlined from Test_2.scala:4 -- Error: tests/neg-macros/i6432b/Test_2.scala:4:19 -------------------------------------------------------------------- 4 | foo"""abc${"123"}xyz${"456"}fgh""" // error // error // error | ^^^ | xyz - | This location contains code that was inlined from Test_2.scala:4 -- Error: tests/neg-macros/i6432b/Test_2.scala:4:30 -------------------------------------------------------------------- 4 | foo"""abc${"123"}xyz${"456"}fgh""" // error // error // error | ^^^ | fgh - | This location contains code that was inlined from Test_2.scala:4 diff --git a/tests/neg-macros/i6976.check b/tests/neg-macros/i6976.check index 2057e55550b4..b67f05960a79 100644 --- a/tests/neg-macros/i6976.check +++ b/tests/neg-macros/i6976.check @@ -6,4 +6,10 @@ | scala.MatchError: Inlined(EmptyTree,List(),Literal(Constant(2))) (of class dotty.tools.dotc.ast.Trees$Inlined) | at playground.macros$.mcrImpl(Macro_1.scala:10) | - | This location contains code that was inlined from Test_2.scala:5 + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |····················································································································· + |This location contains code that was inlined from Macro_1.scala:6 +6 | inline def mcr(x: => Any) = ${mcrImpl('x)} + | ^^^^^^^^^^^^^^ + ·--------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg-macros/i9014.check b/tests/neg-macros/i9014.check index 509eac067fc8..c0d08a42ef2a 100644 --- a/tests/neg-macros/i9014.check +++ b/tests/neg-macros/i9014.check @@ -3,4 +3,3 @@ 1 |val tests = summon[Bar] // error | ^ | Failed to expand! - | This location contains code that was inlined from Test_2.scala:1 diff --git a/tests/neg-macros/ill-abort.check b/tests/neg-macros/ill-abort.check index 25d7654b1b69..2aa9d3396e53 100644 --- a/tests/neg-macros/ill-abort.check +++ b/tests/neg-macros/ill-abort.check @@ -3,4 +3,10 @@ 1 |def test = fail() // error | ^^^^^^ |Macro expansion was aborted by the macro without any errors reported. Macros should issue errors to end-users to facilitate debugging when aborting a macro expansion. - | This location contains code that was inlined from quoted_1.scala:3 + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |····················································································································· + |This location contains code that was inlined from quoted_1.scala:3 +3 |inline def fail(): Unit = ${ impl } + | ^^^^^^^^^ + ·--------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg-macros/macro-class-not-found-1.check b/tests/neg-macros/macro-class-not-found-1.check index 445523c6ade2..08ba5b99f0b8 100644 --- a/tests/neg-macros/macro-class-not-found-1.check +++ b/tests/neg-macros/macro-class-not-found-1.check @@ -5,4 +5,10 @@ | java.lang.NoClassDefFoundError | at Foo$.aMacroImplementation(Foo.scala:8) | - | This location contains code that was inlined from Bar.scala:4 + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |····················································································································· + |This location contains code that was inlined from Foo.scala:5 +5 | inline def myMacro(): Unit = ${ aMacroImplementation } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + ·--------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg-macros/macro-class-not-found-2.check b/tests/neg-macros/macro-class-not-found-2.check index 3cb7506e6bb2..d4ed8f222ba0 100644 --- a/tests/neg-macros/macro-class-not-found-2.check +++ b/tests/neg-macros/macro-class-not-found-2.check @@ -5,4 +5,10 @@ | java.lang.NoClassDefFoundError: this.is.not.a.Class | at Foo$.aMacroImplementation(Foo.scala:8) | - | This location contains code that was inlined from Bar.scala:4 + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |····················································································································· + |This location contains code that was inlined from Foo.scala:5 +5 | inline def myMacro(): Unit = ${ aMacroImplementation } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + ·--------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg-macros/macros-in-same-project-6.check b/tests/neg-macros/macros-in-same-project-6.check index 485f5062db92..17f696508259 100644 --- a/tests/neg-macros/macros-in-same-project-6.check +++ b/tests/neg-macros/macros-in-same-project-6.check @@ -2,4 +2,3 @@ 4 | Foo.myMacro() // error | ^^^^^^^^^^^^^ | some error - | This location contains code that was inlined from Bar.scala:4 diff --git a/tests/neg-scalajs/js-enums.check b/tests/neg-scalajs/js-enums.check index eb358f16e57a..e54b2a5af2da 100644 --- a/tests/neg-scalajs/js-enums.check +++ b/tests/neg-scalajs/js-enums.check @@ -4,9 +4,9 @@ |MyEnum extends scala.reflect.Enum which does not extend js.Any. 5 | case Foo -- Error: tests/neg-scalajs/js-enums.scala:9:5 ------------------------------------------------------------------------- -7 |@js.native -8 |@JSGlobal -9 |enum MyEnumNative extends js.Object: // error + 7 |@js.native + 8 |@JSGlobal + 9 |enum MyEnumNative extends js.Object: // error |^ |MyEnumNative extends scala.reflect.Enum which does not extend js.Any. 10 | case Bar diff --git a/tests/neg/cannot-reduce-inline-match.check b/tests/neg/cannot-reduce-inline-match.check index ceca40a74cbd..e35066949333 100644 --- a/tests/neg/cannot-reduce-inline-match.check +++ b/tests/neg/cannot-reduce-inline-match.check @@ -4,4 +4,12 @@ | cannot reduce inline match with | scrutinee: "f" : ("f" : String) | patterns : case _:Int - | This location contains code that was inlined from cannot-reduce-inline-match.scala:3 + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |····················································································································· + |This location contains code that was inlined from cannot-reduce-inline-match.scala:3 +3 | inline x match { + | ^ +4 | case _: Int => +5 | } + ·--------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg/i11225.check b/tests/neg/i11225.check index 60805a27b22d..0aa5f720e24b 100644 --- a/tests/neg/i11225.check +++ b/tests/neg/i11225.check @@ -42,4 +42,10 @@ 30 | var x7: Int = uni // error | ^^^ | `uninitialized` can only be used as the right hand side of a mutable field definition - | This location contains code that was inlined from i11225.scala:25 + |-------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |···················································································································· + |This location contains code that was inlined from i11225.scala:25 +25 | transparent inline def uni = uninitialized + | ^^^^^^^^^^^^^ + ·-------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg/i13044.check b/tests/neg/i13044.check index 87b8a1fe9ae2..b3e278792148 100644 --- a/tests/neg/i13044.check +++ b/tests/neg/i13044.check @@ -4,41 +4,143 @@ | given instance gen is declared as `inline`, but was not inlined | | Try increasing `-Xmax-inlines` above 32 - | This location contains code that was inlined from i13044.scala:17 - | This location contains code that was inlined from i13044.scala:31 - | This location contains code that was inlined from i13044.scala:37 - | This location contains code that was inlined from i13044.scala:17 - | This location contains code that was inlined from i13044.scala:31 - | This location contains code that was inlined from i13044.scala:37 - | This location contains code that was inlined from i13044.scala:17 - | This location contains code that was inlined from i13044.scala:31 - | This location contains code that was inlined from i13044.scala:37 - | This location contains code that was inlined from i13044.scala:17 - | This location contains code that was inlined from i13044.scala:31 - | This location contains code that was inlined from i13044.scala:37 - | This location contains code that was inlined from i13044.scala:17 - | This location contains code that was inlined from i13044.scala:18 - | This location contains code that was inlined from i13044.scala:31 - | This location contains code that was inlined from i13044.scala:37 + |-------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +17 | val builder = summonInline[Schema[t]].asInstanceOf[Schema[Any]] + | ^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +31 | lazy val fields = recurse[m.MirroredElemTypes] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +37 | inline given gen[A]: Schema[A] = derived + | ^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +17 | val builder = summonInline[Schema[t]].asInstanceOf[Schema[Any]] + | ^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +31 | lazy val fields = recurse[m.MirroredElemTypes] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +37 | inline given gen[A]: Schema[A] = derived + | ^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +17 | val builder = summonInline[Schema[t]].asInstanceOf[Schema[Any]] + | ^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +31 | lazy val fields = recurse[m.MirroredElemTypes] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +37 | inline given gen[A]: Schema[A] = derived + | ^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +17 | val builder = summonInline[Schema[t]].asInstanceOf[Schema[Any]] + | ^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +31 | lazy val fields = recurse[m.MirroredElemTypes] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +37 | inline given gen[A]: Schema[A] = derived + | ^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +17 | val builder = summonInline[Schema[t]].asInstanceOf[Schema[Any]] + | ^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +18 | builder :: recurse[ts] + | ^^^^^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +31 | lazy val fields = recurse[m.MirroredElemTypes] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:17 +37 | inline given gen[A]: Schema[A] = derived + | ^^^^^^^ + ·-------------------------------------------------------------------------------------------------------------------- -- Error: tests/neg/i13044.scala:50:40 --------------------------------------------------------------------------------- 50 | implicit def typeSchema: Schema[A] = Schema.gen // error // error | ^^^^^^^^^^ | method recurse is declared as `inline`, but was not inlined | | Try increasing `-Xmax-inlines` above 32 - | This location contains code that was inlined from i13044.scala:18 - | This location contains code that was inlined from i13044.scala:31 - | This location contains code that was inlined from i13044.scala:37 - | This location contains code that was inlined from i13044.scala:17 - | This location contains code that was inlined from i13044.scala:31 - | This location contains code that was inlined from i13044.scala:37 - | This location contains code that was inlined from i13044.scala:17 - | This location contains code that was inlined from i13044.scala:31 - | This location contains code that was inlined from i13044.scala:37 - | This location contains code that was inlined from i13044.scala:17 - | This location contains code that was inlined from i13044.scala:31 - | This location contains code that was inlined from i13044.scala:37 - | This location contains code that was inlined from i13044.scala:17 - | This location contains code that was inlined from i13044.scala:18 - | This location contains code that was inlined from i13044.scala:31 - | This location contains code that was inlined from i13044.scala:37 + |-------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +18 | builder :: recurse[ts] + | ^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +31 | lazy val fields = recurse[m.MirroredElemTypes] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +37 | inline given gen[A]: Schema[A] = derived + | ^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +17 | val builder = summonInline[Schema[t]].asInstanceOf[Schema[Any]] + | ^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +31 | lazy val fields = recurse[m.MirroredElemTypes] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +37 | inline given gen[A]: Schema[A] = derived + | ^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +17 | val builder = summonInline[Schema[t]].asInstanceOf[Schema[Any]] + | ^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +31 | lazy val fields = recurse[m.MirroredElemTypes] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +37 | inline given gen[A]: Schema[A] = derived + | ^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +17 | val builder = summonInline[Schema[t]].asInstanceOf[Schema[Any]] + | ^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +31 | lazy val fields = recurse[m.MirroredElemTypes] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +37 | inline given gen[A]: Schema[A] = derived + | ^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +17 | val builder = summonInline[Schema[t]].asInstanceOf[Schema[Any]] + | ^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +18 | builder :: recurse[ts] + | ^^^^^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +31 | lazy val fields = recurse[m.MirroredElemTypes] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13044.scala:18 +37 | inline given gen[A]: Schema[A] = derived + | ^^^^^^^ + ·-------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg/i13570.check b/tests/neg/i13570.check index 90e29476b7b1..cf1649b5f4a6 100644 --- a/tests/neg/i13570.check +++ b/tests/neg/i13570.check @@ -6,4 +6,13 @@ | patterns : case s @ _:Seq[Int] if s.isEmpty | case s @ _:Seq[Int] | case _ - | This location contains code that was inlined from i13570.scala:3 + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |····················································································································· + |This location contains code that was inlined from i13570.scala:3 +3 | inline seq match + | ^ +4 | case s: Seq[Int] if s.isEmpty => println("seq is empty") +5 | case s: Seq[Int] => println("seq is not empty") +6 | case _ => println("somthing hinky happened") + ·--------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg/i13991.check b/tests/neg/i13991.check new file mode 100644 index 000000000000..fd092b759c2b --- /dev/null +++ b/tests/neg/i13991.check @@ -0,0 +1,15 @@ +-- Error: tests/neg/i13991.scala:5:7 ----------------------------------------------------------------------------------- + 5 | first[String] // error // before line 10 to test alignment of the error message `|` + | ^^^^^^^^^^^^^ + | no implicit argument of type Foo[String] was found + |-------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |···················································································································· + |This location contains code that was inlined from i13991.scala:8 + 8 | compiletime.summonInline[Foo[A]].foo + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + |···················································································································· + |This location contains code that was inlined from i13991.scala:8 +11 | second[A] + 42 // after line 10 to test alignment of the error message `|` + | ^^^^^^^^^ + ·-------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg/i13991.scala b/tests/neg/i13991.scala new file mode 100644 index 000000000000..af15891e82d3 --- /dev/null +++ b/tests/neg/i13991.scala @@ -0,0 +1,11 @@ +trait Foo[X]: + def foo: Int + +def foo = + first[String] // error // before line 10 to test alignment of the error message `|` + +inline def second[A]: Int = + compiletime.summonInline[Foo[A]].foo + +inline def first[A]: Int = + second[A] + 42 // after line 10 to test alignment of the error message `|` diff --git a/tests/neg/inline-error-pos.check b/tests/neg/inline-error-pos.check index 121684fe14d6..1d65175c6c39 100644 --- a/tests/neg/inline-error-pos.check +++ b/tests/neg/inline-error-pos.check @@ -4,4 +4,11 @@ | cannot reduce inline match with | scrutinee: 2 : (2 : Int) | patterns : case 1 - | This location contains code that was inlined from inline-error-pos.scala:3 + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |····················································································································· + |This location contains code that was inlined from inline-error-pos.scala:3 +3 | inline x match + | ^ +4 | case 1 => 9 + ·--------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg/summonInline.check b/tests/neg/summonInline.check old mode 100755 new mode 100644 index d118299d6dc5..db9b6968ee43 --- a/tests/neg/summonInline.check +++ b/tests/neg/summonInline.check @@ -2,9 +2,21 @@ 19 |val missing1 = summonInlineCheck(1) // error | ^^^^^^^^^^^^^^^^^^^^ | Missing One - | This location contains code that was inlined from summonInline.scala:15 + |-------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |···················································································································· + |This location contains code that was inlined from summonInline.scala:15 +15 | case 1 => summonInline[Missing1] + | ^^^^^^^^^^^^^^^^^^^^^^ + ·-------------------------------------------------------------------------------------------------------------------- -- Error: tests/neg/summonInline.scala:20:32 --------------------------------------------------------------------------- 20 |val missing2 = summonInlineCheck(2) // error | ^^^^^^^^^^^^^^^^^^^^ | Missing Two - | This location contains code that was inlined from summonInline.scala:16 + |-------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |···················································································································· + |This location contains code that was inlined from summonInline.scala:16 +16 | case 2 => summonInline[Missing2] + | ^^^^^^^^^^^^^^^^^^^^^^ + ·-------------------------------------------------------------------------------------------------------------------- From 733af41ab568edb59d42bb09d51336c618778f6e Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 7 Feb 2022 17:19:25 +0100 Subject: [PATCH 2/4] Check if source exists for inline positions --- .../src/dotty/tools/dotc/reporting/MessageRendering.scala | 7 ++++--- project/scripts/cmdTests | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index 1cc98cf75898..b8f2d763fc83 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -236,11 +236,12 @@ trait MessageRendering { sb.append(EOL).append(newBox()) sb.append(EOL).append(offsetBox).append(i"Inline stack trace") for inlinedPos <- inlineStack if inlinedPos != pos1 do - val (srcBefore, srcAfter, offset) = sourceLines(inlinedPos) - val marker = positionMarker(inlinedPos) sb.append(EOL).append(newBox(soft = true)) sb.append(EOL).append(offsetBox).append(i"This location contains code that was inlined from $pos") - sb.append(EOL).append((srcBefore ::: marker :: srcAfter).mkString(EOL)) + if inlinedPos.source.file.exists then + val (srcBefore, srcAfter, _) = sourceLines(inlinedPos) + val marker = positionMarker(inlinedPos) + sb.append(EOL).append((srcBefore ::: marker :: srcAfter).mkString(EOL)) sb.append(EOL).append(endBox) } else sb.append(msg.message) diff --git a/project/scripts/cmdTests b/project/scripts/cmdTests index 659b2808ed07..7eee1439a3a8 100755 --- a/project/scripts/cmdTests +++ b/project/scripts/cmdTests @@ -56,6 +56,7 @@ cp tests/neg/i6371/B_2.scala $OUT/B.scala "$SBT" "scalac $OUT/A.scala -d $OUT1" rm $OUT/A.scala "$SBT" "scalac -classpath $OUT1 -d $OUT1 $OUT/B.scala" > "$tmp" 2>&1 || echo "ok" +cat "$tmp" # for debugging grep -qe "B.scala:2:7" "$tmp" grep -qe "This location contains code that was inlined from A.scala:3" "$tmp" From 20e7269f78916026fc98a7609b5c6a0bc4f8c1e3 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 7 Feb 2022 17:26:43 +0100 Subject: [PATCH 3/4] Re-enable missing cmdTests It might have been disabled by mistake because bootstrapCmdTests was assumed to be the set of tests for the bootstrapped compiler. The second is an extension for the second with tests that can only be run on the bootstrapped compiler. It is now renamed to bootstrappedOnlyCmdTests to make sure we avoid this potential confusion. Fixes #14428 --- .github/workflows/ci.yaml | 6 ++++-- .../scripts/{bootstrapCmdTests => bootstrappedOnlyCmdTests} | 0 tests/pos/i12973.scala | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) rename project/scripts/{bootstrapCmdTests => bootstrappedOnlyCmdTests} (100%) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2847bfd578b9..d9da3baee124 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -112,7 +112,8 @@ jobs: - name: Cmd Tests run: | ./project/scripts/sbt ";dist/pack; scala3-bootstrapped/compile; scala3-bootstrapped/test;sjsSandbox/run;sjsSandbox/test;sjsJUnitTests/test;sjsCompilerTests/test ;sbt-test/scripted scala2-compat/* ;configureIDE ;stdlib-bootstrapped/test:run ;stdlib-bootstrapped-tasty-tests/test; scala3-compiler-bootstrapped/scala3CompilerCoursierTest:test" - ./project/scripts/bootstrapCmdTests + ./project/scripts/cmdTests + ./project/scripts/bootstrappedOnlyCmdTests - name: MiMa run: | @@ -447,7 +448,8 @@ jobs: - name: Test run: | ./project/scripts/sbt ";dist/pack ;scala3-bootstrapped/compile ;scala3-bootstrapped/test;sjsSandbox/run;sjsSandbox/test;sjsJUnitTests/test;sjsCompilerTests/test ;sbt-test/scripted scala2-compat/* ;configureIDE ;stdlib-bootstrapped/test:run ;stdlib-bootstrapped-tasty-tests/test" - ./project/scripts/bootstrapCmdTests + ./project/scripts/cmdTests + ./project/scripts/bootstrappedOnlyCmdTests publish_nightly: runs-on: [self-hosted, Linux] diff --git a/project/scripts/bootstrapCmdTests b/project/scripts/bootstrappedOnlyCmdTests similarity index 100% rename from project/scripts/bootstrapCmdTests rename to project/scripts/bootstrappedOnlyCmdTests diff --git a/tests/pos/i12973.scala b/tests/pos/i12973.scala index 9cda7dbc120b..53c6476d798e 100644 --- a/tests/pos/i12973.scala +++ b/tests/pos/i12973.scala @@ -1,4 +1,4 @@ -// Compiled and placed on the REPL classpath in the bootstrapCmdTests script +// Compiled and placed on the REPL classpath in the bootstrappedOnlyCmdTests script // to test that launching the REPL with `scala -cp ` works (issue #12973) case class Bug12973(): def check = s"$productPrefix is fixed" From 8f38788dbb3405182275bb32440e6b4891ca2f22 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 8 Feb 2022 13:53:13 +0100 Subject: [PATCH 4/4] Comment out debug code --- project/scripts/cmdTests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/scripts/cmdTests b/project/scripts/cmdTests index 7eee1439a3a8..6a175db23e99 100755 --- a/project/scripts/cmdTests +++ b/project/scripts/cmdTests @@ -33,7 +33,7 @@ echo "testing that paths SourceFile annotations are relativized" clear_out "$OUT" "$SBT" "scalac -d $OUT/out.jar -sourceroot tests/pos $(pwd)/tests/pos/i10430/lib.scala $(pwd)/tests/pos/i10430/app.scala" "$SBT" "scalac -print-tasty -color:never $OUT/out.jar" > "$tmp" -cat "$tmp" # for debugging +# cat "$tmp" # for debugging grep -q ": i10430/lib.scala" "$tmp" grep -q ": i10430/app.scala" "$tmp" grep -q "[i10430/lib.scala]" "$tmp"