Skip to content

Commit 4550883

Browse files
Blaisorbladenicolasstucki
authored andcommitted
Add missing Inlined nodes on quotes
1 parent 5fe2c2c commit 4550883

File tree

10 files changed

+96
-17
lines changed

10 files changed

+96
-17
lines changed

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

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ package transform
44
import dotty.tools.dotc.ast.{Trees, tpd, untpd}
55
import scala.collection.mutable
66
import core._
7-
import typer.{Checking, VarianceChecker}
8-
import Types._, Contexts._, Names._, Flags._, DenotTransformers._, Phases._
7+
import dotty.tools.dotc.typer.Checking
8+
import dotty.tools.dotc.typer.Inliner
9+
import dotty.tools.dotc.typer.VarianceChecker
10+
import Types._, Contexts._, Names._, Flags._, DenotTransformers._
911
import SymDenotations._, StdNames._, Annotations._, Trees._, Scopes._
1012
import Decorators._
1113
import Symbols._, SymUtils._
@@ -237,17 +239,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
237239
super.transform(tree1)
238240
}
239241
case Inlined(call, bindings, expansion) if !call.isEmpty =>
240-
// Leave only a call trace consisting of
241-
// - a reference to the top-level class from which the call was inlined,
242-
// - the call's position
243-
// in the call field of an Inlined node.
244-
// The trace has enough info to completely reconstruct positions.
245-
// The minimization is done for two reasons:
246-
// 1. To save space (calls might contain large inline arguments, which would otherwise
247-
// be duplicated
248-
// 2. To enable correct pickling (calls can share symbols with the inlined code, which
249-
// would trigger an assertion when pickling).
250-
val callTrace = Ident(call.symbol.topLevelClass.typeRef).withPos(call.pos)
242+
val callTrace = Inliner.inlineCallTrace(call.symbol, call.pos)
251243
cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(inlineContext(call)))
252244
case tree: Template =>
253245
withNoCheckNews(tree.parents.flatMap(newPart)) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ object Splicer {
4141
val interpreter = new Interpreter(pos, classLoader)
4242
try {
4343
// Some parts of the macro are evaluated during the unpickling performed in quotedExprToTree
44-
val interpreted = interpreter.interpret[scala.quoted.Expr[Any]](tree)
45-
interpreted.fold(tree)(x => PickledQuotes.quotedExprToTree(x))
44+
val interpretedExpr = interpreter.interpret[scala.quoted.Expr[Any]](tree)
45+
interpretedExpr.fold(tree)(x => PickledQuotes.quotedExprToTree(x))
4646
}
4747
catch {
4848
case ex: scala.quoted.QuoteError =>

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import typer.Implicits.SearchFailureType
1515
import scala.collection.mutable
1616
import dotty.tools.dotc.core.StdNames._
1717
import dotty.tools.dotc.core.quoted._
18+
import dotty.tools.dotc.typer.Inliner
1819
import dotty.tools.dotc.util.SourcePosition
1920

2021

@@ -381,7 +382,12 @@ class Staging extends MacroTransformWithImplicits {
381382
capturers(body.symbol)(body)
382383
case _=>
383384
val (body1, splices) = nested(isQuote = true).split(body)
384-
if (level == 0 && !ctx.inInlineMethod) pickledQuote(body1, splices, body.tpe, isType).withPos(quote.pos)
385+
if (level == 0 && !ctx.inInlineMethod) {
386+
val body2 =
387+
if (body1.isType) body1
388+
else Inlined(Inliner.inlineCallTrace(ctx.owner, quote.pos), Nil, body1)
389+
pickledQuote(body2, splices, body.tpe, isType).withPos(quote.pos)
390+
}
385391
else {
386392
// In top-level splice in an inline def. Keep the tree as it is, it will be transformed at inline site.
387393
body
@@ -432,7 +438,8 @@ class Staging extends MacroTransformWithImplicits {
432438
else if (level == 1) {
433439
val (body1, quotes) = nested(isQuote = false).split(splice.qualifier)
434440
val tpe = outer.embedded.getHoleType(splice)
435-
makeHole(body1, quotes, tpe).withPos(splice.pos)
441+
val hole = makeHole(body1, quotes, tpe).withPos(splice.pos)
442+
if (splice.isType) hole else Inlined(EmptyTree, Nil, hole)
436443
}
437444
else if (enclosingInlineds.nonEmpty) { // level 0 in an inlined call
438445
val spliceCtx = ctx.outer // drop the last `inlineContext`

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,15 @@ object Inliner {
149149
(new Reposition).transformInline(inlined)
150150
}
151151
}
152+
153+
/** Leave only a call trace consisting of
154+
* - a reference to the top-level class from which the call was inlined,
155+
* - the call's position
156+
* in the call field of an Inlined node.
157+
* The trace has enough info to completely reconstruct positions.
158+
*/
159+
def inlineCallTrace(callSym: Symbol, pos: Position)(implicit ctx: Context): Tree =
160+
Ident(callSym.topLevelClass.typeRef).withPos(pos)
152161
}
153162

154163
/** Produces an inlined version of `call` via its `inlined` method.

tests/run/i4947e.check

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
assertImpl: Test$.main(Test_2.scala:7)
2+
true
3+
assertImpl: Test$.main(Test_2.scala:8)
4+
false
5+
assertImpl: Test$.main(Test_2.scala:9)
6+
hi: Test$.main(Test_2.scala:10)
7+
hi again: Test$.main(Test_2.scala:11)
8+
false

tests/run/i4947e/Macro_1.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import scala.quoted._
2+
3+
object Macros {
4+
def printStack(tag: String): Unit = {
5+
println(tag + ": "+ new Exception().getStackTrace().apply(1))
6+
}
7+
def assertImpl(expr: Expr[Boolean]) = '{
8+
printStack("assertImpl")
9+
println(~expr)
10+
}
11+
}

tests/run/i4947e/Test_2.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
object Test {
2+
3+
rewrite def assert2(expr: => Boolean): Unit = ~Macros.assertImpl('(expr))
4+
5+
def main(args: Array[String]): Unit = {
6+
val x = 1
7+
assert2(x != 0)
8+
assert2(x == 0)
9+
assert2 {
10+
Macros.printStack("hi")
11+
Macros.printStack("hi again")
12+
x == 0
13+
}
14+
}
15+
}

tests/run/i4947f.check

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
assertImpl: Test$.main(Test_2.scala:7)
2+
true
3+
assertImpl: Test$.main(Test_2.scala:8)
4+
false
5+
assertImpl: Test$.main(Test_2.scala:9)
6+
hi: Test$.main(Test_2.scala:10)
7+
hi again: Test$.main(Test_2.scala:11)
8+
false

tests/run/i4947f/Macro_1.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import scala.quoted._
2+
3+
object Macros {
4+
def printStack(tag: String): Unit = {
5+
println(tag + ": "+ new Exception().getStackTrace().apply(1))
6+
}
7+
def assertImpl(expr: Expr[Boolean]) = '{
8+
printStack("assertImpl")
9+
println(~expr)
10+
}
11+
12+
rewrite def assert2(expr: => Boolean): Unit = ~Macros.assertImpl('(expr))
13+
14+
}

tests/run/i4947f/Test_2.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
object Test {
2+
3+
import Macros._
4+
5+
def main(args: Array[String]): Unit = {
6+
val x = 1
7+
assert2(x != 0)
8+
assert2(x == 0)
9+
assert2 {
10+
Macros.printStack("hi")
11+
Macros.printStack("hi again")
12+
x == 0
13+
}
14+
}
15+
}

0 commit comments

Comments
 (0)