From 4b7da46f1ddda1c636aa6603fe20a2b8aaff6258 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 11 Apr 2024 17:30:21 +0200 Subject: [PATCH] Add quote ASTs to TASTy --- .../tools/dotc/core/tasty/TreePickler.scala | 40 ++++++++++--------- .../tools/dotc/core/tasty/TreeUnpickler.scala | 21 +++++++++- tasty/src/dotty/tools/tasty/TastyFormat.scala | 15 +++++-- 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 0a8669292a74..e2c3b8d0c4b2 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -701,28 +701,32 @@ 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[]() - 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[]() - 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) + withLength { + pickleTree(expr) + pickleType(tree.tpe) // TODO is is possible to recompute this type from `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) + args.foreach(pickleTree) + } case Hole(_, idx, args, _) => writeByte(HOLE) withLength { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 073edb536151..6a1372916678 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -1314,6 +1314,9 @@ class TreeUnpickler(reader: TastyReader, NamedArg(readName(), readTree()) case EXPLICITtpt => readTpt() + case QUOTE => + val body = readTree() + Quote(body, Nil) case _ => readPathTree() } @@ -1503,7 +1506,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, @@ -1551,6 +1554,22 @@ 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 SPLICE => + val expr = readTree() + val tpe = readType() // TODO is is possible to recompute this type from `expr`? + Splice(expr, tpe) + 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 args = until(end)(readTree()) + untpd.SplicePattern(pat, args) // TODO set type? case HOLE => readHole(end, isTerm = true) case _ => diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index 6cd63d0d8f01..c0c707beb918 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -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 Length expr_Term tpe_Type -- Spliced expression `${ expr }` with type `tpe` + SPLICEPATTEN Length pat_Term args_Term* -- Pattern splice `${pat}` or `$pat(args*)` in a quoted pattern -- 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 @@ -543,6 +547,7 @@ object TastyFormat { final val BOUNDED = 102 final val EXPLICITtpt = 103 final val ELIDED = 104 + final val QUOTE = 105 // Tree Cat. 4: tag Nat AST @@ -600,7 +605,7 @@ object TastyFormat { final val ANDtype = 165 // final val ??? = 166 final val ORtype = 167 - // final val ??? = 168 + final val SPLICE = 168 final val POLYtype = 169 final val TYPELAMBDAtype = 170 final val LAMBDAtpt = 171 @@ -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 @@ -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" }