Skip to content

Commit c6367d8

Browse files
Merge pull request #7192 from dotty-staging/refine-macro-from-same-project-detection
Detect macro dependencies within the current run
2 parents 0f6ea2a + 0e3c29d commit c6367d8

File tree

14 files changed

+145
-8
lines changed

14 files changed

+145
-8
lines changed

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

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,17 +1239,60 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
12391239
assert(level == 0)
12401240
val inlinedFrom = enclosingInlineds.last
12411241
val ctx1 = tastyreflect.MacroExpansion.context(inlinedFrom)
1242-
val evaluatedSplice = Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext)(ctx1)
12431242

1244-
val inlinedNormailizer = new TreeMap {
1245-
override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
1246-
case Inlined(EmptyTree, Nil, expr) if enclosingInlineds.isEmpty => transform(expr)
1247-
case _ => super.transform(tree)
1243+
val dependencies = macroDependencies(body)
1244+
1245+
if (dependencies.nonEmpty) {
1246+
var location = inlinedFrom.symbol
1247+
if (location.isLocalDummy) location = location.owner
1248+
1249+
val msg =
1250+
em"""Failed to expand macro. This macro depends on an implementation that is defined in the same project and not yet compiled.
1251+
|In particular ${inlinedFrom.symbol} depends on ${dependencies.map(_.show).mkString(", ")}.
1252+
|
1253+
|Moving ${dependencies.map(_.show).mkString(", ")} to a different project would fix this.
1254+
|""".stripMargin
1255+
ctx.error(msg, inlinedFrom.sourcePos)
1256+
EmptyTree
1257+
} else {
1258+
val evaluatedSplice = Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext)(ctx1)
1259+
1260+
val inlinedNormailizer = new TreeMap {
1261+
override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
1262+
case Inlined(EmptyTree, Nil, expr) if enclosingInlineds.isEmpty => transform(expr)
1263+
case _ => super.transform(tree)
1264+
}
12481265
}
1266+
val normalizedSplice = inlinedNormailizer.transform(evaluatedSplice)
1267+
if (normalizedSplice.isEmpty) normalizedSplice
1268+
else normalizedSplice.withSpan(span)
12491269
}
1250-
val normalizedSplice = inlinedNormailizer.transform(evaluatedSplice)
1251-
if (normalizedSplice.isEmpty) normalizedSplice
1252-
else normalizedSplice.withSpan(span)
1270+
}
1271+
1272+
/** Return the set of symbols that are refered at level -1 by the tree and defined in the current run.
1273+
* This corresponds to the symbols that will need to be interpreted.
1274+
*/
1275+
private def macroDependencies(tree: Tree)(implicit ctx: Context) = {
1276+
new TreeAccumulator[Set[Symbol]] {
1277+
private[this] var level = -1
1278+
override def apply(syms: Set[Symbol], tree: tpd.Tree)(implicit ctx: Context): Set[Symbol] = {
1279+
if (level != -1) foldOver(syms, tree)
1280+
else tree match {
1281+
case tree: RefTree if level == -1 && tree.symbol.isDefinedInCurrentRun && !tree.symbol.isLocal =>
1282+
foldOver(syms + tree.symbol, tree)
1283+
case Quoted(body) =>
1284+
level += 1
1285+
try apply(syms, body)
1286+
finally level -= 1
1287+
case Spliced(body) =>
1288+
level -= 1
1289+
try apply(syms, body)
1290+
finally level += 1
1291+
case _ =>
1292+
foldOver(syms, tree)
1293+
}
1294+
}
1295+
}.apply(Set.empty, tree)
12531296
}
12541297
}
12551298

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- Error: tests/neg-macros/macros-in-same-project-1/Bar.scala:2:13 -----------------------------------------------------
2+
2 | Foo.myMacro() // error
3+
| ^^^^^^^^^^^^^
4+
|Failed to expand macro. This macro depends on an implementation that is defined in the same project and not yet compiled.
5+
|In particular method myMacro depends on method aMacroImplementation.
6+
|
7+
|Moving method aMacroImplementation to a different project would fix this.
8+
| This location is in code that was inlined at Bar.scala:2
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Bar {
2+
Foo.myMacro() // error
3+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import scala.quoted._
2+
3+
object Foo {
4+
5+
inline def myMacro(): Unit = ${ aMacroImplementation }
6+
7+
def aMacroImplementation given QuoteContext: Expr[Unit] = '{ println("Hello") }
8+
9+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- Error: tests/neg-macros/macros-in-same-project-2/Bar.scala:5:9 ------------------------------------------------------
2+
5 | myMacro() // error
3+
| ^^^^^^^^^
4+
|Failed to expand macro. This macro depends on an implementation that is defined in the same project and not yet compiled.
5+
|In particular method myMacro depends on method aMacroImplementation, object Foo.
6+
|
7+
|Moving method aMacroImplementation, object Foo to a different project would fix this.
8+
| This location is in code that was inlined at Bar.scala:5
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
object Bar {
2+
3+
inline def myMacro(): Unit = ${ Foo.aMacroImplementation }
4+
5+
myMacro() // error
6+
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import scala.quoted._
2+
3+
object Foo {
4+
5+
def aMacroImplementation given QuoteContext: Expr[Unit] = '{ println("Hello") }
6+
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- Error: tests/neg-macros/macros-in-same-project-3/Baz.scala:2:13 -----------------------------------------------------
2+
2 | Bar.myMacro() // error
3+
| ^^^^^^^^^^^^^
4+
|Failed to expand macro. This macro depends on an implementation that is defined in the same project and not yet compiled.
5+
|In particular method myMacro depends on method aMacroImplementation.
6+
|
7+
|Moving method aMacroImplementation to a different project would fix this.
8+
| This location is in code that was inlined at Baz.scala:2
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import scala.quoted._
2+
3+
object Bar {
4+
5+
inline def myMacro(): Unit = ${ aMacroImplementation }
6+
7+
def aMacroImplementation given QuoteContext: Expr[Unit] = Foo.hello()
8+
9+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Baz {
2+
Bar.myMacro() // error
3+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import scala.quoted._
2+
3+
object Foo {
4+
5+
def hello() given QuoteContext: Expr[Unit] = '{ println("Hello") }
6+
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- Error: tests/neg-macros/macros-in-same-project-4/Bar.scala:5:13 -----------------------------------------------------
2+
5 | Foo.myMacro() // error
3+
| ^^^^^^^^^^^^^
4+
|Failed to expand macro. This macro depends on an implementation that is defined in the same project and not yet compiled.
5+
|In particular method myMacro depends on method aMacroImplementation.
6+
|
7+
|Moving method aMacroImplementation to a different project would fix this.
8+
| This location is in code that was inlined at Bar.scala:5
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import scala.quoted._
2+
3+
object Bar {
4+
5+
Foo.myMacro() // error
6+
7+
def hello() given QuoteContext: Expr[Unit] = '{ println("Hello") }
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import scala.quoted._
2+
3+
object Foo {
4+
5+
inline def myMacro(): Unit = ${ aMacroImplementation }
6+
7+
def aMacroImplementation given QuoteContext: Expr[Unit] = Bar.hello()
8+
9+
}

0 commit comments

Comments
 (0)