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 Jan 13, 2022
1 parent 0a834ff commit 96bf85e
Show file tree
Hide file tree
Showing 27 changed files with 196 additions and 70 deletions.
21 changes: 11 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,17 @@ 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) if inlinedPos != pos1 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
1 change: 0 additions & 1 deletion compiler/test-resources/repl/i9227
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 0 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,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
1 change: 0 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,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
1 change: 0 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,3 @@
| ^
| NoMatchingImplicits
| no implicit values were found that match type A
| This location contains code that was inlined from Test_2.scala:3
10 changes: 6 additions & 4 deletions tests/neg-macros/i11386.check
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
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
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
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
3 changes: 0 additions & 3 deletions tests/neg-macros/i6432.check
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 0 additions & 3 deletions tests/neg-macros/i6432b.check
Original file line number Diff line number Diff line change
Expand Up @@ -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
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)}
| ^^^^^^^^^^^^^^
1 change: 0 additions & 1 deletion tests/neg-macros/i9014.check
Original file line number Diff line number Diff line change
Expand Up @@ -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
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 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
1 change: 0 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,3 @@
4 | Foo.myMacro() // error
| ^^^^^^^^^^^^^
| some error
| This location contains code that was inlined from Bar.scala:4
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
| ^^^^^^^^^^^^^
128 changes: 96 additions & 32 deletions tests/neg/i13044.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,105 @@
| 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
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
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
| ^^^^^^^
7 changes: 6 additions & 1 deletion tests/neg/i13570.check
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@
| patterns : case s @ _:Seq[Int] if s.isEmpty
| case s @ _:Seq[Int]
| case _
| This location contains code that was inlined from i13570.scala:3
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")
10 changes: 10 additions & 0 deletions tests/neg/i13991.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- Error: tests/neg/i13991.scala:8:15 ----------------------------------------------------------------------------------
8 |def foo = first[String] // error
| ^^^^^^^^^^^^^
| no implicit argument of type Foo[String] was found
This location contains code that was inlined from i13991.scala:4
4 |inline def second[A]: Int = compiletime.summonInline[Foo[A]].foo
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This location contains code that was inlined from i13991.scala:4
6 |inline def first[A]: Int = second[A] + 42
| ^^^^^^^^^
8 changes: 8 additions & 0 deletions tests/neg/i13991.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
trait Foo[X]:
def foo: Int

inline def second[A]: Int = compiletime.summonInline[Foo[A]].foo

inline def first[A]: Int = second[A] + 42

def foo = first[String] // error
5 changes: 4 additions & 1 deletion tests/neg/inline-error-pos.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@
| 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
This location contains code that was inlined from inline-error-pos.scala:3
3 | inline x match
| ^
4 | case 1 => 9
Loading

0 comments on commit 96bf85e

Please sign in to comment.