Skip to content

Commit a0dcc08

Browse files
authored
Merge pull request #1606 from felixmulder/topic/fix-inline-context
Fix #1604: print outer context if applicable
2 parents 26e98d3 + f9328ba commit a0dcc08

File tree

3 files changed

+64
-37
lines changed

3 files changed

+64
-37
lines changed

src/dotty/tools/dotc/reporting/ConsoleReporter.scala

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

5-
import util.SourcePosition
65
import core.Contexts._
76
import java.io.{ BufferedReader, PrintWriter }
87
import diagnostic.{ Message, MessageContainer }
9-
import diagnostic.messages._
8+
import diagnostic.messages.{ Error, Warning, ConditionalWarning }
109

1110
/**
1211
* This class implements a Reporter that displays messages on a text console
@@ -25,48 +24,40 @@ class ConsoleReporter(
2524
def printMessage(msg: String): Unit = { writer.print(msg + "\n"); writer.flush() }
2625

2726
/** Prints the message with the given position indication. */
28-
def printMessageAndPos(msg: Message, pos: SourcePosition, diagnosticLevel: String)(implicit ctx: Context): Boolean = {
29-
printMessage(messageAndPos(msg, pos, diagnosticLevel))
30-
true
31-
}
32-
33-
def printExplanation(m: Message)(implicit ctx: Context): Unit = {
34-
printMessage(explanation(m))
35-
}
36-
37-
override def doReport(m: MessageContainer)(implicit ctx: Context): Unit = {
27+
def doReport(m: MessageContainer)(implicit ctx: Context): Unit = {
3828
val didPrint = m match {
3929
case m: Error =>
40-
val didPrint = printMessageAndPos(m.contained, m.pos, diagnosticLevel(m))
30+
printMessage(messageAndPos(m.contained, m.pos, diagnosticLevel(m)))
4131
if (ctx.settings.prompt.value) displayPrompt()
42-
didPrint
32+
true
4333
case m: ConditionalWarning if !m.enablingOption.value =>
4434
false
4535
case m =>
46-
printMessageAndPos(m.contained, m.pos, diagnosticLevel(m))
36+
printMessage(messageAndPos(m.contained, m.pos, diagnosticLevel(m)))
37+
true
4738
}
4839

4940
if (didPrint && ctx.shouldExplain(m))
50-
printExplanation(m.contained)
41+
printMessage(explanation(m.contained))
5142
else if (didPrint && m.contained.explanation.nonEmpty)
5243
printMessage("\nlonger explanation available when compiling with `-explain`")
5344
}
5445

55-
def displayPrompt(): Unit = {
56-
writer.print("\na)bort, s)tack, r)esume: ")
57-
writer.flush()
46+
/** Show prompt if `-Xprompt` is passed as a flag to the compiler */
47+
def displayPrompt()(implicit ctx: Context): Unit = {
48+
printMessage("\na)bort, s)tack, r)esume: ")
49+
flush()
5850
if (reader != null) {
5951
val response = reader.read().asInstanceOf[Char].toLower
6052
if (response == 'a' || response == 's') {
6153
Thread.dumpStack()
6254
if (response == 'a')
6355
sys.exit(1)
6456
}
65-
writer.print("\n")
66-
writer.flush()
57+
print("\n")
58+
flush()
6759
}
6860
}
6961

7062
override def flush()(implicit ctx: Context): Unit = { writer.flush() }
7163
}
72-

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

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,30 @@ import util.SourcePosition
1212
import scala.collection.mutable
1313

1414
trait MessageRendering {
15+
/** Remove ANSI coloring from `str`, useful for getting real length of
16+
* strings
17+
*
18+
* @return string stripped of ANSI escape codes
19+
*/
1520
def stripColor(str: String): String =
1621
str.replaceAll("\u001B\\[[;\\d]*m", "")
1722

23+
/** When inlining a method call, if there's an error we'd like to get the
24+
* outer context and the `pos` at which the call was inlined.
25+
*
26+
* @return a list of strings with inline locations
27+
*/
28+
def outer(pos: SourcePosition, prefix: String)(implicit ctx: Context): List[String] =
29+
if (pos.outer.exists) {
30+
s"$prefix| This location is in code that was inlined at ${pos.outer}" ::
31+
outer(pos.outer, prefix)
32+
} else Nil
33+
34+
/** Get the sourcelines before and after the position, as well as the offset
35+
* for rendering line numbers
36+
*
37+
* @return (lines before error, lines after error, line numbers offset)
38+
*/
1839
def sourceLines(pos: SourcePosition)(implicit ctx: Context): (List[String], List[String], Int) = {
1940
var maxLen = Int.MinValue
2041
def render(xs: List[Int]) =
@@ -33,6 +54,7 @@ trait MessageRendering {
3354
(render(before), render(after), maxLen)
3455
}
3556

57+
/** The column markers aligned under the error */
3658
def columnMarker(pos: SourcePosition, offset: Int)(implicit ctx: Context): String = {
3759
val prefix = " " * (offset - 1)
3860
val whitespace = " " * pos.startColumn
@@ -45,21 +67,30 @@ trait MessageRendering {
4567
s"$prefix|$whitespace${carets.show}"
4668
}
4769

70+
/** The error message (`msg`) aligned under `pos`
71+
*
72+
* @return aligned error message
73+
*/
4874
def errorMsg(pos: SourcePosition, msg: String, offset: Int)(implicit ctx: Context): String = {
4975
val leastWhitespace = msg.lines.foldLeft(Int.MaxValue) { (minPad, line) =>
5076
val lineLength = stripColor(line).length
51-
val padding =
52-
math.min(math.max(0, ctx.settings.pageWidth.value - offset - lineLength), offset + pos.startColumn)
77+
val currPad = math.min(
78+
math.max(0, ctx.settings.pageWidth.value - offset - lineLength),
79+
offset + pos.startColumn
80+
)
5381

54-
if (padding < minPad) padding
55-
else minPad
82+
math.min(currPad, minPad)
5683
}
5784

5885
msg.lines
59-
.map { line => " " * (offset - 1) + "|" + (" " * (leastWhitespace - offset)) + line }
86+
.map { line => " " * (offset - 1) + "|" + (" " * (leastWhitespace - offset)) + line}
6087
.mkString(sys.props("line.separator"))
6188
}
6289

90+
/** The separator between errors containing the source file and error type
91+
*
92+
* @return separator containing error location and kind
93+
*/
6394
def posStr(pos: SourcePosition, diagnosticLevel: String, message: Message)(implicit ctx: Context): String =
6495
if (pos.exists) Blue({
6596
val file = pos.source.file.toString
@@ -76,28 +107,32 @@ trait MessageRendering {
76107
("-" * math.max(ctx.settings.pageWidth.value - stripColor(prefix).length, 0))
77108
}).show else ""
78109

110+
/** Explanation rendered under "Explanation" header */
79111
def explanation(m: Message)(implicit ctx: Context): String = {
80-
val sb = new StringBuilder(hl"""|
81-
|${Blue("Explanation")}
82-
|${Blue("===========")}""".stripMargin)
112+
val sb = new StringBuilder(
113+
hl"""|
114+
|${Blue("Explanation")}
115+
|${Blue("===========")}"""
116+
)
83117
sb.append('\n').append(m.explanation)
84118
if (m.explanation.lastOption != Some('\n')) sb.append('\n')
85119
sb.toString
86120
}
87121

122+
/** The whole message rendered from `msg` */
88123
def messageAndPos(msg: Message, pos: SourcePosition, diagnosticLevel: String)(implicit ctx: Context): String = {
89124
val sb = mutable.StringBuilder.newBuilder
90125
sb.append(posStr(pos, diagnosticLevel, msg)).append('\n')
91126
if (pos.exists) {
92127
val (srcBefore, srcAfter, offset) = sourceLines(pos)
93128
val marker = columnMarker(pos, offset)
94129
val err = errorMsg(pos, msg.msg, offset)
95-
sb.append((srcBefore ::: marker :: err :: srcAfter).mkString("\n"))
130+
sb.append((srcBefore ::: marker :: err :: outer(pos, " " * (offset - 1)) ::: srcAfter).mkString("\n"))
96131
} else sb.append(msg.msg)
97132
sb.toString
98133
}
99134

100-
def diagnosticLevel(cont: MessageContainer): String = {
135+
def diagnosticLevel(cont: MessageContainer): String =
101136
cont match {
102137
case m: Error => "Error"
103138
case m: FeatureWarning => "Feature Warning"
@@ -107,5 +142,4 @@ trait MessageRendering {
107142
case m: Warning => "Warning"
108143
case m: Info => "Info"
109144
}
110-
}
111145
}

src/dotty/tools/dotc/typer/Inliner.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,12 @@ object Inliner {
236236
def inlineCall(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
237237
if (enclosingInlineds.length < ctx.settings.xmaxInlines.value)
238238
new Inliner(tree, bodyToInline(tree.symbol)).inlined(pt)
239-
else errorTree(tree,
240-
i"""Maximal number of successive inlines (${ctx.settings.xmaxInlines.value}) exceeded,
241-
| Maybe this is caused by a recursive inline method?
242-
| You can use -Xmax:inlines to change the limit.""")
239+
else errorTree(
240+
tree,
241+
i"""|Maximal number of successive inlines (${ctx.settings.xmaxInlines.value}) exceeded,
242+
|Maybe this is caused by a recursive inline method?
243+
|You can use -Xmax:inlines to change the limit."""
244+
)
243245

244246
/** Replace `Inlined` node by a block that contains its bindings and expansion */
245247
def dropInlined(inlined: tpd.Inlined)(implicit ctx: Context): Tree = {

0 commit comments

Comments
 (0)