-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Closed
Labels
area:metaprogramming:quotesIssues related to quotes and splicesIssues related to quotes and splicesitype:bug
Milestone
Description
Compiler version
3.6.2
Minimized code
import scala.quoted.*
def withGiven[T: Type](values: List[Expr[Any]])(result: Quotes ?=> Expr[T])(using Quotes): Expr[T] =
values match
case '{ $x: t } :: values =>
'{ given t = $x; ${ withGiven(values)(result) } }
case _ =>
result
def withGivenInt(x: Expr[Int])(using Quotes) =
withGiven(x :: Nil)(Expr.summon[Int].get)
inline def withInt(inline x: Int) =
${withGivenInt('x)}
Output
scala> withInt(42)
-- Error: ----------------------------------------------------------------------
1 |withInt(42)
|^^^^^^^^^^^
|Exception occurred while executing macro expansion.
|java.util.NoSuchElementException: None.get
| at scala.None$.get(Option.scala:627)
| at scala.None$.get(Option.scala:626)
| at rs$line$1$.withGivenInt$$anonfun$1(rs$line$1:11)
| at rs$line$1$.withGiven(rs$line$1:8)
| at rs$line$1$.withGiven$$anonfun$1(rs$line$1:6)
| at rs$line$1$.withGiven$$anonfun$adapted$1(rs$line$1:6)
| at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:111)
| at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1571)
| at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:136)
| at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformBlock$$anonfun$1$$anonfun$1(tpd.scala:1270)
| at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1252)
| at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1265)
| at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformBlock(tpd.scala:1270)
| at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1551)
| at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:136)
| at dotty.tools.dotc.quoted.PickledQuotes$.spliceTerms(PickledQuotes.scala:153)
| at dotty.tools.dotc.quoted.PickledQuotes$.unpickleTerm(PickledQuotes.scala:89)
| at scala.quoted.runtime.impl.QuotesImpl.unpickleExprV2(QuotesImpl.scala:3279)
| at rs$line$1$.withGiven(rs$line$1:6)
| at rs$line$1$.withGivenInt(rs$line$1:11)
|
|----------------------------------------------------------------------------
|Inline stack trace
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|This location contains code that was inlined from rs$line$1:14
14 | ${withGivenInt('x)}
| ^^^^^^^^^^^^^^^^^^^
----------------------------------------------------------------------------
1 error found
Expectation
Symbol.asQuotes
should populate the implicit scope.
Real world use-case: typelevel/cats-tagless#588
See the hack that I had to do (refs
here are the implicit parameters of the method owning the quotes q
):
def addToGivenScope(refs: List[TermRef])(using q: Quotes) =
if refs.nonEmpty then
try
Expr.summon[Nothing] // fill implicit cache
val ctxMethod = q.getClass.getMethod("ctx")
val ctx = ctxMethod.invoke(q)
val cache = ctxMethod.getReturnType.getDeclaredField("implicitsCache")
cache.setAccessible(true)
val contextual = Class.forName("dotty.tools.dotc.typer.Implicits$ContextualImplicits")
val modified = contextual.getConstructors.head.newInstance(refs, cache.get(ctx), false, ctx)
cache.set(ctx, modified)
catch case _: ReflectiveOperationException => ()
Metadata
Metadata
Assignees
Labels
area:metaprogramming:quotesIssues related to quotes and splicesIssues related to quotes and splicesitype:bug
Type
Projects
Relationships
Development
Select code repository
Activity
jchyb commentedon Dec 30, 2024
Hi! I see the
Expr.summon
docs are not precise in terms of what they mean by "scope", but I always interpreted it as the scope of macro entry method. Were there any problems with using summonInline instead (which delays the summoning until after the macro is expanded)? I see it was removed.joroKr21 commentedon Dec 30, 2024
summonInline
also doesn't take into account the implicit scope of the current owner.That's how it works currently but that's a departure from normal Scala giving special semantics to macros. In a sense, quasi-quotes in Scala 2 emulated better code you would write by hand.
joroKr21 commentedon May 11, 2025
@jchyb consider this (same applies for the reflection API)
joroKr21 commentedon May 12, 2025
Here I mean literally
Scope
in the compiler. We can see from the example above that the implementation of implicit search is leaking in macros. It does find given members of classes and objects because the implicit search goes through the symbol in those cases. But for methods and local definitions it searches in the current scope and theQuotesImpl
doesn't populate the scope the same way theTyper
would.Preserve implicits in Quotes context (#23263)