Skip to content

Commit

Permalink
Add quote ASTs to TASTy
Browse files Browse the repository at this point in the history
Add AST nodes for Quote, Splice, QuotePattern, and QuoteSplice to TASTy.
  • Loading branch information
nicolasstucki committed Apr 12, 2024
1 parent 62e0641 commit e12cb19
Show file tree
Hide file tree
Showing 14 changed files with 72 additions and 25 deletions.
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def Splice(expr: Tree, tpe: Type)(using Context): Splice =
untpd.Splice(expr).withType(tpe)

def Splice(expr: Tree)(using Context): Splice =
ta.assignType(untpd.Splice(expr), expr)

def SplicePattern(pat: Tree, args: List[Tree], tpe: Type)(using Context): SplicePattern =
untpd.SplicePattern(pat, args).withType(tpe)

def Hole(isTerm: Boolean, idx: Int, args: List[Tree], content: Tree, tpe: Type)(using Context): Hole =
untpd.Hole(isTerm, idx, args, content).withType(tpe)

Expand Down
41 changes: 23 additions & 18 deletions compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -701,28 +701,33 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) {
pickleTree(alias)
}
case tree @ Quote(body, Nil) =>
// TODO: Add QUOTE tag to TASTy
assert(body.isTerm,
"""Quote with type should not be pickled.
|Quote with type should only exists after staging phase at staging level 0.""".stripMargin)
pickleTree(
// scala.quoted.runtime.Expr.quoted[<tree.bodyType>](<body>)
ref(defn.QuotedRuntime_exprQuote)
.appliedToType(tree.bodyType)
.appliedTo(body)
.withSpan(tree.span)
)
writeByte(QUOTE)
pickleTree(body)
case Splice(expr) =>
pickleTree( // TODO: Add SPLICE tag to TASTy
// scala.quoted.runtime.Expr.splice[<tree.tpe>](<expr>)
ref(defn.QuotedRuntime_exprSplice)
.appliedToType(tree.tpe)
.appliedTo(expr)
.withSpan(tree.span)
)
case tree: QuotePattern =>
// TODO: Add QUOTEPATTERN tag to TASTy
pickleTree(QuotePatterns.encode(tree))
writeByte(SPLICE)
pickleTree(expr)
case QuotePattern(bindings, body, quotes) =>
writeByte(QUOTEPATTERN)
withLength {
if body.isType then writeByte(EXPLICITtpt)
pickleTree(body)
pickleTree(quotes)
pickleType(tree.tpe)
bindings.foreach(pickleTree)
}
case SplicePattern(pat, args) =>
writeByte(SPLICEPATTERN)
withLength {
pickleTree(pat)
pickleType(tree.tpe)
args.foreach(pickleTree)
// TODO: Handle `targs` for #18271. We should be able to pickle the
// `targs ::: args` if we add an `EXPLICITtpt` to the targs.
// See comment in SPLICEPATTERN unpickling.
}
case Hole(_, idx, args, _) =>
writeByte(HOLE)
withLength {
Expand Down
29 changes: 25 additions & 4 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,10 @@ class TreeUnpickler(reader: TastyReader,
NamedArg(readName(), readTree())
case EXPLICITtpt =>
readTpt()
case QUOTE =>
Quote(readTree(), Nil)
case SPLICE =>
Splice(readTree())
case _ =>
readPathTree()
}
Expand Down Expand Up @@ -1379,9 +1383,9 @@ class TreeUnpickler(reader: TastyReader,
val fn = readTree()
val args = until(end)(readTree())
if fn.symbol.isConstructor then constructorApply(fn, args)
else if fn.symbol == defn.QuotedRuntime_exprQuote then quotedExpr(fn, args)
else if fn.symbol == defn.QuotedRuntime_exprSplice then splicedExpr(fn, args)
else if fn.symbol == defn.QuotedRuntime_exprNestedSplice then nestedSpliceExpr(fn, args)
else if fn.symbol == defn.QuotedRuntime_exprQuote then quotedExpr(fn, args) // decode pre 3.5.0 encoding
else if fn.symbol == defn.QuotedRuntime_exprSplice then splicedExpr(fn, args) // decode pre 3.5.0 encoding
else if fn.symbol == defn.QuotedRuntime_exprNestedSplice then nestedSpliceExpr(fn, args) // decode pre 3.5.0 encoding
else tpd.Apply(fn, args)
case TYPEAPPLY =>
tpd.TypeApply(readTree(), until(end)(readTpt()))
Expand Down Expand Up @@ -1503,7 +1507,7 @@ class TreeUnpickler(reader: TastyReader,
val unapply = UnApply(fn, implicitArgs, argPats, patType)
if fn.symbol == defn.QuoteMatching_ExprMatch_unapply
|| fn.symbol == defn.QuoteMatching_TypeMatch_unapply
then QuotePatterns.decode(unapply)
then QuotePatterns.decode(unapply) // decode pre 3.5.0 encoding
else unapply
case REFINEDtpt =>
val refineCls = symAtAddr.getOrElse(start,
Expand Down Expand Up @@ -1551,6 +1555,23 @@ class TreeUnpickler(reader: TastyReader,
val hi = if currentAddr == end then lo else readTpt()
val alias = if currentAddr == end then EmptyTree else readTpt()
createNullableTypeBoundsTree(lo, hi, alias)
case QUOTEPATTERN =>
val bodyReader = fork
skipTree()
val quotes = readTree()
val patType = readType()
val bindings = readStats(ctx.owner, end)
val body = bodyReader.readTree() // need bindings in scope, so needs to be read before
QuotePattern(bindings, body, quotes, patType)
case SPLICEPATTERN =>
val pat = readTree()
val patType = readType()
val args = until(end)(readTree())
// TODO: for #18271 we need to split the targs from the args.
// Probably need somthing like this:
// val (targs, args) = until(end)(readTree()).span(_.isType)
// See comment in SPLICEPATTERN pickling
SplicePattern(pat, args, patType)
case HOLE =>
readHole(end, isTerm = true)
case _ =>
Expand Down
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,12 @@ trait TypeAssigner {
def assignType(tree: untpd.UnApply, proto: Type)(using Context): UnApply =
tree.withType(proto)

def assignType(tree: untpd.Splice, expr: Tree)(using Context): Splice =
val tpe = expr.tpe // Quotes ?=> Expr[T]
.baseType(defn.FunctionSymbol(1, isContextual = true)).argTypes.last // Expr[T]
.baseType(defn.QuotedExprClass).argTypes.head // T
tree.withType(tpe)

def assignType(tree: untpd.QuotePattern, proto: Type)(using Context): QuotePattern =
tree.withType(proto)

Expand Down
15 changes: 12 additions & 3 deletions tasty/src/dotty/tools/tasty/TastyFormat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,14 @@ Standard-Section: "ASTs" TopLevelStat*
WHILE Length cond_Term body_Term -- while cond do body
REPEATED Length elem_Type elem_Term* -- Varargs argument of type `elem`
SELECTouter Length levels_Nat qual_Term underlying_Type -- Follow `levels` outer links, starting from `qual`, with given `underlying` type
QUOTE body_Term -- Quoted expression `'{ body }`
SPLICE expr_Term -- Spliced expression `${ expr }`
SPLICEPATTEN Length pat_Term tpe_Type args_Term* -- Pattern splice `${pat}` or `$pat(args*)` in a quoted pattern of type `tpe`
-- patterns:
BIND Length boundName_NameRef patType_Type pat_Term -- name @ pat, wherev `patType` is the type of the bound symbol
ALTERNATIVE Length alt_Term* -- alt1 | ... | altn as a pattern
UNAPPLY Length fun_Term ImplicitArg* pat_Type pat_Term* -- Unapply node `fun(_: pat_Type)(implicitArgs)` flowing into patterns `pat`.
QUOTEPATTERN Length body_Term quotes_Term pat_Type bindings_Term* -- Quote pattern node `'{ bindings*; body }(using quotes)`
-- type trees:
IDENTtpt NameRef Type -- Used for all type idents
SELECTtpt NameRef qual_Term -- qual.name
Expand Down Expand Up @@ -543,7 +547,8 @@ object TastyFormat {
final val BOUNDED = 102
final val EXPLICITtpt = 103
final val ELIDED = 104

final val QUOTE = 105
final val SPLICE = 106

// Tree Cat. 4: tag Nat AST
final val firstNatASTTreeTag = IDENT
Expand Down Expand Up @@ -610,8 +615,8 @@ object TastyFormat {
final val TYPEREFin = 175
final val SELECTin = 176
final val EXPORT = 177
// final val ??? = 178
// final val ??? = 179
final val QUOTEPATTERN = 178
final val SPLICEPATTERN = 179
final val METHODtype = 180
final val APPLYsigpoly = 181

Expand Down Expand Up @@ -858,6 +863,10 @@ object TastyFormat {
case PROTECTEDqualified => "PROTECTEDqualified"
case EXPLICITtpt => "EXPLICITtpt"
case ELIDED => "ELIDED"
case QUOTE => "QUOTE"
case SPLICE => "SPLICE"
case QUOTEPATTERN => "QUOTEPATTERN"
case SPLICEPATTERN => "SPLICEPATTERN"
case HOLE => "HOLE"
}

Expand Down
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.
File renamed without changes.
File renamed without changes.

0 comments on commit e12cb19

Please sign in to comment.