From 3b718fb687f78dc592ee8e08af56e61de510e4e0 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Thu, 19 Jun 2025 15:45:39 +0200 Subject: [PATCH 1/3] Preserve implicits in Quotes context [Cherry-picked 39e2f698e62fd2a1cac804704b8b1ad3a73f6243][modified] --- .../tools/dotc/quoted/PickledQuotes.scala | 4 +- tests/run-macros/i22260.check | 5 ++ tests/run-macros/i22260/Macros_1.scala | 49 +++++++++++++++++++ tests/run-macros/i22260/Test_2.scala | 6 +++ 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 tests/run-macros/i22260.check create mode 100644 tests/run-macros/i22260/Macros_1.scala create mode 100644 tests/run-macros/i22260/Test_2.scala diff --git a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala index 4536fcbdf41b..2a06e5d98f1d 100644 --- a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala @@ -21,6 +21,8 @@ import scala.quoted.runtime.impl.* import scala.collection.mutable import QuoteUtils.* +import dotty.tools.io.NoAbstractFile +import dotty.tools.dotc.ast.TreeMapWithImplicits object PickledQuotes { import tpd.* @@ -98,7 +100,7 @@ object PickledQuotes { /** Replace all term holes with the spliced terms */ private def spliceTerms(tree: Tree, typeHole: TypeHole, termHole: ExprHole)(using Context): Tree = { - def evaluateHoles = new TreeMapWithPreciseStatContexts { + def evaluateHoles = new TreeMapWithImplicits { override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match { case Hole(isTerm, idx, args, _) => inContext(SpliceScope.contextWithNewSpliceScope(tree.sourcePos)) { diff --git a/tests/run-macros/i22260.check b/tests/run-macros/i22260.check new file mode 100644 index 000000000000..d186effeb923 --- /dev/null +++ b/tests/run-macros/i22260.check @@ -0,0 +1,5 @@ +42 +42 +42 +42 +42 \ No newline at end of file diff --git a/tests/run-macros/i22260/Macros_1.scala b/tests/run-macros/i22260/Macros_1.scala new file mode 100644 index 000000000000..c67633fe16cf --- /dev/null +++ b/tests/run-macros/i22260/Macros_1.scala @@ -0,0 +1,49 @@ +import scala.quoted.* + +object Macros: + inline def inMethod: Int = ${ insideMethod } + inline def usMethod: Int = ${ usingMethod } + inline def inObject: Int = ${ insideObject } + inline def inClass: Int = ${ insideClass } + inline def usClass: Int = ${ usingClass } + + def summon(using Quotes) = + Expr.summon[Int].getOrElse('{ 0 }) + + def insideMethod(using Quotes): Expr[Int] = '{ + def foo = + given Int = 42 + ${summon} + + foo + } + + def usingMethod(using Quotes): Expr[Int] = '{ + def foo(using Int) = + ${summon} + + foo(using 42) + } + + def insideObject(using Quotes): Expr[Int] = '{ + object Foo: + given Int = 42 + val x = ${summon} + + Foo.x + } + + def insideClass(using Quotes): Expr[Int] = '{ + class Foo: + given Int = 42 + val x = ${summon} + + new Foo().x + } + + def usingClass(using Quotes): Expr[Int] = '{ + class Foo(using Int): + val x = ${summon} + + new Foo(using 42).x + } diff --git a/tests/run-macros/i22260/Test_2.scala b/tests/run-macros/i22260/Test_2.scala new file mode 100644 index 000000000000..a71f5480f3db --- /dev/null +++ b/tests/run-macros/i22260/Test_2.scala @@ -0,0 +1,6 @@ +@main def Test = + println(Macros.inMethod) + println(Macros.usMethod) + println(Macros.inObject) + println(Macros.inClass) + println(Macros.usClass) From e4c0eadef9128864cc677b67495fc2607bbc68d2 Mon Sep 17 00:00:00 2001 From: Georgi Krastev Date: Sun, 25 May 2025 15:56:05 +0300 Subject: [PATCH 2/3] Also fix asQuotes implicit context for methods --- .../src/dotty/tools/dotc/core/SymDenotations.scala | 9 +++++++-- .../src/scala/quoted/runtime/impl/QuotesImpl.scala | 13 ++++++++++--- tests/run-macros/i22260.check | 1 + tests/run-macros/i22260/Macros_1.scala | 10 +++++++++- tests/run-macros/i22260/Test_2.scala | 1 + 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 889e3d12a98c..d6ec1852d623 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -338,8 +338,13 @@ object SymDenotations { def recurWithoutParamss(info: Type): List[List[Symbol]] = info match case info: LambdaType => - val params = info.paramNames.lazyZip(info.paramInfos).map((pname, ptype) => - newSymbol(symbol, pname, SyntheticParam, ptype)) + val commonFlags = + if info.isContextualMethod then Given | SyntheticParam + else if info.isImplicitMethod then Implicit | SyntheticParam + else SyntheticParam + val params = info.paramNames.lazyZip(info.paramInfos).map: (pname, ptype) => + val flags = if ptype.hasAnnotation(defn.ErasedParamAnnot) then commonFlags | Erased else commonFlags + newSymbol(symbol, pname, flags, ptype) val prefs = params.map(_.namedType) for param <- params do param.info = param.info.substParams(info, prefs) diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 13f144d45122..42b9c0254c33 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -11,6 +11,7 @@ import dotty.tools.dotc.core.Contexts.* import dotty.tools.dotc.core.Decorators.* import dotty.tools.dotc.core.NameKinds import dotty.tools.dotc.core.NameOps.* +import dotty.tools.dotc.core.Scopes.* import dotty.tools.dotc.core.StdNames.* import dotty.tools.dotc.core.Types import dotty.tools.dotc.NoCompilationUnit @@ -2579,7 +2580,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler modFlags | dotc.core.Flags.ModuleValCreationFlags, clsFlags | dotc.core.Flags.ModuleClassCreationFlags, parents, - dotc.core.Scopes.newScope, + newScope, privateWithin) val cls = mod.moduleClass.asClass cls.enter(dotc.core.Symbols.newConstructor(cls, dotc.core.Flags.Synthetic, Nil, Nil)) @@ -2592,7 +2593,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler xCheckMacroAssert(!privateWithin.exists || privateWithin.isType, "privateWithin must be a type symbol or `Symbol.noSymbol`") val privateWithin1 = if privateWithin.isTerm then Symbol.noSymbol else privateWithin checkValidFlags(flags.toTermFlags, Flags.validMethodFlags) - dotc.core.Symbols.newSymbol(owner, name.toTermName, flags | dotc.core.Flags.Method, tpe, privateWithin1) + val method = dotc.core.Symbols.newSymbol(owner, name.toTermName, flags | dotc.core.Flags.Method, tpe, privateWithin1) + method.setParamss(method.paramSymss) + method def newVal(owner: Symbol, name: String, tpe: TypeRepr, flags: Flags, privateWithin: Symbol): Symbol = xCheckMacroAssert(!privateWithin.exists || privateWithin.isType, "privateWithin must be a type symbol or `Symbol.noSymbol`") val privateWithin1 = if privateWithin.isTerm then Symbol.noSymbol else privateWithin @@ -2807,7 +2810,11 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler def asQuotes: Nested = assert(self.ownersIterator.contains(ctx.owner), s"$self is not owned by ${ctx.owner}") - new QuotesImpl(using ctx.withOwner(self)) + val newCtx = if ctx.owner eq self then ctx else + val newCtx = ctx.fresh.setOwner(self) + if !self.flags.is(Flags.Method) then newCtx + else newCtx.setScope(newScopeWith(self.paramSymss.flatten*)) + new QuotesImpl(using newCtx) end extension diff --git a/tests/run-macros/i22260.check b/tests/run-macros/i22260.check index d186effeb923..a50c8c916b8c 100644 --- a/tests/run-macros/i22260.check +++ b/tests/run-macros/i22260.check @@ -2,4 +2,5 @@ 42 42 42 +42 42 \ No newline at end of file diff --git a/tests/run-macros/i22260/Macros_1.scala b/tests/run-macros/i22260/Macros_1.scala index c67633fe16cf..44538bfcd521 100644 --- a/tests/run-macros/i22260/Macros_1.scala +++ b/tests/run-macros/i22260/Macros_1.scala @@ -1,6 +1,7 @@ import scala.quoted.* object Macros: + inline def crMethod: Int = ${ createMethod } inline def inMethod: Int = ${ insideMethod } inline def usMethod: Int = ${ usingMethod } inline def inObject: Int = ${ insideObject } @@ -8,7 +9,14 @@ object Macros: inline def usClass: Int = ${ usingClass } def summon(using Quotes) = - Expr.summon[Int].getOrElse('{ 0 }) + Expr.summon[Int].getOrElse('{0}) + + def createMethod(using Quotes): Expr[Int] = + import quotes.reflect.* + val tpe = MethodType(MethodTypeKind.Contextual)("x" :: Nil)(_ => TypeRepr.of[Int] :: Nil, _ => TypeRepr.of[Int]) + val sym = Symbol.newMethod(Symbol.spliceOwner, "foo", tpe) + val method = DefDef(sym, _ => Some(summon(using sym.asQuotes).asTerm)) + Block(method :: Nil, Apply(Ref(sym), '{42}.asTerm :: Nil)).asExprOf[Int] def insideMethod(using Quotes): Expr[Int] = '{ def foo = diff --git a/tests/run-macros/i22260/Test_2.scala b/tests/run-macros/i22260/Test_2.scala index a71f5480f3db..3f512fa6308a 100644 --- a/tests/run-macros/i22260/Test_2.scala +++ b/tests/run-macros/i22260/Test_2.scala @@ -1,4 +1,5 @@ @main def Test = + println(Macros.crMethod) println(Macros.inMethod) println(Macros.usMethod) println(Macros.inObject) From ee5a4fbcd3dc97efbb3a954cffd30156a18abed6 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Thu, 19 Jun 2025 16:53:42 +0200 Subject: [PATCH 3/3] Also fix asQuotes implicit context for methods [Cherry-picked ccc5d1aee7fe9e4e64eb5b78d258bebeddb150ce][modified]