Skip to content

Commit d9b7911

Browse files
committed
Fix spliced-captured this
1 parent 2731ec5 commit d9b7911

File tree

5 files changed

+58
-8
lines changed

5 files changed

+58
-8
lines changed

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -695,9 +695,12 @@ class TreePickler(pickler: TastyPickler) {
695695
writeNat(idx)
696696
pickleType(tree.tpe, richTypes = true)
697697
args.foreach { arg =>
698-
arg.tpe match
699-
case _: TermRef if arg.isType => writeByte(EXPLICITtpt)
700-
case _ =>
698+
if arg.isType then
699+
// Add EXPLICITtpt if the type can represent a type or a term.
700+
// This is only needed if the tree of the type would be unpickled as a term tree.
701+
arg.tpe match
702+
case _: TermRef | _: ThisType => writeByte(EXPLICITtpt)
703+
case _ =>
701704
pickleTree(arg)
702705
}
703706
}

compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,9 @@ class PickleQuotes extends MacroTransform {
203203
private def getPicklableHoleType(tpe: Type, isStagedClasses: Symbol => Boolean)(using Context) =
204204
new TypeOps.AvoidMap {
205205
def toAvoid(tp: NamedType) = !isStagedClasses(tp.typeSymbol) && !isStaticPrefix(tp)
206+
override def apply(tp: Type): Type = tp match
207+
case tp: ThisType if tp.typeSymbol.isLocal => super.apply(tp.widen)
208+
case _ => super.apply(tp)
206209
}.apply(tpe)
207210
}
208211

compiler/src/dotty/tools/dotc/transform/Splicing.scala

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,14 +167,15 @@ class Splicing extends MacroTransform:
167167
* ```
168168
*/
169169
private class SpliceTransformer(spliceOwner: Symbol, isCaptured: Symbol => Boolean) extends Transformer:
170-
private var refBindingMap = mutable.LinkedHashMap.empty[Symbol, (Tree, Symbol)]
170+
private var refTermBindingMap = mutable.LinkedHashMap.empty[Symbol, (Tree, Symbol)]
171+
private var refTypeBindingMap = mutable.LinkedHashMap.empty[Symbol, (Tree, Symbol)]
171172
/** Reference to the `Quotes` instance of the current level 1 splice */
172173
private var quotes: Tree | Null = null // TODO: add to the context
173174

174175
def transformSplice(tree: tpd.Tree, tpe: Type, holeIdx: Int)(using Context): tpd.Tree =
175176
assert(level == 0)
176177
val newTree = transform(tree)
177-
val (refs, bindings) = refBindingMap.values.toList.unzip
178+
val (refs, bindings) = (refTypeBindingMap.values ++ refTermBindingMap.values).toList.unzip
178179
val bindingsTypes = bindings.map(_.termRef.widenTermRefExpr)
179180
val methType = MethodType(bindingsTypes, newTree.tpe)
180181
val meth = newSymbol(spliceOwner, nme.ANON_FUN, Synthetic | Method, methType)
@@ -212,6 +213,11 @@ class Splicing extends MacroTransform:
212213
case _: TypeTree | _: SingletonTypeTree =>
213214
if containsCapturedType(tree.tpe) && level >= 1 then getTagRefFor(tree)
214215
else tree
216+
case _: This =>
217+
if isCaptured(tree.symbol) then
218+
val tag = getTagRefFor(tree)
219+
spliced(tag.tpe)(capturedTerm(tree))
220+
else super.transform(tree)
215221
case tree @ Assign(lhs: RefTree, rhs) =>
216222
if isCaptured(lhs.symbol) then transformSplicedAssign(tree)
217223
else super.transform(tree)
@@ -302,7 +308,7 @@ class Splicing extends MacroTransform:
302308
Param,
303309
defn.QuotedExprClass.typeRef.appliedTo(tpe),
304310
)
305-
val bindingSym = refBindingMap.getOrElseUpdate(tree.symbol, (tree, newBinding))._2
311+
val bindingSym = refTermBindingMap.getOrElseUpdate(tree.symbol, (tree, newBinding))._2
306312
ref(bindingSym)
307313

308314
private def newQuotedTypeClassBinding(tpe: Type)(using Context) =
@@ -314,14 +320,14 @@ class Splicing extends MacroTransform:
314320
)
315321

316322
private def capturedType(tree: Tree)(using Context): Symbol =
317-
refBindingMap.getOrElseUpdate(tree.symbol, (TypeTree(tree.tpe), newQuotedTypeClassBinding(tree.tpe)))._2
323+
refTypeBindingMap.getOrElseUpdate(tree.symbol, (TypeTree(tree.tpe), newQuotedTypeClassBinding(tree.tpe)))._2
318324

319325
private def capturedPartTypes(quote: Quote)(using Context): Tree =
320326
val (tags, body1) = inContextWithQuoteTypeTags {
321327
val capturePartTypes = new TypeMap {
322328
def apply(tp: Type) = tp match {
323329
case typeRef: TypeRef if containsCapturedType(typeRef) =>
324-
val termRef = refBindingMap
330+
val termRef = refTypeBindingMap
325331
.getOrElseUpdate(typeRef.symbol, (TypeTree(typeRef), newQuotedTypeClassBinding(typeRef)))._2.termRef
326332
val tagRef = getTagRef(termRef)
327333
tagRef
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import scala.quoted.*
2+
3+
object Macro:
4+
inline def generateCode: Unit = ${ testThisPaths }
5+
6+
def testThisPaths(using Quotes): Expr[Unit] =
7+
'{
8+
trait E extends G:
9+
type V
10+
val f: F
11+
${ val expr = '{ println(this) }; expr }
12+
${ val expr = '{ println(f) }; expr }
13+
${ val expr = '{ println(this.f) }; expr }
14+
${ val expr = '{ println(??? : this.type) }; expr }
15+
${ val expr = '{ println(??? : V) }; expr }
16+
${ val expr = '{ println(??? : this.V) }; expr }
17+
${ val expr = '{ println(??? : this.f.V) }; expr }
18+
${ val expr = '{ println(??? : this.f.type) }; expr }
19+
${
20+
val expr = '{
21+
println(this)
22+
println(f)
23+
println(this.f)
24+
println(??? : this.type)
25+
println(??? : V)
26+
println(??? : this.V)
27+
println(??? : this.f.V)
28+
println(??? : this.f.type)
29+
}
30+
expr
31+
}
32+
trait F:
33+
type V
34+
}
35+
36+
trait G:
37+
val f: Any
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@main def test = Macro.generateCode

0 commit comments

Comments
 (0)