@@ -45,6 +45,9 @@ object QuoteContextImpl {
45
45
46
46
class QuoteContextImpl private (ctx : Context ) extends QuoteContext , QuoteUnpickler , QuoteMatching :
47
47
48
+ private val yCheck : Boolean =
49
+ ctx.settings.Ycheck .value(using ctx).exists(x => x == " all" || x == " macros" )
50
+
48
51
extension [T ](self : scala.quoted.Expr [T ]):
49
52
def show : String =
50
53
reflect.TreeMethodsImpl .show(reflect.Term .of(self))
@@ -118,6 +121,13 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, QuoteUnpickl
118
121
QuoteContextImpl .this .asExprOf[T ](self.asExpr)(using tp)
119
122
end extension
120
123
124
+ extension [ThisTree <: Tree ](self : ThisTree ):
125
+ def changeOwner (from : Symbol , to : Symbol ): ThisTree =
126
+ tpd.TreeOps (self).changeOwner(from, to)
127
+ def changeNonLocalOwners (newOwner : Symbol ): ThisTree =
128
+ tpd.TreeOps (self).changeNonLocalOwners(newOwner).asInstanceOf [ThisTree ]
129
+ end extension
130
+
121
131
end TreeMethodsImpl
122
132
123
133
type PackageClause = tpd.PackageDef
@@ -238,9 +248,9 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, QuoteUnpickl
238
248
239
249
object DefDef extends DefDefModule :
240
250
def apply (symbol : Symbol , rhsFn : List [TypeRepr ] => List [List [Term ]] => Option [Term ]): DefDef =
241
- withDefaultPos(tpd.polyDefDef(symbol.asTerm, tparams => vparamss => rhsFn(tparams)(vparamss).getOrElse(tpd.EmptyTree )))
251
+ withDefaultPos(tpd.polyDefDef(symbol.asTerm, tparams => vparamss => yCheckedOwners( rhsFn(tparams)(vparamss), symbol ).getOrElse(tpd.EmptyTree )))
242
252
def copy (original : Tree )(name : String , typeParams : List [TypeDef ], paramss : List [List [ValDef ]], tpt : TypeTree , rhs : Option [Term ]): DefDef =
243
- tpd.cpy.DefDef (original)(name.toTermName, typeParams, paramss, tpt, rhs.getOrElse(tpd.EmptyTree ))
253
+ tpd.cpy.DefDef (original)(name.toTermName, typeParams, paramss, tpt, yCheckedOwners( rhs, original.symbol) .getOrElse(tpd.EmptyTree ))
244
254
def unapply (ddef : DefDef ): Option [(String , List [TypeDef ], List [List [ValDef ]], TypeTree , Option [Term ])] =
245
255
Some ((ddef.name.toString, ddef.typeParams, ddef.paramss, ddef.tpt, optional(ddef.rhs)))
246
256
end DefDef
@@ -264,9 +274,9 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, QuoteUnpickl
264
274
265
275
object ValDef extends ValDefModule :
266
276
def apply (symbol : Symbol , rhs : Option [Term ]): ValDef =
267
- tpd.ValDef (symbol.asTerm, rhs.getOrElse(tpd.EmptyTree ))
277
+ tpd.ValDef (symbol.asTerm, yCheckedOwners( rhs, symbol) .getOrElse(tpd.EmptyTree ))
268
278
def copy (original : Tree )(name : String , tpt : TypeTree , rhs : Option [Term ]): ValDef =
269
- tpd.cpy.ValDef (original)(name.toTermName, tpt, rhs.getOrElse(tpd.EmptyTree ))
279
+ tpd.cpy.ValDef (original)(name.toTermName, tpt, yCheckedOwners( rhs, original.symbol) .getOrElse(tpd.EmptyTree ))
270
280
def unapply (vdef : ValDef ): Option [(String , TypeTree , Option [Term ])] =
271
281
Some ((vdef.name.toString, vdef.tpt, optional(vdef.rhs)))
272
282
@@ -729,12 +739,12 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, QuoteUnpickl
729
739
object Lambda extends LambdaModule :
730
740
def apply (tpe : MethodType , rhsFn : List [Tree ] => Tree ): Block =
731
741
val meth = dotc.core.Symbols .newSymbol(ctx.owner, nme.ANON_FUN , Synthetic | Method , tpe)
732
- tpd.Closure (meth, tss => changeOwnerOfTree( rhsFn(tss.head), meth))
742
+ tpd.Closure (meth, tss => tpd. TreeOps (yCheckedOwners( rhsFn(tss.head), ctx.owner)).changeOwner(ctx.owner , meth))
733
743
734
- def unapply (tree : Block ): Option [(List [ValDef ], Term )] = tree match {
744
+ def unapply (tree : Block ): Option [(Symbol , List [ValDef ], Term )] = tree match {
735
745
case Block ((ddef @ DefDef (_, _, params :: Nil , _, Some (body))) :: Nil , Closure (meth, _))
736
746
if ddef.symbol == meth.symbol =>
737
- Some ((params, body))
747
+ Some ((meth.symbol, params, body))
738
748
case _ => None
739
749
}
740
750
end Lambda
@@ -2541,6 +2551,44 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, QuoteUnpickl
2541
2551
private def withDefaultPos [T <: Tree ](fn : Context ?=> T ): T =
2542
2552
fn(using ctx.withSource(Position .ofMacroExpansion.source)).withSpan(Position .ofMacroExpansion.span)
2543
2553
2554
+ private def yCheckedOwners (tree : Option [Tree ], owner : Symbol ): tree.type =
2555
+ if yCheck then
2556
+ tree match
2557
+ case Some (tree) =>
2558
+ yCheckOwners(tree, owner)
2559
+ case _ =>
2560
+ tree
2561
+
2562
+ private def yCheckedOwners (tree : Tree , owner : Symbol ): tree.type =
2563
+ if yCheck then
2564
+ yCheckOwners(tree, owner)
2565
+ tree
2566
+
2567
+ private def yCheckOwners (tree : Tree , owner : Symbol ): Unit =
2568
+ new tpd.TreeTraverser {
2569
+ def traverse (t : Tree )(using Context ): Unit =
2570
+ t match
2571
+ case t : tpd.DefTree =>
2572
+ val defOwner = t.symbol.owner
2573
+ assert(defOwner == owner,
2574
+ s """ Tree had an unexpected owner for ${t.symbol}
2575
+ |Expected: $owner ( ${owner.fullName})
2576
+ |But was: $defOwner ( ${defOwner.fullName})
2577
+ |
2578
+ |
2579
+ |The code of the definition of ${t.symbol} is
2580
+ | ${TreeMethods .show(t)}
2581
+ |
2582
+ |which was found in the code
2583
+ | ${TreeMethods .show(tree)}
2584
+ |
2585
+ |which has the AST representation
2586
+ | ${TreeMethods .showExtractors(tree)}
2587
+ |
2588
+ | """ .stripMargin) // TODO add a good error message
2589
+ case _ => traverseChildren(t)
2590
+ }.traverse(tree)
2591
+
2544
2592
end reflect
2545
2593
2546
2594
def unpickleExpr [T ](pickled : String | List [String ], typeHole : (Int , Seq [Any ]) => scala.quoted.Type [? ], termHole : (Int , Seq [Any ], scala.quoted.QuoteContext ) => scala.quoted.Expr [? ]): scala.quoted.Expr [T ] =
0 commit comments