Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add quote ASTs to TASTy #20165

Merged
merged 3 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
48 changes: 30 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,40 @@ 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)
withLength {
pickleTree(body)
pickleType(tree.bodyType)
}
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)
withLength {
pickleTree(expr)
pickleType(tree.tpe)
}
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) =>
val targs = Nil // SplicePattern `targs` will be added with #18271
writeByte(SPLICEPATTERN)
withLength {
pickleTree(pat)
pickleType(tree.tpe)
for targ <- targs do
writeByte(EXPLICITtpt)
pickleTree(targ)
args.foreach(pickleTree)
}
case Hole(_, idx, args, _) =>
writeByte(HOLE)
withLength {
Expand Down
26 changes: 22 additions & 4 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1379,9 +1379,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 +1503,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 +1551,24 @@ 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 QUOTE =>
Quote(readTree(), Nil).withBodyType(readType())
case SPLICE =>
Splice(readTree()).withType(readType())
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 (targs, args) = until(end)(readTree()).span(_.isType)
assert(targs.isEmpty, "unexpected type arguments in SPLICEPATTERN") // `targs` will be needed for #18271. Until this fearure is added they should be empty.
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 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:
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 @@ -544,7 +548,6 @@ object TastyFormat {
final val EXPLICITtpt = 103
final val ELIDED = 104


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

final val MATCHtype = 190
final val MATCHtpt = 191
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.