Skip to content

Commit

Permalink
Revert "Show inlined positions with source code"
Browse files Browse the repository at this point in the history
This temporarily reverts commit e523c8d to fix the
CI, see scala#14406.
  • Loading branch information
smarter committed Feb 5, 2022
1 parent 4c7ec9b commit 4e53c4e
Show file tree
Hide file tree
Showing 28 changed files with 111 additions and 422 deletions.
183 changes: 48 additions & 135 deletions compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ 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
Expand All @@ -27,25 +25,31 @@ trait MessageRendering {
def stripColor(str: String): String =
str.replaceAll("\u001b\\[.*?m", "")

/** 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)
/** 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)
else Nil

/** Get the sourcelines before and after the position, as well as the offset
* for rendering line numbers
*
* @return (lines before error, lines after error, line numbers offset)
*/
private def sourceLines(pos: SourcePosition)(using Context, Level, Offset): (List[String], List[String], Int) = {
def sourceLines(pos: SourcePosition, diagnosticLevel: String)(using Context): (List[String], List[String], Int) = {
assert(pos.exists && pos.source.file.exists)
var maxLen = Int.MinValue
def render(offsetAndLine: (Int, String)): String = {
val (offset1, line) = offsetAndLine
val lineNbr = (pos.source.offsetToLine(offset1) + 1).toString
val prefix = String.format(s"%${offset - 2}s |", lineNbr)
val (offset, line) = offsetAndLine
val lineNbr = pos.source.offsetToLine(offset)
val prefix = s"${lineNbr + 1} |"
maxLen = math.max(maxLen, prefix.length)
val lnum = hl(" " * math.max(0, maxLen - prefix.length - 1) + prefix)
val lnum = hl(diagnosticLevel)(" " * math.max(0, maxLen - prefix.length) + prefix)
lnum + line.stripLineEnd
}

Expand Down Expand Up @@ -73,75 +77,23 @@ trait MessageRendering {
)
}

/** 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 = {
/** The column markers aligned under the error */
def columnMarker(pos: SourcePosition, offset: Int, diagnosticLevel: String)(using Context): String = {
val prefix = " " * (offset - 1)
val padding = pos.startColumnPadding
val carets =
val carets = hl(diagnosticLevel) {
if (pos.startLine == pos.endLine)
"^" * math.max(1, pos.endColumn - pos.startColumn)
else "^"
hl(s"$offsetBox$padding$carets")
}
s"$prefix|$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
*/
private def errorMsg(pos: SourcePosition, msg: String)(using Context, Level, Offset): String = {
def errorMsg(pos: SourcePosition, msg: String, offset: Int)(using Context): 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
Expand All @@ -151,35 +103,35 @@ trait MessageRendering {
}

msg.linesIterator
.map { line => offsetBox + (if line.isEmpty then "" else padding + line) }
.map { line => " " * (offset - 1) + "|" + (if line.isEmpty then "" else padding + line) }
.mkString(EOL)
}

/** The source file path, line and column numbers from the given SourcePosition */
protected def posFileStr(pos: SourcePosition): String =
def posFileStr(pos: SourcePosition): String =
val path = pos.source.file.path
if pos.exists then s"$path:${pos.line + 1}:${pos.column}" else path

/** The separator between errors containing the source file and error type
*
* @return separator containing error location and kind
*/
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)
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 "
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 == "") 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)
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))
}) else ""

/** Explanation rendered under "Explanation" header */
Expand All @@ -194,7 +146,7 @@ trait MessageRendering {
sb.toString
}

private def appendFilterHelp(dia: Diagnostic, sb: mutable.StringBuilder): Unit =
def appendFilterHelp(dia: Diagnostic, sb: mutable.StringBuilder): Unit =
import dia._
val hasId = msg.errorId.errorNumber >= 0
val category = dia match {
Expand All @@ -214,34 +166,17 @@ trait MessageRendering {
/** The whole message rendered from `msg` */
def messageAndPos(dia: Diagnostic)(using Context): String = {
import 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 levelString = diagnosticLevel(dia)
val sb = mutable.StringBuilder()
val posString = posStr(pos, msg, diagnosticLevel(dia))
val posString = posStr(pos, levelString, msg)
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)
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)
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))
}
else sb.append(msg.message)
}
Expand All @@ -251,13 +186,15 @@ trait MessageRendering {
sb.toString
}

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 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 diagnosticLevel(dia: Diagnostic): String =
def diagnosticLevel(dia: Diagnostic): String =
dia match {
case dia: FeatureWarning => "Feature Warning"
case dia: DeprecationWarning => "Deprecation Warning"
Expand All @@ -268,28 +205,4 @@ 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
}
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/Splicer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ object Splicer {
val oldContextClassLoader = Thread.currentThread().getContextClassLoader
Thread.currentThread().setContextClassLoader(classLoader)
try {
val interpreter = new Interpreter(splicePos, classLoader)
val interpreter = new Interpreter(spliceExpansionPos, classLoader)

// Some parts of the macro are evaluated during the unpickling performed in quotedExprToTree
val interpretedExpr = interpreter.interpret[Quotes => scala.quoted.Expr[Any]](tree)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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(call, em"$msg")
errorTree(tpt, em"$msg")
case _ =>
evidence
return searchImplicit(callTypeArgs.head)
Expand Down
1 change: 1 addition & 0 deletions compiler/test-resources/repl/i9227
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ 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
1 change: 1 addition & 0 deletions tests/neg-macros/delegate-match-1.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
| ^
| 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
1 change: 1 addition & 0 deletions tests/neg-macros/delegate-match-2.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
| ^
| 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
1 change: 1 addition & 0 deletions tests/neg-macros/delegate-match-3.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
| ^
| NoMatchingImplicits
| no implicit values were found that match type A
| This location contains code that was inlined from Test_2.scala:3
18 changes: 4 additions & 14 deletions tests/neg-macros/i11386.check
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,11 @@
6 | dummy(0) // error
| ^
| test
|---------------------------------------------------------------------------------------------------------------------
|Inline stack trace
|·····················································································································
|This location contains code that was inlined from Test_2.scala:6
7 | notNull(i)
| ^^^^^^^^^^
·---------------------------------------------------------------------------------------------------------------------
| This location contains code that was inlined from Test_2.scala:6
| This location contains code that was inlined from Macro_1.scala:7
-- Error: tests/neg-macros/i11386/Test_2.scala:8:20 --------------------------------------------------------------------
8 | dummy(int2String(0)) // error
| ^^^^^^^^^^^^^
| test
|---------------------------------------------------------------------------------------------------------------------
|Inline stack trace
|·····················································································································
|This location contains code that was inlined from Test_2.scala:8
7 | notNull(i)
| ^^^^^^^^^^
·---------------------------------------------------------------------------------------------------------------------
| This location contains code that was inlined from Test_2.scala:8
| This location contains code that was inlined from Macro_1.scala:7
16 changes: 0 additions & 16 deletions tests/neg-macros/i13991.check

This file was deleted.

10 changes: 0 additions & 10 deletions tests/neg-macros/i13991/Macro_1.scala

This file was deleted.

6 changes: 0 additions & 6 deletions tests/neg-macros/i13991/Test_2.scala

This file was deleted.

3 changes: 3 additions & 0 deletions tests/neg-macros/i6432.check
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
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
Loading

0 comments on commit 4e53c4e

Please sign in to comment.