Skip to content

Commit 76d9eb7

Browse files
Merge pull request #9381 from dotty-staging/refactor-type-splice-logic
Refactor type splice logic
2 parents b7b03b3 + 88630ae commit 76d9eb7

File tree

10 files changed

+76
-40
lines changed

10 files changed

+76
-40
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 type 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/ast/tpd.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -891,19 +891,19 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
891891
selectWithSig(sym.name, sym.signature)
892892

893893
/** A unary apply node with given argument: `tree(arg)` */
894-
def appliedTo(arg: Tree)(using Context): Tree =
894+
def appliedTo(arg: Tree)(using Context): Apply =
895895
appliedToArgs(arg :: Nil)
896896

897897
/** An apply node with given arguments: `tree(arg, args0, ..., argsN)` */
898-
def appliedTo(arg: Tree, args: Tree*)(using Context): Tree =
898+
def appliedTo(arg: Tree, args: Tree*)(using Context): Apply =
899899
appliedToArgs(arg :: args.toList)
900900

901901
/** An apply node with given argument list `tree(args(0), ..., args(args.length - 1))` */
902902
def appliedToArgs(args: List[Tree])(using Context): Apply =
903903
Apply(tree, args)
904904

905905
/** An applied node that accepts only varargs as arguments */
906-
def appliedToVarargs(args: List[Tree], tpt: Tree)(using Context): Tree =
906+
def appliedToVarargs(args: List[Tree], tpt: Tree)(using Context): Apply =
907907
appliedTo(repeated(args, tpt))
908908

909909
/** The current tree applied to given argument lists:

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ class Definitions {
710710
@tu lazy val InternalQuotedType_unapply: Symbol = InternalQuotedTypeModule.requiredMethod(nme.unapply)
711711

712712
@tu lazy val QuotedTypeClass: ClassSymbol = ctx.requiredClass("scala.quoted.Type")
713-
@tu lazy val QuotedType_splice: Symbol = QuotedTypeClass.requiredType(tpnme.splice)
713+
@tu lazy val QuotedType_splice: Symbol = QuotedTypeClass.requiredType(tpnme.spliceType)
714714

715715
@tu lazy val QuotedTypeModule: Symbol = QuotedTypeClass.companionModule
716716

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ object StdNames {
578578
val setSymbol: N = "setSymbol"
579579
val setType: N = "setType"
580580
val setTypeSignature: N = "setTypeSignature"
581-
val splice: N = "$splice"
581+
val spliceType: N = "T"
582582
val standardInterpolator: N = "standardInterpolator"
583583
val staticClass : N = "staticClass"
584584
val staticModule : N = "staticModule"

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

Lines changed: 12 additions & 9 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
@@ -267,13 +270,13 @@ object PCPCheckAndHeal {
267270

268271
private def mkTagSymbolAndAssignType(spliced: TermRef): TypeDef = {
269272
val splicedTree = tpd.ref(spliced).withSpan(span)
270-
val rhs = splicedTree.select(tpnme.splice).withSpan(span)
273+
val rhs = splicedTree.select(tpnme.spliceType).withSpan(span)
271274
val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs, EmptyTree)
272275
val local = ctx.newSymbol(
273276
owner = ctx.owner,
274277
name = UniqueName.fresh((splicedTree.symbol.name.toString + "$_").toTermName).toTypeName,
275278
flags = Synthetic,
276-
info = TypeAlias(splicedTree.tpe.select(tpnme.splice)),
279+
info = TypeAlias(splicedTree.tpe.select(tpnme.spliceType)),
277280
coord = span).asType
278281
local.addAnnotation(Annotation(defn.InternalQuoted_QuoteTypeTagAnnot))
279282
ctx.typeAssigner.assignType(untpd.TypeDef(local.name, alias), local)

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.spliceType))
374+
else
375+
val splice = ref(defn.InternalQuoted_exprSplice).appliedToType(tree.tpe).appliedTo(body)
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
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,9 @@ trait QuotesAndSplices {
170170
typeSym.addAnnotation(Annotation(New(ref(defn.InternalQuotedMatcher_patternTypeAnnot.typeRef)).withSpan(tree.expr.span)))
171171
val pat = typedPattern(tree.expr, defn.QuotedTypeClass.typeRef.appliedTo(typeSym.typeRef))(
172172
using spliceContext.retractMode(Mode.QuotedPattern).withOwner(spliceOwner(ctx)))
173-
pat.select(tpnme.splice)
173+
pat.select(tpnme.spliceType)
174174
else
175-
typedSelect(untpd.Select(tree.expr, tpnme.splice), pt)(using spliceContext).withSpan(tree.span)
175+
typedSelect(untpd.Select(tree.expr, tpnme.spliceType), pt)(using spliceContext).withSpan(tree.span)
176176
}
177177

178178
private def checkSpliceOutsideQuote(tree: untpd.Tree)(using Context): Unit =

library/src-bootstrapped/scala/quoted/Type.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ package scala.quoted
33
import scala.quoted.show.SyntaxHighlight
44

55
/** Quoted type (or kind) `T` */
6-
abstract class Type[T <: AnyKind] private[scala] {
7-
type `$splice` = T
6+
abstract class Type[X <: AnyKind] private[scala] {
7+
type T = X
88

99
/** Show a source code like representation of this type without syntax highlight */
1010
def show(using qctx: QuoteContext): String =

0 commit comments

Comments
 (0)