Skip to content

Unencode quote and splice trees #17342

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

Merged
merged 46 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
c2f6362
Rename `Spliced` to `SplicedExpr`
nicolasstucki Apr 21, 2023
938d3ae
Split `Quoted` extractor into `QuotedExpr` and `QuotedTypeOf`
nicolasstucki Apr 21, 2023
b7ca9b1
Split `transformQuotation` into `transformQuotedExpr` and `transformQ…
nicolasstucki Apr 21, 2023
deb03a7
Add `QuotedExpr` to encode quotes directly in the AST
nicolasstucki Apr 21, 2023
b7a7227
Add `SplicedExpr` to encode splices directly in the AST
nicolasstucki Apr 21, 2023
fe64a3e
Remove splice outer quotes context
nicolasstucki Apr 25, 2023
161ef49
Rename `SplicedExpr.{spliced=>expr}`
nicolasstucki Apr 25, 2023
cf30d30
Use QuotedExpr instead of Quote trees
nicolasstucki Apr 25, 2023
f0d758b
Use SplicedExpr instead of Splice trees
nicolasstucki Apr 25, 2023
c6adab8
Move typedQuotedExpr/typedSplicedExpr to QuotesAndSplices
nicolasstucki Apr 25, 2023
3a045c4
Rename QuotedExpr to Quote and SplicedExpr to Splice
nicolasstucki Apr 25, 2023
76d0daf
Add documentation
nicolasstucki Apr 25, 2023
75bacdb
Backwards compatibility support for quotes and splice in reflection API
nicolasstucki Apr 25, 2023
0e6dc2e
Add regression test
nicolasstucki Apr 25, 2023
cdd5ffb
Adapt REPL test output
nicolasstucki Apr 26, 2023
04f020f
Remove `Splice.isInBraces`
nicolasstucki Apr 27, 2023
35db4a1
Move Quote/Splice retyping into ReTyper
nicolasstucki Apr 27, 2023
1ef7f59
Add documentation
nicolasstucki Apr 27, 2023
687d06e
Transform Quote/Splice in MiniPhase
nicolasstucki Apr 27, 2023
1f62049
Add TODOs and fix typos
nicolasstucki Apr 28, 2023
5ae7861
Remove `tpt` from `Quote`
nicolasstucki Apr 28, 2023
3976d06
Remove `tpt` from `Splice`
nicolasstucki Apr 28, 2023
d4b2f09
Rename `Quote.{expr=>body}`
nicolasstucki Apr 28, 2023
35408ec
Fix staging level tracking in Transformer
nicolasstucki Apr 28, 2023
e73eab7
Cleanup unnecessary staging level updates
nicolasstucki Apr 28, 2023
e06b0f9
Use `Quote to encode `Type.of` in the `staging phase`
nicolasstucki May 1, 2023
095a7f1
Remove state from TreeMapWithStages
nicolasstucki May 1, 2023
10cbc60
Fix wrong staging level error message
nicolasstucki May 1, 2023
3097f49
Simplify quoted type transformation in CrossStageSafety
nicolasstucki May 1, 2023
8a9871f
Simplify Quote/Splice transformations in CrossStageSafety
nicolasstucki May 1, 2023
966835b
Deduplicate code that transforms `Quote`, `Splice`, `Type.of`
nicolasstucki May 1, 2023
95c39bc
Cleanup
nicolasstucki May 1, 2023
0ca6066
Remove redundant case
nicolasstucki May 1, 2023
e3735fa
Refactor
nicolasstucki May 1, 2023
6956c43
Refactor quote cancellation logic
nicolasstucki May 1, 2023
859f6e6
Remove unnecessary quotation level change
nicolasstucki May 1, 2023
e4ddc88
Add missing change of staging level
nicolasstucki May 1, 2023
7e8d2b1
Simplify macroDependencies using level from context
nicolasstucki May 1, 2023
a3c657b
Fix typo
nicolasstucki May 1, 2023
be3cd48
Refactor use of Quote
nicolasstucki May 1, 2023
7bd7c92
Do not traverse type trees to find inline method calls
nicolasstucki May 1, 2023
b991b40
Remove post-condition that is already checked by Staging
nicolasstucki May 1, 2023
e611139
Refactor quote pickling case
nicolasstucki May 1, 2023
37200be
Cleanup
nicolasstucki May 1, 2023
e75cafe
Remove unnecessary widening
nicolasstucki May 1, 2023
9214daa
Apply suggestions from code review
nicolasstucki May 1, 2023
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: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -338,9 +338,9 @@ object desugar {
def quotedPattern(tree: untpd.Tree, expectedTpt: untpd.Tree)(using Context): untpd.Tree = {
def adaptToExpectedTpt(tree: untpd.Tree): untpd.Tree = tree match {
// Add the expected type as an ascription
case _: untpd.Splice =>
case _: untpd.SplicedExpr =>
untpd.Typed(tree, expectedTpt).withSpan(tree.span)
case Typed(expr: untpd.Splice, tpt) =>
case Typed(expr: untpd.SplicedExpr, tpt) =>
cpy.Typed(tree)(expr, untpd.makeAndType(tpt, expectedTpt).withSpan(tpt.span))

// Propagate down the expected type to the leafs of the expression
Expand Down Expand Up @@ -1989,7 +1989,7 @@ object desugar {
case QuotedExpr(expr, _) =>
new UntypedTreeTraverser {
def traverse(tree: untpd.Tree)(using Context): Unit = tree match {
case Splice(expr) => collect(expr)
case SplicedExpr(expr, _) => collect(expr)
case _ => traverseChildren(tree)
}
}.traverse(expr)
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,7 @@ object Trees {
case class SplicedExpr[+T <: Untyped] private[ast] (expr: Tree[T], tpt: Tree[T])(implicit @constructorOnly src: SourceFile)
extends TermTree[T] {
type ThisTree[+T <: Untyped] = SplicedExpr[T]
def isInBraces: Boolean = span.end != expr.span.end
}

/** A type tree that represents an existing or inferred type */
Expand Down
11 changes: 0 additions & 11 deletions compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
override def isType: Boolean = !isTerm
}
case class Throw(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
case class Splice(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree {
def isInBraces: Boolean = span.end != expr.span.end
}
case class ForYield(enums: List[Tree], expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
case class ForDo(enums: List[Tree], body: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
case class GenFrom(pat: Tree, expr: Tree, checkMode: GenCheckMode)(implicit @constructorOnly src: SourceFile) extends Tree
Expand Down Expand Up @@ -623,10 +620,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
case tree: Throw if expr eq tree.expr => tree
case _ => finalize(tree, untpd.Throw(expr)(tree.source))
}
def Splice(tree: Tree)(expr: Tree)(using Context): Tree = tree match {
case tree: Splice if expr eq tree.expr => tree
case _ => finalize(tree, untpd.Splice(expr)(tree.source))
}
def ForYield(tree: Tree)(enums: List[Tree], expr: Tree)(using Context): TermTree = tree match {
case tree: ForYield if (enums eq tree.enums) && (expr eq tree.expr) => tree
case _ => finalize(tree, untpd.ForYield(enums, expr)(tree.source))
Expand Down Expand Up @@ -708,8 +701,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
cpy.Tuple(tree)(transform(trees))
case Throw(expr) =>
cpy.Throw(tree)(transform(expr))
case Splice(expr) =>
cpy.Splice(tree)(transform(expr))
case ForYield(enums, expr) =>
cpy.ForYield(tree)(transform(enums), transform(expr))
case ForDo(enums, body) =>
Expand Down Expand Up @@ -767,8 +758,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
this(x, trees)
case Throw(expr) =>
this(x, expr)
case Splice(expr) =>
this(x, expr)
case ForYield(enums, expr) =>
this(this(x, enums), expr)
case ForDo(enums, body) =>
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1764,7 +1764,7 @@ object Parsers {
syntaxError(em"$msg\n\nHint: $hint", Span(start, in.lastOffset))
Ident(nme.ERROR.toTypeName)
else
Splice(expr)
SplicedExpr(expr, EmptyTree)
}

/** SimpleType ::= SimpleLiteral
Expand Down
4 changes: 1 addition & 3 deletions compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -712,8 +712,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}
case Number(digits, kind) =>
digits
case Splice(tree) =>
keywordStr("${") ~ toTextGlobal(dropBlock(tree)) ~ keywordStr("}")
case Thicket(trees) =>
"Thicket {" ~~ toTextGlobal(trees, "\n") ~~ "}"
case MacroTree(call) =>
Expand All @@ -722,7 +720,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
val tptText = (keywordStr("[") ~ toTextGlobal(tpt) ~ keywordStr("]")).provided(!tpt.isEmpty && printDebug)
keywordStr("'") ~ tptText ~ keywordStr("{") ~ toTextGlobal(expr) ~ keywordStr("}")
case SplicedExpr(expr, tpt) =>
val tptText = (keywordStr("[") ~ toTextGlobal(tpt) ~ keywordStr("]")).provided(printDebug)
val tptText = (keywordStr("[") ~ toTextGlobal(tpt) ~ keywordStr("]")).provided(!tpt.isEmpty && printDebug)
keywordStr("$") ~ tptText ~ keywordStr("{") ~ toTextGlobal(expr) ~ keywordStr("}")
case Hole(isTermHole, idx, args, content, tpt) =>
val (prefix, postfix) = if isTermHole then ("{{{", "}}}") else ("[[[", "]]]")
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1097,7 +1097,7 @@ trait Applications extends Compatibility {
}
else {
val app = tree.fun match
case _: untpd.Splice if ctx.mode.is(Mode.QuotedPattern) => typedAppliedSplice(tree, pt)
case _: untpd.SplicedExpr if ctx.mode.is(Mode.QuotedPattern) => typedAppliedSplice(tree, pt)
case _ => realApply
app match {
case Apply(fn @ Select(left, _), right :: Nil) if fn.hasType =>
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ trait QuotesAndSplices {
def typedQuote(tree: untpd.QuotedExpr, pt: Type)(using Context): Tree = {
record("typedQuote")
tree.expr match {
case untpd.Splice(innerExpr) if tree.isTerm && !ctx.mode.is(Mode.Pattern) =>
case untpd.SplicedExpr(innerExpr, _) if tree.isTerm && !ctx.mode.is(Mode.Pattern) =>
report.warning("Canceled splice directly inside a quote. '{ ${ XYZ } } is equivalent to XYZ.", tree.srcPos)
case _ =>
}
Expand Down Expand Up @@ -70,7 +70,7 @@ trait QuotesAndSplices {
}

/** Translate `${ t: Expr[T] }` into expression `t.splice` while tracking the quotation level in the context */
def typedSplice(tree: untpd.Splice, pt: Type)(using Context): Tree = {
def typedSplice(tree: untpd.SplicedExpr, pt: Type)(using Context): Tree = {
record("typedSplice")
checkSpliceOutsideQuote(tree)
tree.expr match {
Expand Down Expand Up @@ -123,7 +123,7 @@ trait QuotesAndSplices {
*/
def typedAppliedSplice(tree: untpd.Apply, pt: Type)(using Context): Tree = {
assert(ctx.mode.is(Mode.QuotedPattern))
val untpd.Apply(splice: untpd.Splice, args) = tree: @unchecked
val untpd.Apply(splice: untpd.SplicedExpr, args) = tree: @unchecked
if !isFullyDefined(pt, ForceDegree.flipBottom) then
report.error(em"Type must be fully defined.", splice.srcPos)
tree.withType(UnspecifiedErrorType)
Expand Down
16 changes: 9 additions & 7 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2054,12 +2054,15 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
assignType(cpy.QuotedExpr(tree)(expr1, tpt1), tpt1)

def typedSplicedExpr(tree: untpd.SplicedExpr, pt: Type)(using Context): Tree =
val tpt1 = checkSimpleKinded(typedType(tree.tpt, mapPatternBounds = true))
val splicedType = // Quotes ?=> Expr[T]
defn.FunctionType(1, isContextual = true)
.appliedTo(defn.QuotesClass.typeRef, defn.QuotedExprClass.typeRef.appliedTo(tpt1.tpe.widenSkolem))
val expr1 = typed(tree.expr, splicedType)(using StagingLevel.spliceContext)
assignType(cpy.SplicedExpr(tree)(expr1, tpt1), tpt1)
if tree.tpt.isEmpty then
typedSplice(tree, pt)
else
val tpt1 = checkSimpleKinded(typedType(tree.tpt, mapPatternBounds = true))
val splicedType = // Quotes ?=> Expr[T]
defn.FunctionType(1, isContextual = true)
.appliedTo(defn.QuotesClass.typeRef, defn.QuotedExprClass.typeRef.appliedTo(tpt1.tpe.widenSkolem))
val expr1 = typed(tree.expr, splicedType)(using StagingLevel.spliceContext)
assignType(cpy.SplicedExpr(tree)(expr1, tpt1), tpt1)

def completeTypeTree(tree: untpd.TypeTree, pt: Type, original: untpd.Tree)(using Context): TypeTree =
tree.withSpan(original.span).withAttachmentsFrom(original)
Expand Down Expand Up @@ -3092,7 +3095,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
case tree @ untpd.PostfixOp(qual, Ident(nme.WILDCARD)) => typedAsFunction(tree, pt)
case untpd.EmptyTree => tpd.EmptyTree
case tree: untpd.QuotedExpr => typedQuotedExpr(tree, pt)
case tree: untpd.Splice => typedSplice(tree, pt)
case tree: untpd.SplicedExpr => typedSplicedExpr(tree, pt)
case tree: untpd.MacroTree => report.error("Unexpected macro", tree.srcPos); tpd.nullLiteral // ill-formed code may reach here
case tree: untpd.Hole => typedHole(tree, pt)
Expand Down