Skip to content

Commit 897fc8d

Browse files
committed
Track splice calls instead of inline calls
The real thing that needs to be tracked for cyclic dependencies are calls to spliced methods. Move the suspend machinery from inline calls to these.
1 parent 6f21c72 commit 897fc8d

File tree

4 files changed

+20
-58
lines changed

4 files changed

+20
-58
lines changed

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ object Splicer {
4747
interpretedExpr.fold(tree)(macroClosure => PickledQuotes.quotedExprToTree(macroClosure(QuoteContext())))
4848
}
4949
catch {
50+
case ex: CompilationUnit.SuspendException =>
51+
throw ex
5052
case ex: StopInterpretation =>
5153
ctx.error(ex.msg, ex.pos)
5254
EmptyTree
@@ -199,14 +201,14 @@ object Splicer {
199201
else if (fn.symbol.is(Module))
200202
interpretModuleAccess(fn.symbol)
201203
else if (fn.symbol.isStatic) {
202-
val staticMethodCall = interpretedStaticMethodCall(fn.symbol.owner, fn.symbol)
204+
val staticMethodCall = interpretedStaticMethodCall(fn.symbol.owner, fn.symbol, tree.sourcePos)
203205
staticMethodCall(args.flatten.map(interpretTree))
204206
}
205207
else if (fn.qualifier.symbol.is(Module) && fn.qualifier.symbol.isStatic)
206208
if (fn.name == nme.asInstanceOfPM)
207209
interpretModuleAccess(fn.qualifier.symbol)
208210
else {
209-
val staticMethodCall = interpretedStaticMethodCall(fn.qualifier.symbol.moduleClass, fn.symbol)
211+
val staticMethodCall = interpretedStaticMethodCall(fn.qualifier.symbol.moduleClass, fn.symbol, tree.sourcePos)
210212
staticMethodCall(args.flatten.map(interpretTree))
211213
}
212214
else if (env.contains(fn.symbol))
@@ -264,7 +266,12 @@ object Splicer {
264266
private def interpretQuoteContext()(implicit env: Env): Object =
265267
QuoteContext()
266268

267-
private def interpretedStaticMethodCall(moduleClass: Symbol, fn: Symbol)(implicit env: Env): List[Object] => Object = {
269+
private def interpretedStaticMethodCall(moduleClass: Symbol, fn: Symbol, pos: SourcePosition)(implicit env: Env): List[Object] => Object = {
270+
if fn.isDefinedInCurrentRun then
271+
if ctx.compilationUnit.source.file == fn.associatedFile then
272+
ctx.error("Cannot call macro defined in the same source file", pos)
273+
ctx.compilationUnit.suspend()
274+
268275
val (inst, clazz) =
269276
if (moduleClass.name.startsWith(str.REPL_SESSION_LINE))
270277
(null, loadReplLineClass(moduleClass))

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

Lines changed: 8 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,6 @@ object Inliner {
7070
*/
7171
def inlineCall(tree: Tree)(implicit ctx: Context): Tree = {
7272
if (tree.symbol == defn.CompiletimeTesting_typeChecks) return Intrinsics.typeChecks(tree)
73-
if tree.symbol.is(Macro) && tree.symbol.isDefinedInCurrentRun then
74-
if ctx.compilationUnit.source.file == tree.symbol.associatedFile then
75-
ctx.error("Cannot call macro defined in the same source file", tree.sourcePos)
76-
ctx.compilationUnit.suspend()
7773

7874
/** Set the position of all trees logically contained in the expansion of
7975
* inlined call `call` to the position of `call`. This transform is necessary
@@ -1241,59 +1237,17 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
12411237
assert(level == 0)
12421238
val inlinedFrom = enclosingInlineds.last
12431239
val ctx1 = tastyreflect.MacroExpansion.context(inlinedFrom)
1240+
val evaluatedSplice = Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext)(ctx1)
12441241

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

compiler/test/dotc/run-test-pickling.blacklist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ derive-generic.scala
1616
mixin-forwarder-overload
1717
t8905
1818
t10889
19+
macros-in-same-project1
1920
i5257.scala
2021
enum-java
2122
tuple-ops.scala

tests/neg/macro-cycle1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ object Test {
44

55
inline def foo: Unit = ${fooImpl}
66

7-
foo
7+
foo // error
88
}

0 commit comments

Comments
 (0)