Skip to content

Commit 5261ee0

Browse files
Add quote ASTs to TASTy (#20165)
Add AST nodes for `Quote`, `Splice`, `QuotePattern`, and `QuoteSplice` to TASTy. ``` Term = ... QUOTE Length body_Term bodyTpe_Type -- Quoted expression `'{ body }` of a body typed as `bodyTpe` SPLICE Length expr_Term tpe_Type -- Spliced expression `${ expr }` typed as `tpe` SPLICEPATTEN Length pat_Term tpe_Type targs_Type* args_Term* -- Pattern splice `${pat}` or `$pat[targs*](args*)` in a quoted pattern of type `tpe`. -- patterns: ... QUOTEPATTERN Length body_Term quotes_Term pat_Type bindings_Term* -- Quote pattern node `'{ bindings*; body }(using quotes)` ```
2 parents 1cf779c + 743cc0b commit 5261ee0

File tree

14 files changed

+76
-25
lines changed

14 files changed

+76
-25
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
178178
def Splice(expr: Tree, tpe: Type)(using Context): Splice =
179179
untpd.Splice(expr).withType(tpe)
180180

181+
def Splice(expr: Tree)(using Context): Splice =
182+
ta.assignType(untpd.Splice(expr), expr)
183+
184+
def SplicePattern(pat: Tree, args: List[Tree], tpe: Type)(using Context): SplicePattern =
185+
untpd.SplicePattern(pat, args).withType(tpe)
186+
181187
def Hole(isTerm: Boolean, idx: Int, args: List[Tree], content: Tree, tpe: Type)(using Context): Hole =
182188
untpd.Hole(isTerm, idx, args, content).withType(tpe)
183189

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

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -743,28 +743,40 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) {
743743
pickleTree(alias)
744744
}
745745
case tree @ Quote(body, Nil) =>
746-
// TODO: Add QUOTE tag to TASTy
747746
assert(body.isTerm,
748747
"""Quote with type should not be pickled.
749748
|Quote with type should only exists after staging phase at staging level 0.""".stripMargin)
750-
pickleTree(
751-
// scala.quoted.runtime.Expr.quoted[<tree.bodyType>](<body>)
752-
ref(defn.QuotedRuntime_exprQuote)
753-
.appliedToType(tree.bodyType)
754-
.appliedTo(body)
755-
.withSpan(tree.span)
756-
)
749+
writeByte(QUOTE)
750+
withLength {
751+
pickleTree(body)
752+
pickleType(tree.bodyType)
753+
}
757754
case Splice(expr) =>
758-
pickleTree( // TODO: Add SPLICE tag to TASTy
759-
// scala.quoted.runtime.Expr.splice[<tree.tpe>](<expr>)
760-
ref(defn.QuotedRuntime_exprSplice)
761-
.appliedToType(tree.tpe)
762-
.appliedTo(expr)
763-
.withSpan(tree.span)
764-
)
765-
case tree: QuotePattern =>
766-
// TODO: Add QUOTEPATTERN tag to TASTy
767-
pickleTree(QuotePatterns.encode(tree))
755+
writeByte(SPLICE)
756+
withLength {
757+
pickleTree(expr)
758+
pickleType(tree.tpe)
759+
}
760+
case QuotePattern(bindings, body, quotes) =>
761+
writeByte(QUOTEPATTERN)
762+
withLength {
763+
if body.isType then writeByte(EXPLICITtpt)
764+
pickleTree(body)
765+
pickleTree(quotes)
766+
pickleType(tree.tpe)
767+
bindings.foreach(pickleTree)
768+
}
769+
case SplicePattern(pat, args) =>
770+
val targs = Nil // SplicePattern `targs` will be added with #18271
771+
writeByte(SPLICEPATTERN)
772+
withLength {
773+
pickleTree(pat)
774+
pickleType(tree.tpe)
775+
for targ <- targs do
776+
writeByte(EXPLICITtpt)
777+
pickleTree(targ)
778+
args.foreach(pickleTree)
779+
}
768780
case Hole(_, idx, args, _) =>
769781
writeByte(HOLE)
770782
withLength {

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

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,9 +1396,9 @@ class TreeUnpickler(reader: TastyReader,
13961396
val fn = readTree()
13971397
val args = until(end)(readTree())
13981398
if fn.symbol.isConstructor then constructorApply(fn, args)
1399-
else if fn.symbol == defn.QuotedRuntime_exprQuote then quotedExpr(fn, args)
1400-
else if fn.symbol == defn.QuotedRuntime_exprSplice then splicedExpr(fn, args)
1401-
else if fn.symbol == defn.QuotedRuntime_exprNestedSplice then nestedSpliceExpr(fn, args)
1399+
else if fn.symbol == defn.QuotedRuntime_exprQuote then quotedExpr(fn, args) // decode pre 3.5.0 encoding
1400+
else if fn.symbol == defn.QuotedRuntime_exprSplice then splicedExpr(fn, args) // decode pre 3.5.0 encoding
1401+
else if fn.symbol == defn.QuotedRuntime_exprNestedSplice then nestedSpliceExpr(fn, args) // decode pre 3.5.0 encoding
14021402
else tpd.Apply(fn, args)
14031403
case TYPEAPPLY =>
14041404
tpd.TypeApply(readTree(), until(end)(readTpt()))
@@ -1520,7 +1520,7 @@ class TreeUnpickler(reader: TastyReader,
15201520
val unapply = UnApply(fn, implicitArgs, argPats, patType)
15211521
if fn.symbol == defn.QuoteMatching_ExprMatch_unapply
15221522
|| fn.symbol == defn.QuoteMatching_TypeMatch_unapply
1523-
then QuotePatterns.decode(unapply)
1523+
then QuotePatterns.decode(unapply) // decode pre 3.5.0 encoding
15241524
else unapply
15251525
case REFINEDtpt =>
15261526
val refineCls = symAtAddr.getOrElse(start,
@@ -1568,6 +1568,24 @@ class TreeUnpickler(reader: TastyReader,
15681568
val hi = if currentAddr == end then lo else readTpt()
15691569
val alias = if currentAddr == end then EmptyTree else readTpt()
15701570
createNullableTypeBoundsTree(lo, hi, alias)
1571+
case QUOTE =>
1572+
Quote(readTree(), Nil).withBodyType(readType())
1573+
case SPLICE =>
1574+
Splice(readTree()).withType(readType())
1575+
case QUOTEPATTERN =>
1576+
val bodyReader = fork
1577+
skipTree()
1578+
val quotes = readTree()
1579+
val patType = readType()
1580+
val bindings = readStats(ctx.owner, end)
1581+
val body = bodyReader.readTree() // need bindings in scope, so needs to be read before
1582+
QuotePattern(bindings, body, quotes, patType)
1583+
case SPLICEPATTERN =>
1584+
val pat = readTree()
1585+
val patType = readType()
1586+
val (targs, args) = until(end)(readTree()).span(_.isType)
1587+
assert(targs.isEmpty, "unexpected type arguments in SPLICEPATTERN") // `targs` will be needed for #18271. Until this fearure is added they should be empty.
1588+
SplicePattern(pat, args, patType)
15711589
case HOLE =>
15721590
readHole(end, isTerm = true)
15731591
case _ =>

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,12 @@ trait TypeAssigner {
531531
def assignType(tree: untpd.UnApply, proto: Type)(using Context): UnApply =
532532
tree.withType(proto)
533533

534+
def assignType(tree: untpd.Splice, expr: Tree)(using Context): Splice =
535+
val tpe = expr.tpe // Quotes ?=> Expr[T]
536+
.baseType(defn.FunctionSymbol(1, isContextual = true)).argTypes.last // Expr[T]
537+
.baseType(defn.QuotedExprClass).argTypes.head // T
538+
tree.withType(tpe)
539+
534540
def assignType(tree: untpd.QuotePattern, proto: Type)(using Context): QuotePattern =
535541
tree.withType(proto)
536542

tasty/src/dotty/tools/tasty/TastyFormat.scala

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,14 @@ Standard-Section: "ASTs" TopLevelStat*
110110
WHILE Length cond_Term body_Term -- while cond do body
111111
REPEATED Length elem_Type elem_Term* -- Varargs argument of type `elem`
112112
SELECTouter Length levels_Nat qual_Term underlying_Type -- Follow `levels` outer links, starting from `qual`, with given `underlying` type
113+
QUOTE Length body_Term bodyTpe_Type -- Quoted expression `'{ body }` of a body typed as `bodyTpe`
114+
SPLICE Length expr_Term tpe_Type -- Spliced expression `${ expr }` typed as `tpe`
115+
SPLICEPATTEN Length pat_Term tpe_Type targs_Type* args_Term* -- Pattern splice `${pat}` or `$pat[targs*](args*)` in a quoted pattern of type `tpe`.
113116
-- patterns:
114117
BIND Length boundName_NameRef patType_Type pat_Term -- name @ pat, wherev `patType` is the type of the bound symbol
115118
ALTERNATIVE Length alt_Term* -- alt1 | ... | altn as a pattern
116119
UNAPPLY Length fun_Term ImplicitArg* pat_Type pat_Term* -- Unapply node `fun(_: pat_Type)(implicitArgs)` flowing into patterns `pat`.
120+
QUOTEPATTERN Length body_Term quotes_Term pat_Type bindings_Term* -- Quote pattern node `'{ bindings*; body }(using quotes)`
117121
-- type trees:
118122
IDENTtpt NameRef Type -- Used for all type idents
119123
SELECTtpt NameRef qual_Term -- qual.name
@@ -544,7 +548,6 @@ object TastyFormat {
544548
final val EXPLICITtpt = 103
545549
final val ELIDED = 104
546550

547-
548551
// Tree Cat. 4: tag Nat AST
549552
final val firstNatASTTreeTag = IDENT
550553
final val IDENT = 110
@@ -610,10 +613,12 @@ object TastyFormat {
610613
final val TYPEREFin = 175
611614
final val SELECTin = 176
612615
final val EXPORT = 177
613-
// final val ??? = 178
614-
// final val ??? = 179
616+
final val QUOTE = 178
617+
final val SPLICE = 179
615618
final val METHODtype = 180
616619
final val APPLYsigpoly = 181
620+
final val QUOTEPATTERN = 182
621+
final val SPLICEPATTERN = 183
617622

618623
final val MATCHtype = 190
619624
final val MATCHtpt = 191
@@ -858,6 +863,10 @@ object TastyFormat {
858863
case PROTECTEDqualified => "PROTECTEDqualified"
859864
case EXPLICITtpt => "EXPLICITtpt"
860865
case ELIDED => "ELIDED"
866+
case QUOTE => "QUOTE"
867+
case SPLICE => "SPLICE"
868+
case QUOTEPATTERN => "QUOTEPATTERN"
869+
case SPLICEPATTERN => "SPLICEPATTERN"
861870
case HOLE => "HOLE"
862871
}
863872

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)