Skip to content

Commit 9c2992f

Browse files
committed
Only make the staged parts of a quote inlineable
Contents of splices do not need to be transformed as they will be evaluated before the code is inlined. Therefore we only want to make code at staging level 1 or grater inlineable. If the quote is in an inline method, we also need to make the contents of the splices inlineable (i.e. for any level). Fix #14603
1 parent fae7c09 commit 9c2992f

File tree

3 files changed

+40
-2
lines changed

3 files changed

+40
-2
lines changed

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import NameKinds.{InlineAccessorName, UniqueInlineName}
1717
import NameOps._
1818
import Annotations._
1919
import transform.{AccessProxies, PCPCheckAndHeal, Splicer}
20+
import transform.SymUtils.*
2021
import config.Printers.inlining
2122
import util.Property
2223
import dotty.tools.dotc.transform.TreeMapWithStages._
@@ -61,13 +62,17 @@ object PrepareInlineable {
6162
*
6263
* Constant vals don't need accessors since they are inlined in FirstTransform.
6364
* Inline methods don't need accessors since they are inlined in Typer.
65+
*
66+
* When creating accessors for staged/quoted code we only need to create accessors
67+
* for the code that is staged. This excludes code at level 0 (except if it is inlined).
6468
*/
6569
def needsAccessor(sym: Symbol)(using Context): Boolean =
6670
sym.isTerm &&
6771
(sym.isOneOf(AccessFlags) || sym.privateWithin.exists) &&
6872
!sym.isContainedIn(inlineSym) &&
6973
!(sym.isStableMember && sym.info.widenTermRefExpr.isInstanceOf[ConstantType]) &&
70-
!sym.isInlineMethod
74+
!sym.isInlineMethod &&
75+
(Inliner.inInlineMethod || StagingContext.level > 0)
7176

7277
def preTransform(tree: Tree)(using Context): Tree
7378

@@ -79,7 +84,14 @@ object PrepareInlineable {
7984
}
8085

8186
override def transform(tree: Tree)(using Context): Tree =
82-
postTransform(super.transform(preTransform(tree)))
87+
inContext(stagingContext(tree)) {
88+
postTransform(super.transform(preTransform(tree)))
89+
}
90+
91+
private def stagingContext(tree: Tree)(using Context): Context = tree match
92+
case tree: Apply if tree.symbol.isQuote => StagingContext.quoteContext
93+
case tree: Apply if tree.symbol.isExprSplice => StagingContext.spliceContext
94+
case _ => ctx
8395
}
8496

8597
/** Direct approach: place the accessor with the accessed symbol. This has the

tests/pos-macros/i14603.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import scala.quoted.*
2+
3+
class Macro(using qctx: Quotes): // Anti-pattern: put Quotes in a field
4+
import qctx.reflect._
5+
6+
def apply: Expr[Unit] = '{
7+
println("in quote")
8+
${ val a: Term = '{ println("in nested quote") }.asTerm; ??? }
9+
}

tests/pos-macros/i14603b.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import scala.language.experimental.macros
2+
import scala.quoted.*
3+
4+
class Runtime
5+
6+
class Macro(using qctx: Quotes) { // Anti-pattern: put Quotes in a field
7+
import qctx.reflect._
8+
9+
def apply[A: Type](x: Expr[A]): Expr[Unit] = {
10+
'{
11+
val rt: Runtime = ???
12+
${Block(doExprs('{ rt }.asTerm), '{ () }.asTerm).asExprOf[Unit]}
13+
}
14+
}
15+
16+
private def doExprs(rt: Term): List[Term] = Nil
17+
}

0 commit comments

Comments
 (0)