Skip to content

Commit

Permalink
Show inlined positions with source code
Browse files Browse the repository at this point in the history
This gives more context to the users on what happen and where the code came from.
  • Loading branch information
nicolasstucki committed Dec 16, 2021
1 parent 3f7a7ae commit 2daaa03
Show file tree
Hide file tree
Showing 27 changed files with 239 additions and 70 deletions.
22 changes: 12 additions & 10 deletions compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,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.exists then pos :: inlinePosStack(pos.outer)
else Nil

/** Get the sourcelines before and after the position, as well as the offset
Expand Down Expand Up @@ -173,10 +167,18 @@ trait MessageRendering {
if (pos.exists) {
val pos1 = pos.nonInlined
if (pos1.exists && pos1.source.file.exists) {
// Print error message at inline position
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))
sb.append((srcBefore ::: marker :: err :: srcAfter).mkString(EOL))
// print inline stack trace
for inlinedPos <- inlinePosStack(pos) do
val (srcBefore, srcAfter, offset) = sourceLines(inlinedPos, levelString)
val marker = columnMarker(inlinedPos, offset, levelString)
val prefix = " " * (offset - 1)
sb.append((i"\nThis location contains code that was inlined from $pos" :: srcBefore ::: marker :: srcAfter).mkString(EOL))

}
else sb.append(msg.message)
}
Expand Down
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(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)
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(tpt, em"$msg")
errorTree(call, em"$msg")
case _ =>
evidence
return searchImplicit(callTypeArgs.head)
Expand Down
4 changes: 3 additions & 1 deletion compiler/test-resources/repl/i9227
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ 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
This location contains code that was inlined from rs$line$1:1
1 | import scala.quoted._; inline def myMacro[T]: Unit = ${ myMacroImpl[T] }; def myMacroImpl[T](using Quotes): Expr[Unit] = '{}; println(myMacro[Int])
| ^^^^^^^^^^^^
1 error found
4 changes: 3 additions & 1 deletion tests/neg-macros/delegate-match-1.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@
| ^
| 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
This location contains code that was inlined from Test_2.scala:6
6 | f // error
| ^
4 changes: 3 additions & 1 deletion tests/neg-macros/delegate-match-2.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@
| ^
| 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
This location contains code that was inlined from Test_2.scala:5
5 | f // error
| ^
4 changes: 3 additions & 1 deletion tests/neg-macros/delegate-match-3.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@
| ^
| NoMatchingImplicits
| no implicit values were found that match type A
| This location contains code that was inlined from Test_2.scala:3
This location contains code that was inlined from Test_2.scala:3
3 | f // error
| ^
16 changes: 12 additions & 4 deletions tests/neg-macros/i11386.check
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@
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
This location contains code that was inlined from Test_2.scala:6
6 | dummy(0) // error
| ^
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
This location contains code that was inlined from Test_2.scala:8
8 | dummy(int2String(0)) // error
| ^^^^^^^^^^^^^
This location contains code that was inlined from Test_2.scala:8
7 | notNull(i)
| ^^^^^^^^^^
11 changes: 11 additions & 0 deletions tests/neg-macros/i13991.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

-- Error: tests/neg-macros/i13991/Test_2.scala:6:5 ---------------------------------------------------------------------
6 | v2 // error
| ^^
| Error
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")
| ^^^^^^^^^^^^^^^^^^^^^^^
10 changes: 10 additions & 0 deletions tests/neg-macros/i13991/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -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)
6 changes: 6 additions & 0 deletions tests/neg-macros/i13991/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
object Main:
def main(args: Array[String]): Unit =
inline def v2 = InlineMac.sample("foo")
inline def v1 = v2

v2 // error
12 changes: 9 additions & 3 deletions tests/neg-macros/i6432.check
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@
4 | foo"abc${"123"}xyz${"456"}fgh" // error // error // error
| ^^^
| abc
| This location contains code that was inlined from Test_2.scala:4
This location contains code that was inlined from Test_2.scala:4
4 | foo"abc${"123"}xyz${"456"}fgh" // error // error // error
| ^^^
-- 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
This location contains code that was inlined from Test_2.scala:4
4 | foo"abc${"123"}xyz${"456"}fgh" // error // error // error
| ^^^
-- 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
This location contains code that was inlined from Test_2.scala:4
4 | foo"abc${"123"}xyz${"456"}fgh" // error // error // error
| ^^^
12 changes: 9 additions & 3 deletions tests/neg-macros/i6432b.check
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@
4 | foo"""abc${"123"}xyz${"456"}fgh""" // error // error // error
| ^^^
| abc
| This location contains code that was inlined from Test_2.scala:4
This location contains code that was inlined from Test_2.scala:4
4 | foo"""abc${"123"}xyz${"456"}fgh""" // error // error // error
| ^^^
-- 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
This location contains code that was inlined from Test_2.scala:4
4 | foo"""abc${"123"}xyz${"456"}fgh""" // error // error // error
| ^^^
-- 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
This location contains code that was inlined from Test_2.scala:4
4 | foo"""abc${"123"}xyz${"456"}fgh""" // error // error // error
| ^^^
4 changes: 3 additions & 1 deletion tests/neg-macros/i6976.check
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
| 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
This location contains code that was inlined from Macro_1.scala:6
6 | inline def mcr(x: => Any) = ${mcrImpl('x)}
| ^^^^^^^^^^^^^^
4 changes: 3 additions & 1 deletion tests/neg-macros/i9014.check
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
1 |val tests = summon[Bar] // error
| ^
| Failed to expand!
| This location contains code that was inlined from Test_2.scala:1
This location contains code that was inlined from Test_2.scala:1
1 |val tests = summon[Bar] // error
| ^
4 changes: 3 additions & 1 deletion tests/neg-macros/ill-abort.check
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
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
This location contains code that was inlined from quoted_1.scala:3
3 |inline def fail(): Unit = ${ impl }
| ^^^^^^^^^
4 changes: 3 additions & 1 deletion tests/neg-macros/macro-class-not-found-1.check
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@
| java.lang.NoClassDefFoundError
| at Foo$.aMacroImplementation(Foo.scala:8)
|
| This location contains code that was inlined from Bar.scala:4
This location contains code that was inlined from Foo.scala:5
5 | inline def myMacro(): Unit = ${ aMacroImplementation }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
4 changes: 3 additions & 1 deletion tests/neg-macros/macro-class-not-found-2.check
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@
| 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
This location contains code that was inlined from Foo.scala:5
5 | inline def myMacro(): Unit = ${ aMacroImplementation }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
4 changes: 3 additions & 1 deletion tests/neg-macros/macros-in-same-project-6.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
4 | Foo.myMacro() // error
| ^^^^^^^^^^^^^
| some error
| This location contains code that was inlined from Bar.scala:4
This location contains code that was inlined from Bar.scala:4
4 | Foo.myMacro() // error
| ^^^^^^^^^^^^^
6 changes: 5 additions & 1 deletion tests/neg/cannot-reduce-inline-match.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@
| 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
This location contains code that was inlined from cannot-reduce-inline-match.scala:3
3 | inline x match {
| ^
4 | case _: Int =>
5 | }
4 changes: 3 additions & 1 deletion tests/neg/i11225.check
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@
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
This location contains code that was inlined from i11225.scala:25
25 | transparent inline def uni = uninitialized
| ^^^^^^^^^^^^^
Loading

0 comments on commit 2daaa03

Please sign in to comment.