Skip to content

Commit 833201e

Browse files
committed
Show inlined positions with source code
This gives more context to the users on what happen and where the code came from.
1 parent eb75a1a commit 833201e

27 files changed

+239
-70
lines changed

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

+12-10
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,9 @@ trait MessageRendering {
2525
def stripColor(str: String): String =
2626
str.replaceAll("\u001b\\[.*?m", "")
2727

28-
/** When inlining a method call, if there's an error we'd like to get the
29-
* outer context and the `pos` at which the call was inlined.
30-
*
31-
* @return a list of strings with inline locations
32-
*/
33-
def outer(pos: SourcePosition, prefix: String)(using Context): List[String] =
34-
if (pos.outer.exists)
35-
i"$prefix| This location contains code that was inlined from $pos" ::
36-
outer(pos.outer, prefix)
28+
/** List of all the inline calls that surround the position */
29+
def inlinePosStack(pos: SourcePosition): List[SourcePosition] =
30+
if pos.outer.exists then pos :: inlinePosStack(pos.outer)
3731
else Nil
3832

3933
/** Get the sourcelines before and after the position, as well as the offset
@@ -173,10 +167,18 @@ trait MessageRendering {
173167
if (pos.exists) {
174168
val pos1 = pos.nonInlined
175169
if (pos1.exists && pos1.source.file.exists) {
170+
// Print error message at inline position
176171
val (srcBefore, srcAfter, offset) = sourceLines(pos1, levelString)
177172
val marker = columnMarker(pos1, offset, levelString)
178173
val err = errorMsg(pos1, msg.message, offset)
179-
sb.append((srcBefore ::: marker :: err :: outer(pos, " " * (offset - 1)) ::: srcAfter).mkString(EOL))
174+
sb.append((srcBefore ::: marker :: err :: srcAfter).mkString(EOL))
175+
// print inline stack trace
176+
for inlinedPos <- inlinePosStack(pos) do
177+
val (srcBefore, srcAfter, offset) = sourceLines(inlinedPos, levelString)
178+
val marker = columnMarker(inlinedPos, offset, levelString)
179+
val prefix = " " * (offset - 1)
180+
sb.append((i"\nThis location contains code that was inlined from $pos" :: srcBefore ::: marker :: srcAfter).mkString(EOL))
181+
180182
}
181183
else sb.append(msg.message)
182184
}

compiler/src/dotty/tools/dotc/transform/Splicer.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ object Splicer {
4949
val oldContextClassLoader = Thread.currentThread().getContextClassLoader
5050
Thread.currentThread().setContextClassLoader(classLoader)
5151
try {
52-
val interpreter = new Interpreter(spliceExpansionPos, classLoader)
52+
val interpreter = new Interpreter(splicePos, classLoader)
5353

5454
// Some parts of the macro are evaluated during the unpickling performed in quotedExprToTree
5555
val interpretedExpr = interpreter.interpret[Quotes => scala.quoted.Expr[Any]](tree)

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
853853
evidence.tpe match
854854
case fail: Implicits.SearchFailureType =>
855855
val msg = evTyper.missingArgMsg(evidence, tpt.tpe, "")
856-
errorTree(tpt, em"$msg")
856+
errorTree(call, em"$msg")
857857
case _ =>
858858
evidence
859859
return searchImplicit(callTypeArgs.head)

compiler/test-resources/repl/i9227

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@ scala> import scala.quoted._; inline def myMacro[T]: Unit = ${ myMacroImpl[T] };
33
1 | import scala.quoted._; inline def myMacro[T]: Unit = ${ myMacroImpl[T] }; def myMacroImpl[T](using Quotes): Expr[Unit] = '{}; println(myMacro[Int])
44
| ^^^^^^^^^^^^
55
| Cannot call macro method myMacroImpl defined in the same source file
6-
| This location contains code that was inlined from rs$line$1:1
6+
This location contains code that was inlined from rs$line$1:1
7+
1 | import scala.quoted._; inline def myMacro[T]: Unit = ${ myMacroImpl[T] }; def myMacroImpl[T](using Quotes): Expr[Unit] = '{}; println(myMacro[Int])
8+
| ^^^^^^^^^^^^
79
1 error found

tests/neg-macros/delegate-match-1.check

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44
| ^
55
| AmbiguousImplicits
66
| both value a1 in class Test1 and value a2 in class Test1 match type A
7-
| This location contains code that was inlined from Test_2.scala:6
7+
This location contains code that was inlined from Test_2.scala:6
8+
6 | f // error
9+
| ^

tests/neg-macros/delegate-match-2.check

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44
| ^
55
| DivergingImplicit
66
| method a1 in class Test produces a diverging implicit search when trying to match type A
7-
| This location contains code that was inlined from Test_2.scala:5
7+
This location contains code that was inlined from Test_2.scala:5
8+
5 | f // error
9+
| ^

tests/neg-macros/delegate-match-3.check

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44
| ^
55
| NoMatchingImplicits
66
| no implicit values were found that match type A
7-
| This location contains code that was inlined from Test_2.scala:3
7+
This location contains code that was inlined from Test_2.scala:3
8+
3 | f // error
9+
| ^

tests/neg-macros/i11386.check

+12-4
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,19 @@
33
6 | dummy(0) // error
44
| ^
55
| test
6-
| This location contains code that was inlined from Test_2.scala:6
7-
| This location contains code that was inlined from Macro_1.scala:7
6+
This location contains code that was inlined from Test_2.scala:6
7+
6 | dummy(0) // error
8+
| ^
9+
This location contains code that was inlined from Test_2.scala:6
10+
7 | notNull(i)
11+
| ^^^^^^^^^^
812
-- Error: tests/neg-macros/i11386/Test_2.scala:8:20 --------------------------------------------------------------------
913
8 | dummy(int2String(0)) // error
1014
| ^^^^^^^^^^^^^
1115
| test
12-
| This location contains code that was inlined from Test_2.scala:8
13-
| This location contains code that was inlined from Macro_1.scala:7
16+
This location contains code that was inlined from Test_2.scala:8
17+
8 | dummy(int2String(0)) // error
18+
| ^^^^^^^^^^^^^
19+
This location contains code that was inlined from Test_2.scala:8
20+
7 | notNull(i)
21+
| ^^^^^^^^^^

tests/neg-macros/i13991.check

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
-- Error: tests/neg-macros/i13991/Test_2.scala:6:5 ---------------------------------------------------------------------
3+
6 | v2 // error
4+
| ^^
5+
| Error
6+
This location contains code that was inlined from Test_2.scala:3
7+
3 | inline def v2 = InlineMac.sample("foo")
8+
| ^^^^^
9+
This location contains code that was inlined from Test_2.scala:3
10+
3 | inline def v2 = InlineMac.sample("foo")
11+
| ^^^^^^^^^^^^^^^^^^^^^^^

tests/neg-macros/i13991/Macro_1.scala

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import scala.quoted.*
2+
3+
object InlineMac:
4+
5+
inline def sample(inline expr: String): Int =
6+
${ sampleImpl('expr) }
7+
8+
def sampleImpl(expr: Expr[String])(using Quotes): Expr[Int] =
9+
import quotes.reflect.*
10+
report.errorAndAbort("Error", expr)

tests/neg-macros/i13991/Test_2.scala

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
object Main:
2+
def main(args: Array[String]): Unit =
3+
inline def v2 = InlineMac.sample("foo")
4+
inline def v1 = v2
5+
6+
v2 // error

tests/neg-macros/i6432.check

+9-3
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@
33
4 | foo"abc${"123"}xyz${"456"}fgh" // error // error // error
44
| ^^^
55
| abc
6-
| This location contains code that was inlined from Test_2.scala:4
6+
This location contains code that was inlined from Test_2.scala:4
7+
4 | foo"abc${"123"}xyz${"456"}fgh" // error // error // error
8+
| ^^^
79
-- Error: tests/neg-macros/i6432/Test_2.scala:4:17 ---------------------------------------------------------------------
810
4 | foo"abc${"123"}xyz${"456"}fgh" // error // error // error
911
| ^^^
1012
| xyz
11-
| This location contains code that was inlined from Test_2.scala:4
13+
This location contains code that was inlined from Test_2.scala:4
14+
4 | foo"abc${"123"}xyz${"456"}fgh" // error // error // error
15+
| ^^^
1216
-- Error: tests/neg-macros/i6432/Test_2.scala:4:28 ---------------------------------------------------------------------
1317
4 | foo"abc${"123"}xyz${"456"}fgh" // error // error // error
1418
| ^^^
1519
| fgh
16-
| This location contains code that was inlined from Test_2.scala:4
20+
This location contains code that was inlined from Test_2.scala:4
21+
4 | foo"abc${"123"}xyz${"456"}fgh" // error // error // error
22+
| ^^^

tests/neg-macros/i6432b.check

+9-3
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@
33
4 | foo"""abc${"123"}xyz${"456"}fgh""" // error // error // error
44
| ^^^
55
| abc
6-
| This location contains code that was inlined from Test_2.scala:4
6+
This location contains code that was inlined from Test_2.scala:4
7+
4 | foo"""abc${"123"}xyz${"456"}fgh""" // error // error // error
8+
| ^^^
79
-- Error: tests/neg-macros/i6432b/Test_2.scala:4:19 --------------------------------------------------------------------
810
4 | foo"""abc${"123"}xyz${"456"}fgh""" // error // error // error
911
| ^^^
1012
| xyz
11-
| This location contains code that was inlined from Test_2.scala:4
13+
This location contains code that was inlined from Test_2.scala:4
14+
4 | foo"""abc${"123"}xyz${"456"}fgh""" // error // error // error
15+
| ^^^
1216
-- Error: tests/neg-macros/i6432b/Test_2.scala:4:30 --------------------------------------------------------------------
1317
4 | foo"""abc${"123"}xyz${"456"}fgh""" // error // error // error
1418
| ^^^
1519
| fgh
16-
| This location contains code that was inlined from Test_2.scala:4
20+
This location contains code that was inlined from Test_2.scala:4
21+
4 | foo"""abc${"123"}xyz${"456"}fgh""" // error // error // error
22+
| ^^^

tests/neg-macros/i6976.check

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@
66
| scala.MatchError: Inlined(EmptyTree,List(),Literal(Constant(2))) (of class dotty.tools.dotc.ast.Trees$Inlined)
77
| at playground.macros$.mcrImpl(Macro_1.scala:10)
88
|
9-
| This location contains code that was inlined from Test_2.scala:5
9+
This location contains code that was inlined from Macro_1.scala:6
10+
6 | inline def mcr(x: => Any) = ${mcrImpl('x)}
11+
| ^^^^^^^^^^^^^^

tests/neg-macros/i9014.check

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@
33
1 |val tests = summon[Bar] // error
44
| ^
55
| Failed to expand!
6-
| This location contains code that was inlined from Test_2.scala:1
6+
This location contains code that was inlined from Test_2.scala:1
7+
1 |val tests = summon[Bar] // error
8+
| ^

tests/neg-macros/ill-abort.check

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@
33
1 |def test = fail() // error
44
| ^^^^^^
55
|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.
6-
| This location contains code that was inlined from quoted_1.scala:3
6+
This location contains code that was inlined from quoted_1.scala:3
7+
3 |inline def fail(): Unit = ${ impl }
8+
| ^^^^^^^^^

tests/neg-macros/macro-class-not-found-1.check

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@
55
| java.lang.NoClassDefFoundError
66
| at Foo$.aMacroImplementation(Foo.scala:8)
77
|
8-
| This location contains code that was inlined from Bar.scala:4
8+
This location contains code that was inlined from Foo.scala:5
9+
5 | inline def myMacro(): Unit = ${ aMacroImplementation }
10+
| ^^^^^^^^^^^^^^^^^^^^^^^^^

tests/neg-macros/macro-class-not-found-2.check

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@
55
| java.lang.NoClassDefFoundError: this.is.not.a.Class
66
| at Foo$.aMacroImplementation(Foo.scala:8)
77
|
8-
| This location contains code that was inlined from Bar.scala:4
8+
This location contains code that was inlined from Foo.scala:5
9+
5 | inline def myMacro(): Unit = ${ aMacroImplementation }
10+
| ^^^^^^^^^^^^^^^^^^^^^^^^^

tests/neg-macros/macros-in-same-project-6.check

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
4 | Foo.myMacro() // error
33
| ^^^^^^^^^^^^^
44
| some error
5-
| This location contains code that was inlined from Bar.scala:4
5+
This location contains code that was inlined from Bar.scala:4
6+
4 | Foo.myMacro() // error
7+
| ^^^^^^^^^^^^^

tests/neg/cannot-reduce-inline-match.check

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@
44
| cannot reduce inline match with
55
| scrutinee: "f" : ("f" : String)
66
| patterns : case _:Int
7-
| This location contains code that was inlined from cannot-reduce-inline-match.scala:3
7+
This location contains code that was inlined from cannot-reduce-inline-match.scala:3
8+
3 | inline x match {
9+
| ^
10+
4 | case _: Int =>
11+
5 | }

tests/neg/i11225.check

+3-1
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@
4242
30 | var x7: Int = uni // error
4343
| ^^^
4444
| `uninitialized` can only be used as the right hand side of a mutable field definition
45-
| This location contains code that was inlined from i11225.scala:25
45+
This location contains code that was inlined from i11225.scala:25
46+
25 | transparent inline def uni = uninitialized
47+
| ^^^^^^^^^^^^^

0 commit comments

Comments
 (0)