Skip to content

Commit f4f3304

Browse files
committed
Refactor type splice logic
Specialize the matching and handling of term/type splices. This avoids unnecessary operations on either.
1 parent 5cdfd31 commit f4f3304

File tree

5 files changed

+65
-29
lines changed

5 files changed

+65
-29
lines changed

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -879,15 +879,22 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
879879

880880
/** Extractors for splices */
881881
object Spliced {
882-
/** Extracts the content of a spliced tree.
883-
* The result can be the contents of a term or type splice, which
884-
* will return a term or type tree respectively.
882+
/** Extracts the content of a spliced expresion tree.
883+
* The result can be the contents of a term splice, which
884+
* will return a term tree.
885885
*/
886-
def unapply(tree: tpd.Tree)(using Context): Option[tpd.Tree] = tree match {
887-
case tree: tpd.Apply if tree.symbol.isSplice => Some(tree.args.head)
888-
case tree: tpd.Select if tree.symbol.isSplice => Some(tree.qualifier)
889-
case _ => None
890-
}
886+
def unapply(tree: tpd.Apply)(using Context): Option[tpd.Tree] =
887+
if tree.symbol.isSplice then Some(tree.args.head) else None
888+
}
889+
890+
/** Extractors for splices */
891+
object SplicedType {
892+
/** Extracts the content of a spliced type tree.
893+
* The result can be the contents of a type splice, which
894+
* will return a type tree.
895+
*/
896+
def unapply(tree: tpd.Select)(using Context): Option[tpd.Tree] =
897+
if tree.symbol.isSplice then Some(tree.qualifier) else None
891898
}
892899

