Skip to content

Commit e59cd6c

Browse files
Merge pull request #6805 from dotty-staging/fix-macro-detection
Fix macro detection
2 parents 06204ea + e6c1fb5 commit e59cd6c

File tree

5 files changed

+65
-44
lines changed

5 files changed

+65
-44
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1027,7 +1027,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
10271027

10281028
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
10291029
constToLiteral(betaReduce(super.typedApply(tree, pt))) match {
1030-
case res: Apply if res.symbol == defn.InternalQuoted_exprSplice && level == 0 =>
1030+
case res: Apply if res.symbol == defn.InternalQuoted_exprSplice && level == 0 && call.symbol.is(Macro) =>
10311031
expandMacro(res.args.head, tree.span)
10321032
case res => res
10331033
}

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

Lines changed: 28 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -245,51 +245,36 @@ object PrepareInlineable {
245245
}
246246

247247
def checkInlineMacro(sym: Symbol, rhs: Tree, pos: SourcePosition)(implicit ctx: Context) = {
248-
if (!ctx.isAfterTyper) {
249-
var isMacro = false
250-
new TreeMapWithStages(freshStagingContext) {
251-
override protected def transformSplice(body: tpd.Tree, splice: tpd.Tree)(implicit ctx: Context): tpd.Tree = {
252-
isMacro = true
253-
splice
254-
}
255-
override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree =
256-
if (isMacro) tree else super.transform(tree)
257-
}.transform(rhs)
258-
259-
if (isMacro) {
260-
sym.setFlag(Macro)
261-
if (level == 0) {
262-
def isValidMacro(tree: Tree)(implicit ctx: Context): Unit = tree match {
263-
case Spliced(code) =>
264-
if (code.symbol.flags.is(Inline))
265-
ctx.error("Macro cannot be implemented with an `inline` method", code.sourcePos)
266-
Splicer.checkValidMacroBody(code)
267-
new PCPCheckAndHeal(freshStagingContext).transform(rhs) // Ignore output, only check PCP
248+
if (sym.is(Macro) && !ctx.isAfterTyper) {
249+
def isValidMacro(tree: Tree)(implicit ctx: Context): Unit = tree match {
250+
case Spliced(code) =>
251+
if (code.symbol.flags.is(Inline))
252+
ctx.error("Macro cannot be implemented with an `inline` method", code.sourcePos)
253+
Splicer.checkValidMacroBody(code)
254+
new PCPCheckAndHeal(freshStagingContext).transform(rhs) // Ignore output, only check PCP
268255

269-
case Block(List(stat), Literal(Constants.Constant(()))) => isValidMacro(stat)
270-
case Block(Nil, expr) => isValidMacro(expr)
271-
case Typed(expr, _) => isValidMacro(expr)
272-
case Block(DefDef(nme.ANON_FUN, _, _, _, _) :: Nil, Closure(_, fn, _)) if fn.symbol.info.isImplicitMethod =>
273-
// TODO Suppot this pattern
274-
ctx.error(
275-
"""Macros using a return type of the form `foo(): given X => Y` are not yet supported.
276-
|
277-
|Place the implicit as an argument (`foo() given X: Y`) to overcome this limitation.
278-
|""".stripMargin, tree.sourcePos)
279-
case _ =>
280-
ctx.error(
281-
"""Malformed macro.
282-
|
283-
|Expected the splice ${...} to be at the top of the RHS:
284-
| inline def foo(inline x: X, ..., y: Y): Int = ${impl(x, ... '{y}})
285-
|
286-
| * The contents of the splice must call a static method
287-
| * All arguments must be quoted or inline
288-
""".stripMargin, pos)
289-
}
290-
isValidMacro(rhs)
291-
}
256+
case Block(List(stat), Literal(Constants.Constant(()))) => isValidMacro(stat)
257+
case Block(Nil, expr) => isValidMacro(expr)
258+
case Typed(expr, _) => isValidMacro(expr)
259+
case Block(DefDef(nme.ANON_FUN, _, _, _, _) :: Nil, Closure(_, fn, _)) if fn.symbol.info.isImplicitMethod =>
260+
// TODO Suppot this pattern
261+
ctx.error(
262+
"""Macros using a return type of the form `foo(): given X => Y` are not yet supported.
263+
|
264+
|Place the implicit as an argument (`foo() given X: Y`) to overcome this limitation.
265+
|""".stripMargin, tree.sourcePos)
266+
case _ =>
267+
ctx.error(
268+
"""Malformed macro.
269+
|
270+
|Expected the splice ${...} to be at the top of the RHS:
271+
| inline def foo(inline x: X, ..., y: Y): Int = ${impl(x, ... '{y}})
272+
|
273+
| * The contents of the splice must call a static method
274+
| * All arguments must be quoted or inline
275+
""".stripMargin, pos)
292276
}
277+
isValidMacro(rhs)
293278
}
294279
}
295280

tests/neg/inline-quote.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import scala.quoted._
2+
3+
object Test {
4+
5+
inline def foo(x: Expr[Int]) given QuoteContext: Expr[Int] = '{ // error
6+
println("foo")
7+
${
8+
${??? : Expr[Int]}
9+
10+
x
11+
}
12+
}
13+
14+
15+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
scala.Predef.println("foo")
3+
45
4+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import scala.quoted._
2+
3+
object Test {
4+
5+
inline def foo(x: Expr[Int]) given QuoteContext: Expr[Int] = '{
6+
println("foo")
7+
$x
8+
}
9+
10+
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
11+
12+
def main(args: Array[String]): Unit = withQuoteContext {
13+
val y = '{45}
14+
println(foo(y).show)
15+
}
16+
17+
}

0 commit comments

Comments
 (0)