Skip to content

Commit e5c079e

Browse files
committed
Move blackbox macro exapnsion to ReifyQuotes
1 parent b5b41b4 commit e5c079e

File tree

13 files changed

+93
-39
lines changed

13 files changed

+93
-39
lines changed

compiler/src/dotty/tools/dotc/core/Flags.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,9 @@ object Flags {
350350
/** An opaque type alias or a class containing one */
351351
val (Opaque @ _, _, _) = newFlags(43, "opaque")
352352

353+
/** An transparent inline method */
354+
val (_, Transparent @ _, _) = newFlags(44, "transparent")
355+
353356

354357
// ------------ Flags following this one are not pickled ----------------------------------
355358

@@ -426,7 +429,7 @@ object Flags {
426429
CommonSourceModifierFlags.toTypeFlags | Abstract | Sealed | Opaque | Open
427430

428431
val TermSourceModifierFlags: FlagSet =
429-
CommonSourceModifierFlags.toTermFlags | Inline | AbsOverride | Lazy | Erased
432+
CommonSourceModifierFlags.toTermFlags | Inline | AbsOverride | Lazy | Erased | Transparent
430433

431434
/** Flags representing modifiers that can appear in trees */
432435
val ModifierFlags: FlagSet =
@@ -443,7 +446,7 @@ object Flags {
443446
Scala2SpecialFlags, MutableOrOpen, Opaque, Touched, JavaStatic,
444447
OuterOrCovariant, LabelOrContravariant, CaseAccessor,
445448
Extension, NonMember, Implicit, Given, Permanent, Synthetic,
446-
SuperParamAliasOrScala2x, Inline, Macro)
449+
SuperParamAliasOrScala2x, Inline, Macro, Transparent)
447450

448451
/** Flags that are not (re)set when completing the denotation, or, if symbol is
449452
* a top-level class or object, when completing the denotation once the class

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,7 @@ class TreePickler(pickler: TastyPickler) {
699699
if (flags.is(ParamAccessor)) writeModTag(PARAMsetter)
700700
if (flags.is(SuperParamAlias)) writeModTag(PARAMalias)
701701
if (flags.is(Exported)) writeModTag(EXPORTED)
702+
if (flags.is(Transparent)) writeModTag(TRANSPARENT)
702703
assert(!(flags.is(Label)))
703704
}
704705
else {

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ class TreeUnpickler(reader: TastyReader,
635635
case INLINE => addFlag(Inline)
636636
case INLINEPROXY => addFlag(InlineProxy)
637637
case MACRO => addFlag(Macro)
638+
case TRANSPARENT => addFlag(Transparent)
638639
case OPAQUE => addFlag(Opaque)
639640
case STATIC => addFlag(JavaStatic)
640641
case OBJECT => addFlag(Module)

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,7 @@ class ReifyQuotes extends MacroTransform {
195195
case splice: Select => cpy.Select(splice)(body1, splice.name)
196196
}
197197
}
198-
else {
199-
assert(level == 1, "unexpected top splice outside quote")
198+
else if (level == 1) {
200199
val (body1, quotes) = nested(isQuote = false).splitSplice(body)(spliceContext)
201200
val tpe = outer.embedded.getHoleType(body, splice)
202201
val hole = makeHole(splice.isTerm, body1, quotes, tpe).withSpan(splice.span)
@@ -206,6 +205,10 @@ class ReifyQuotes extends MacroTransform {
206205
// For example we can have a lifted tree containing the LHS of an assignment (see tests/run-with-compiler/quote-var.scala).
207206
if (splice.isType || outer.embedded.isLiftedSymbol(body.symbol)) hole
208207
else Inlined(EmptyTree, Nil, hole).withSpan(splice.span)
208+
} else {
209+
assert(level == 0, "unexpected splice insiced top splice")
210+
val newBody = Inliner.expandMacro(body, splice.span)
211+
transform(newBody)
209212
}
210213

211214
/** Transforms the contents of a nested splice

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

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,27 @@ object Inliner {
325325
val errors = compileForErrors(tree, false)
326326
packErrors(errors)
327327
}
328+
329+
def expandMacro(body: Tree, span: Span)(implicit ctx: Context) = {
330+
assert(level == 0)
331+
val inlinedFrom = enclosingInlineds.last
332+
val ctx1 = tastyreflect.MacroExpansion.context(inlinedFrom)
333+
334+
val evaluatedSplice = inContext(tastyreflect.MacroExpansion.context(inlinedFrom)) {
335+
Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext)
336+
}
337+
338+
val inlinedNormailizer = new TreeMap {
339+
override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
340+
case Inlined(EmptyTree, Nil, expr) if enclosingInlineds.isEmpty => transform(expr)
341+
case _ => super.transform(tree)
342+
}
343+
}
344+
val normalizedSplice = inlinedNormailizer.transform(evaluatedSplice)
345+
if (normalizedSplice.isEmpty) normalizedSplice
346+
else normalizedSplice.withSpan(span)
347+
}
348+
328349
}
329350

330351
/** Produces an inlined version of `call` via its `inlined` method.
@@ -1233,7 +1254,14 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
12331254
case res: Apply if res.symbol == defn.InternalQuoted_exprSplice
12341255
&& level == 0
12351256
&& !suppressInline =>
1236-
expandMacro(res.args.head, tree.span)
1257+
val body = res.args.head
1258+
checkMacroDependencies(body, call.sourcePos)
1259+
if call.symbol.is(Transparent) then
1260+
expandMacro(res.args.head, tree.span)
1261+
else
1262+
// Blackbox macros expanded later in ReifyQuotes
1263+
ctx.compilationUnit.needsStaging = true
1264+
res
12371265
case res => res
12381266
}
12391267

@@ -1391,31 +1419,16 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
13911419
}
13921420
}
13931421

1394-
private def expandMacro(body: Tree, span: Span)(using Context) = {
1422+
private def checkMacroDependencies(body: Tree, callPos: SourcePosition)(implicit ctx: Context): Unit = {
13951423
assert(level == 0)
1396-
val inlinedFrom = enclosingInlineds.last
13971424
val dependencies = macroDependencies(body)
1398-
13991425
if dependencies.nonEmpty && !ctx.reporter.errorsReported then
14001426
for sym <- dependencies do
14011427
if ctx.compilationUnit.source.file == sym.associatedFile then
1402-
ctx.error(em"Cannot call macro $sym defined in the same source file", call.sourcePos)
1428+
ctx.error(em"Cannot call macro $sym defined in the same source file", callPos)
14031429
if (ctx.settings.XprintSuspension.value)
1404-
ctx.echo(i"suspension triggered by macro call to ${sym.showLocated} in ${sym.associatedFile}", call.sourcePos)
1430+
ctx.echo(i"suspension triggered by macro call to ${sym.showLocated} in ${sym.associatedFile}", callPos)
14051431
ctx.compilationUnit.suspend() // this throws a SuspendException
1406-
1407-
val evaluatedSplice = inContext(tastyreflect.MacroExpansion.context(inlinedFrom)) {
1408-
Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext)
1409-
}
1410-
val inlinedNormailizer = new TreeMap {
1411-
override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match {
1412-
case Inlined(EmptyTree, Nil, expr) if enclosingInlineds.isEmpty => transform(expr)
1413-
case _ => super.transform(tree)
1414-
}
1415-
}
1416-
val normalizedSplice = inlinedNormailizer.transform(evaluatedSplice)
1417-
if (normalizedSplice.isEmpty) normalizedSplice
1418-
else normalizedSplice.withSpan(span)
14191432
}
14201433

14211434
/** Return the set of symbols that are referred at level -1 by the tree and defined in the current run.

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,6 +1917,9 @@ class Typer extends Namer
19171917

19181918
if (sym.isInlineMethod)
19191919
val rhsToInline = PrepareInlineable.wrapRHS(ddef, tpt1, rhs1)
1920+
rhsToInline match
1921+
case _: Typed =>
1922+
case _ => sym.setFlag(Transparent) // FIXME Tag whitebox macros (do it in desugar)
19201923
PrepareInlineable.registerInlineInfo(sym, rhsToInline)
19211924

19221925
if (sym.isConstructor && !sym.isPrimaryConstructor) {

tasty/src/dotty/tools/tasty/TastyFormat.scala

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ Standard-Section: "ASTs" TopLevelStat*
185185
OPAQUE -- opaque, also used for classes containing opaque aliases
186186
INLINE -- inline
187187
MACRO -- Inline method containing toplevel splices
188+
TRANSPARENT -- Transparent inline method
188189
INLINEPROXY -- Symbol of binding with an argument to an inline method as rhs (TODO: do we still need this?)
189190
STATIC -- Mapped to static Java member
190191
OBJECT -- An object or its class
@@ -351,16 +352,17 @@ object TastyFormat {
351352
final val HASDEFAULT = 31
352353
final val STABLE = 32
353354
final val MACRO = 33
354-
final val ERASED = 34
355-
final val OPAQUE = 35
356-
final val EXTENSION = 36
357-
final val GIVEN = 37
358-
final val PARAMsetter = 38
359-
final val EXPORTED = 39
360-
final val OPEN = 40
361-
final val PARAMEND = 41
362-
final val PARAMalias = 42
363-
final val SUPERTRAIT = 43
355+
final val TRANSPARENT = 34
356+
final val ERASED = 35
357+
final val OPAQUE = 36
358+
final val EXTENSION = 37
359+
final val GIVEN = 38
360+
final val PARAMsetter = 39
361+
final val EXPORTED = 40
362+
final val OPEN = 41
363+
final val PARAMEND = 42
364+
final val PARAMalias = 43
365+
final val SUPERTRAIT = 44
364366

365367
// Cat. 2: tag Nat
366368

@@ -500,6 +502,7 @@ object TastyFormat {
500502
| INLINE
501503
| INLINEPROXY
502504
| MACRO
505+
| TRANSPARENT
503506
| OPAQUE
504507
| STATIC
505508
| OBJECT
@@ -561,6 +564,7 @@ object TastyFormat {
561564
case INLINE => "INLINE"
562565
case INLINEPROXY => "INLINEPROXY"
563566
case MACRO => "MACRO"
567+
case TRANSPARENT => "TRANSPARENT"
564568
case OPAQUE => "OPAQUE"
565569
case STATIC => "STATIC"
566570
case OBJECT => "OBJECT"

tests/neg-macros/i6530.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
object Macros {
22
inline def q : Int = ${ '[ Int ] } // error
33
val x : Int = 1 + q // error
4+
5+
transparent inline def q2: Int = ${ '[ Int ] } // error
6+
val y : Int = 1 + q2 // error
47
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
DefDef("foo", Nil, Nil, Inferred(), None)
2-
ValDef("bar", Inferred(), None)
1+
DefDef("foo", Nil, Nil, TypeIdent("Int"), Some(Apply(Select(Literal(Constant(1)), "+"), List(Literal(Constant(2))))))
2+
ValDef("bar", TypeIdent("Int"), Some(Apply(Select(Literal(Constant(2)), "+"), List(Literal(Constant(3))))))
33
Bind("x", Ident("_"))

tests/run-custom-args/Yretain-trees/tasty-extractors-owners.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
foo
2-
ValDef("macro", Inferred(), None)
2+
DefDef("main", Nil, List(List(ValDef("args", Applied(TypeIdent("Array"), List(TypeIdent("String"))), None))), TypeIdent("Unit"), Some(Block(Nil, Inlined(Some(Projection(Inferred(), "Macros$")), Nil, Typed(Apply(TypeApply(Ident("exprSplice"), List(Inferred())), List(Block(List(DefDef("$anonfun", Nil, List(List(ValDef("evidence$1", Inferred(), None))), Inferred(), Some(Apply(Apply(TypeApply(Ident("impl"), List(Inferred())), List(Apply(Select(Apply(TypeApply(Ident("exprQuote"), List(Inferred())), List(Inlined(None, Nil, Block(List(DefDef("foo", Nil, Nil, Inferred(), Some(Block(List(DefDef("bar", Nil, Nil, Inferred(), Some(Literal(Constant(1)))), ValDef("bar2", Inferred(), Some(Literal(Constant(2))))), Typed(Ident("bar"), Inferred())))), ValDef("foo2", Inferred(), Some(Block(List(DefDef("baz", Nil, Nil, Inferred(), Some(Literal(Constant(3)))), ValDef("baz2", Inferred(), Some(Literal(Constant(4))))), Typed(Ident("baz"), Inferred())))), ClassDef("A", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, None, List(TypeDef("B", TypeIdent("Int")), DefDef("b", Nil, Nil, Inferred(), Some(Literal(Constant(5)))), ValDef("b2", Inferred(), Some(Literal(Constant(6))))))), Literal(Constant(())))))), "apply"), List(Ident("evidence$1"))))), List(Ident("evidence$1")))))), Closure(Ident("$anonfun"), None)))), TypeIdent("Unit"))))))
33

44
bar
55
DefDef("foo", Nil, Nil, Inferred(), None)
@@ -8,7 +8,7 @@ bar2
88
DefDef("foo", Nil, Nil, Inferred(), None)
99

1010
foo2
11-
ValDef("macro", Inferred(), None)
11+
DefDef("main", Nil, List(List(ValDef("args", Applied(TypeIdent("Array"), List(TypeIdent("String"))), None))), TypeIdent("Unit"), Some(Block(Nil, Inlined(Some(Projection(Inferred(), "Macros$")), Nil, Typed(Apply(TypeApply(Ident("exprSplice"), List(Inferred())), List(Block(List(DefDef("$anonfun", Nil, List(List(ValDef("evidence$1", Inferred(), None))), Inferred(), Some(Apply(Apply(TypeApply(Ident("impl"), List(Inferred())), List(Apply(Select(Apply(TypeApply(Ident("exprQuote"), List(Inferred())), List(Inlined(None, Nil, Block(List(DefDef("foo", Nil, Nil, Inferred(), Some(Block(List(DefDef("bar", Nil, Nil, Inferred(), Some(Literal(Constant(1)))), ValDef("bar2", Inferred(), Some(Literal(Constant(2))))), Typed(Ident("bar"), Inferred())))), ValDef("foo2", Inferred(), Some(Block(List(DefDef("baz", Nil, Nil, Inferred(), Some(Literal(Constant(3)))), ValDef("baz2", Inferred(), Some(Literal(Constant(4))))), Typed(Ident("baz"), Inferred())))), ClassDef("A", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, None, List(TypeDef("B", TypeIdent("Int")), DefDef("b", Nil, Nil, Inferred(), Some(Literal(Constant(5)))), ValDef("b2", Inferred(), Some(Literal(Constant(6))))))), Literal(Constant(())))))), "apply"), List(Ident("evidence$1"))))), List(Ident("evidence$1")))))), Closure(Ident("$anonfun"), None)))), TypeIdent("Unit"))))))
1212

1313
baz
1414
ValDef("foo2", Inferred(), None)
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
DefDef("foo", Nil, Nil, Inferred(), None)
2-
ValDef("bar", Inferred(), None)
1+
DefDef("foo", Nil, Nil, TypeIdent("Int"), Some(Apply(Select(Literal(Constant(1)), "+"), List(Literal(Constant(2))))))
2+
ValDef("bar", TypeIdent("Int"), Some(Apply(Select(Literal(Constant(2)), "+"), List(Literal(Constant(3))))))

tests/run-macros/box/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+
5+
inline def blackbox: Int = ${one}
6+
7+
transparent inline def whitebox: Int = ${one}
8+
9+
private def one(using QuoteContext): Expr[Int] = Expr(1)
10+
11+
}

tests/run-macros/box/Test_2.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import scala.quoted._
2+
import Macros._
3+
4+
object Test {
5+
def main(args: Array[String]): Unit = {
6+
val a: Int = blackbox
7+
val b: 1 = whitebox
8+
9+
assert(a == 1)
10+
assert(b == 1)
11+
}
12+
}

0 commit comments

Comments
 (0)