893900
/** Extractor for not-null assertions.

compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,25 +123,28 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
123123
* - If inside inlined code, expand the macro code.
124124
* - If inside of a macro definition, check the validity of the macro.
125125
*/
126-
protected def transformSplice(body: Tree, splice: Tree)(using Context): Tree = {
126+
protected def transformSplice(body: Tree, splice: Apply)(using Context): Tree = {
127127
val body1 = transform(body)(using spliceContext)
128-
splice match {
129-
case Apply(fun @ TypeApply(_, _ :: Nil), _) if splice.isTerm =>
128+
splice.fun match {
129+
case fun @ TypeApply(_, _ :: Nil) =>
130130
// Type of the splice itsel must also be healed
131131
// internal.Quoted.expr[F[T]](... T ...) --> internal.Quoted.expr[F[$t]](... T ...)
132132
val tp = healType(splice.sourcePos)(splice.tpe.widenTermRefExpr)
133133
cpy.Apply(splice)(cpy.TypeApply(fun)(fun.fun, tpd.TypeTree(tp) :: Nil), body1 :: Nil)
134-
case Apply(f @ Apply(fun @ TypeApply(_, _), qctx :: Nil), _) if splice.isTerm =>
134+
case f @ Apply(fun @ TypeApply(_, _), qctx :: Nil) =>
135135
// Type of the splice itsel must also be healed
136136
// internal.Quoted.expr[F[T]](... T ...) --> internal.Quoted.expr[F[$t]](... T ...)
137137
val tp = healType(splice.sourcePos)(splice.tpe.widenTermRefExpr)
138138
cpy.Apply(splice)(cpy.Apply(f)(cpy.TypeApply(fun)(fun.fun, tpd.TypeTree(tp) :: Nil), qctx :: Nil), body1 :: Nil)
139-
case splice: Select =>
140-
val tagRef = getQuoteTypeTags.getTagRef(splice.qualifier.tpe.asInstanceOf[TermRef])
141-
ref(tagRef).withSpan(splice.span)
142139
}
143140
}
144141

142+
protected def transformSpliceType(body: Tree, splice: Select)(using Context): Tree = {
143+
val body1 = transform(body)(using spliceContext)
144+
val tagRef = getQuoteTypeTags.getTagRef(splice.qualifier.tpe.asInstanceOf[TermRef])
145+
ref(tagRef).withSpan(splice.span)
146+
}
147+
145148
/** Check that annotations do not contain quotes and and that splices are valid */
146149
private def checkAnnotations(tree: Tree)(using Context): Unit =
147150
tree match

compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,10 @@ class ReifyQuotes extends MacroTransform {
187187
* and make a hole from these parts. Otherwise issue an error, unless we
188188
* are in the body of an inline method.
189189
*/
190-
protected def transformSplice(body: Tree, splice: Tree)(using Context): Tree =
190+
protected def transformSplice(body: Tree, splice: Apply)(using Context): Tree =
191191
if (level > 1) {
192192
val body1 = nested(isQuote = false).transform(body)(using spliceContext)
193-
splice match {
194-
case splice: Apply => cpy.Apply(splice)(splice.fun, body1 :: Nil)
195-
case splice: Select => cpy.Select(splice)(body1, splice.name)
196-
}
193+
cpy.Apply(splice)(splice.fun, body1 :: Nil)
197194
}
198195
else {
199196
assert(level == 1, "unexpected top splice outside quote")
@@ -204,10 +201,26 @@ class ReifyQuotes extends MacroTransform {
204201
// enclosing quote. Any intemediate splice will add it's own Inlined node and cancel it before splicig the lifted tree.
205202
// Note that lifted trees are not necessarily expressions and that Inlined nodes are expected to be expressions.
206203
// For example we can have a lifted tree containing the LHS of an assignment (see tests/run-with-compiler/quote-var.scala).
207-
if (splice.isType || outer.embedded.isLiftedSymbol(body.symbol)) hole
204+
if (outer.embedded.isLiftedSymbol(body.symbol)) hole
208205
else Inlined(EmptyTree, Nil, hole).withSpan(splice.span)
209206
}
210207

208+
/** If inside a quote, split the body of the splice into a core and a list of embedded quotes
209+
* and make a hole from these parts. Otherwise issue an error, unless we
210+
* are in the body of an inline method.
211+
*/
212+
protected def transformSpliceType(body: Tree, splice: Select)(using Context): Tree =
213+
if (level > 1) {
214+
val body1 = nested(isQuote = false).transform(body)(using spliceContext)
215+
cpy.Select(splice)(body1, splice.name)
216+
}
217+
else {
218+
assert(level == 1, "unexpected top splice outside quote")
219+
val (body1, quotes) = nested(isQuote = false).splitSplice(body)(using spliceContext)
220+
val tpe = outer.embedded.getHoleType(body, splice)
221+
makeHole(splice.isTerm, body1, quotes, tpe).withSpan(splice.span)
222+
}
223+
211224
/** Transforms the contents of a nested splice
212225
* Assuming
213226
* '{
@@ -356,11 +369,11 @@ class ReifyQuotes extends MacroTransform {
356369
capturers(body.symbol)(body)
357370
case tree: RefTree if isCaptured(tree.symbol, level) =>
358371
val body = capturers(tree.symbol).apply(tree)
359-
val splice: Tree =
360-
if (tree.isType) body.select(tpnme.splice)
361-
else ref(defn.InternalQuoted_exprSplice).appliedToType(tree.tpe).appliedTo(body)
362-
363-
transformSplice(body, splice)
372+
if (tree.isType)
373+
transformSpliceType(body, body.select(tpnme.splice))
374+
else
375+
val splice = ref(defn.InternalQuoted_exprSplice).appliedToType(tree.tpe).appliedTo(body).asInstanceOf[Apply]
376+
transformSplice(body, splice)
364377

365378
case tree: DefDef if tree.symbol.is(Macro) && level == 0 =>
366379
// Shrink size of the tree. The methods have already been inlined.

compiler/src/dotty/tools/dotc/transform/TreeMapWithStages.scala

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,11 @@ abstract class TreeMapWithStages(@constructorOnly ictx: Context) extends TreeMap
7171
case quote: TypeApply => cpy.TypeApply(quote)(quote.fun, body :: Nil)
7272
}
7373

74-
/** Transform the splice `splice` which contains the spliced `body`. */
75-
protected def transformSplice(body: Tree, splice: Tree)(using Context): Tree
74+
/** Transform the expression splice `splice` which contains the spliced `body`. */
75+
protected def transformSplice(body: Tree, splice: Apply)(using Context): Tree
76+
77+
/** Transform the typee splice `splice` which contains the spliced `body`. */
78+
protected def transformSpliceType(body: Tree, splice: Select)(using Context): Tree
7679

7780
override def transform(tree: Tree)(using Context): Tree =
7881
if (tree.source != ctx.source && tree.source.exists)
@@ -94,7 +97,7 @@ abstract class TreeMapWithStages(@constructorOnly ictx: Context) extends TreeMap
9497
tree match {
9598
case Apply(Select(Quoted(quotedTree), _), _) if quotedTree.isType =>
9699
dropEmptyBlocks(quotedTree) match
97-
case Spliced(t) =>
100+
case SplicedType(t) =>
98101
// '[ x.$splice ] --> x
99102
transform(t)
100103
case _ =>
@@ -121,6 +124,12 @@ abstract class TreeMapWithStages(@constructorOnly ictx: Context) extends TreeMap
121124
}
122125
finally inQuoteOrSplice = old
123126

127+
case tree @ SplicedType(splicedTree) =>
128+
val old = inQuoteOrSplice
129+
inQuoteOrSplice = true
130+
try transformSpliceType(splicedTree, tree)
131+
finally inQuoteOrSplice = old
132+
124133
case Block(stats, _) =>
125134
val last = enteredSyms
126135
stats.foreach(markDef)

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,6 +1450,10 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
14501450
level -= 1
14511451
try apply(syms, body)
14521452
finally level += 1
1453+
case SplicedType(body) =>
1454+
level -= 1
1455+
try apply(syms, body)
1456+
finally level += 1
14531457
case _ =>
14541458
foldOver(syms, tree)
14551459
}

0 commit comments

Comments
 (0)