Skip to content

Commit 036096a

Browse files
authored
Merge pull request #6073 from dotty-staging/remove-splice-private-method
Remove splice internal representation from public API
2 parents 51fb89d + 59a170e commit 036096a

File tree

22 files changed

+125
-66
lines changed

22 files changed

+125
-66
lines changed

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -824,8 +824,11 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
824824
* The result can be the contents of a term or type splice, which
825825
* will return a term or type tree respectively.
826826
*/
827-
def unapply(tree: tpd.Select)(implicit ctx: Context): Option[tpd.Tree] =
828-
if (tree.symbol.isSplice) Some(tree.qualifier) else None
827+
def unapply(tree: tpd.Tree)(implicit ctx: Context): Option[tpd.Tree] = tree match {
828+
case tree: tpd.Apply if tree.symbol.isSplice => Some(tree.args.head)
829+
case tree: tpd.Select if tree.symbol.isSplice => Some(tree.qualifier)
830+
case _ => None
831+
}
829832
}
830833
}
831834

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,12 +704,13 @@ class Definitions {
704704

705705
lazy val QuotedExprType: TypeRef = ctx.requiredClassRef("scala.quoted.Expr")
706706
def QuotedExprClass(implicit ctx: Context): ClassSymbol = QuotedExprType.symbol.asClass
707-
lazy val QuotedExpr_splice : TermSymbol = QuotedExprClass.requiredMethod(nme.splice)
708707

709708
lazy val InternalQuotedModule: TermRef = ctx.requiredModuleRef("scala.internal.Quoted")
710709
def InternalQuotedModuleClass: Symbol = InternalQuotedModule.symbol
711710
lazy val InternalQuoted_exprQuoteR: TermRef = InternalQuotedModuleClass.requiredMethodRef("exprQuote".toTermName)
712711
def InternalQuoted_exprQuote(implicit ctx: Context): Symbol = InternalQuoted_exprQuoteR.symbol
712+
lazy val InternalQuoted_exprSpliceR: TermRef = InternalQuotedModuleClass.requiredMethodRef("exprSplice".toTermName)
713+
def InternalQuoted_exprSplice(implicit ctx: Context): Symbol = InternalQuoted_exprSpliceR.symbol
713714
lazy val InternalQuoted_typeQuoteR: TermRef = InternalQuotedModuleClass.requiredMethodRef("typeQuote".toTermName)
714715
def InternalQuoted_typeQuote(implicit ctx: Context): Symbol = InternalQuoted_typeQuoteR.symbol
715716

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
328328
if (name.isTypeName) typeText(txt)
329329
else txt
330330
case tree @ Select(qual, name) =>
331-
if (tree.hasType && tree.symbol == defn.QuotedExpr_splice) keywordStr("${") ~ toTextLocal(qual) ~ keywordStr("}")
332-
else if (tree.hasType && tree.symbol == defn.QuotedType_splice) typeText("${") ~ toTextLocal(qual) ~ typeText("}")
331+
if (tree.hasType && tree.symbol == defn.QuotedType_splice) typeText("${") ~ toTextLocal(qual) ~ typeText("}")
333332
else if (qual.isType) toTextLocal(qual) ~ "#" ~ typeText(toText(name))
334333
else toTextLocal(qual) ~ ("." ~ nameIdText(tree) provided (name != nme.CONSTRUCTOR || ctx.settings.YprintDebug.value))
335334
case tree: This =>
@@ -343,6 +342,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
343342
}
344343
else if (fun.hasType && fun.symbol == defn.InternalQuoted_exprQuote)
345344
keywordStr("'{") ~ toTextGlobal(args, ", ") ~ keywordStr("}")
345+
else if (fun.hasType && fun.symbol == defn.InternalQuoted_exprSplice)
346+
keywordStr("${") ~ toTextGlobal(args, ", ") ~ keywordStr("}")
346347
else
347348
toTextLocal(fun) ~ "(" ~ toTextGlobal(args, ", ") ~ ")"
348349
case tree: TypeApply =>

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

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,23 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
4949
* - If inside inlined code, expand the macro code.
5050
* - If inside of a macro definition, check the validity of the macro.
5151
*/
52-
protected def transformSplice(splice: Select)(implicit ctx: Context): Tree = {
52+
protected def transformSplice(body: Tree, splice: Tree)(implicit ctx: Context): Tree = {
5353
if (level >= 1) {
54-
val body1 = transform(splice.qualifier)(spliceContext)
55-
val splice1 = cpy.Select(splice)(body1, splice.name)
56-
if (splice1.isType) splice1
57-
else addSpliceCast(splice1)
54+
val body1 = transform(body)(spliceContext)
55+
splice match {
56+
case Apply(fun: TypeApply, _) if splice.isTerm =>
57+
// Type of the splice itsel must also be healed
58+
// internal.Quoted.expr[F[T]](... T ...) --> internal.Quoted.expr[F[$t]](... T ...)
59+
val tp = checkType(splice.sourcePos).apply(splice.tpe.widenTermRefExpr)
60+
cpy.Apply(splice)(cpy.TypeApply(fun)(fun.fun, tpd.TypeTree(tp) :: Nil), body1 :: Nil)
61+
case splice: Select => cpy.Select(splice)(body1, splice.name)
62+
}
5863
}
5964
else {
6065
assert(!enclosingInlineds.nonEmpty, "unexpanded macro")
6166
assert(ctx.owner.isInlineMethod)
62-
if (Splicer.canBeSpliced(splice.qualifier)) { // level 0 inside an inline definition
63-
transform(splice.qualifier)(spliceContext) // Just check PCP
67+
if (Splicer.canBeSpliced(body)) { // level 0 inside an inline definition
68+
transform(body)(spliceContext) // Just check PCP
6469
splice
6570
}
6671
else { // level 0 inside an inline definition
@@ -72,15 +77,6 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
7277
}
7378
}
7479

75-
76-
/** Add cast to force boundaries where T and $t (an alias of T) are used to ensure PCP.
77-
* '{ ${...: T} } --> '{ ${...: T}.asInstanceOf[T] } --> '{ ${...: T}.asInstanceOf[$t] }
78-
*/
79-
protected def addSpliceCast(tree: Tree)(implicit ctx: Context): Tree = {
80-
val tp = checkType(tree.sourcePos).apply(tree.tpe.widenTermRefExpr)
81-
tree.cast(tp).withSpan(tree.span)
82-
}
83-
8480
/** If `tree` refers to a locally defined symbol (either directly, or in a pickled type),
8581
* check that its staging level matches the current level. References to types
8682
* that are phase-incorrect can still be healed as follows:

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

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ class ReifyQuotes extends MacroTransform {
170170
*/
171171
override protected def transformQuotation(body: Tree, quote: Tree)(implicit ctx: Context): Tree = {
172172
val isType = quote.symbol eq defn.InternalQuoted_typeQuote
173-
assert(!body.symbol.isSplice)
173+
assert(!(body.symbol.isSplice && (body.isInstanceOf[GenericApply[_]] || body.isInstanceOf[Select])))
174174
if (level > 0) {
175175
val body1 = nested(isQuote = true).transform(body)(quoteContext)
176176
super.transformQuotation(body1, quote)
@@ -222,21 +222,24 @@ class ReifyQuotes extends MacroTransform {
222222
* and make a hole from these parts. Otherwise issue an error, unless we
223223
* are in the body of an inline method.
224224
*/
225-
protected def transformSplice(splice: Select)(implicit ctx: Context): Tree = {
225+
protected def transformSplice(body: Tree, splice: Tree)(implicit ctx: Context): Tree = {
226226
if (level > 1) {
227-
val body1 = nested(isQuote = false).transform(splice.qualifier)(spliceContext)
228-
body1.select(splice.name)
227+
val body1 = nested(isQuote = false).transform(body)(spliceContext)
228+
splice match {
229+
case splice: Apply => cpy.Apply(splice)(splice.fun, body1 :: Nil)
230+
case splice: Select => cpy.Select(splice)(body1, splice.name)
231+
}
229232
}
230233
else {
231234
assert(level == 1, "unexpected top splice outside quote")
232-
val (body1, quotes) = nested(isQuote = false).splitSplice(splice.qualifier)(spliceContext)
233-
val tpe = outer.embedded.getHoleType(splice)
235+
val (body1, quotes) = nested(isQuote = false).splitSplice(body)(spliceContext)
236+
val tpe = outer.embedded.getHoleType(body, splice)
234237
val hole = makeHole(body1, quotes, tpe).withSpan(splice.span)
235238
// We do not place add the inline marker for trees that where lifted as they come from the same file as their
236239
// enclosing quote. Any intemediate splice will add it's own Inlined node and cancel it before splicig the lifted tree.
237240
// Note that lifted trees are not necessarily expressions and that Inlined nodes are expected to be expressions.
238241
// For example we can have a lifted tree containing the LHS of an assignment (see tests/run-with-compiler/quote-var.scala).
239-
if (splice.isType || outer.embedded.isLiftedSymbol(splice.qualifier.symbol)) hole
242+
if (splice.isType || outer.embedded.isLiftedSymbol(body.symbol)) hole
240243
else Inlined(EmptyTree, Nil, hole).withSpan(splice.span)
241244
}
242245
}
@@ -346,14 +349,13 @@ class ReifyQuotes extends MacroTransform {
346349
override def transform(tree: Tree)(implicit ctx: Context): Tree =
347350
reporting.trace(i"Reifier.transform $tree at $level", show = true) {
348351
tree match {
349-
case TypeApply(Select(spliceTree @ Spliced(_), _), tp) if tree.symbol.isTypeCast =>
350-
// Splice term which should be in the form `${x}.asInstanceOf[T]` where T is an artifact of
351-
// typer to allow pickling/unpickling phase consistent types
352-
transformSplice(spliceTree)
353-
354352
case tree: RefTree if isCaptured(tree.symbol, level) =>
355-
val t = capturers(tree.symbol).apply(tree)
356-
transformSplice(t.select(if (tree.isTerm) nme.splice else tpnme.splice))
353+
val body = capturers(tree.symbol).apply(tree)
354+
val splice: Tree =
355+
if (tree.isType) body.select(tpnme.splice)
356+
else ref(defn.InternalQuoted_exprSplice).appliedToType(tree.tpe).appliedTo(body)
357+
358+
transformSplice(body, splice)
357359

358360
case tree: DefDef if tree.symbol.is(Macro) && level == 0 =>
359361
// Shrink size of the tree. The methods have already been inlined.
@@ -396,11 +398,11 @@ object ReifyQuotes {
396398
}
397399

398400
/** Type used for the hole that will replace this splice */
399-
def getHoleType(splice: tpd.Select)(implicit ctx: Context): Type = {
401+
def getHoleType(body: tpd.Tree, splice: tpd.Tree)(implicit ctx: Context): Type = {
400402
// For most expressions the splice.tpe but there are some types that are lost by lifting
401403
// that can be recoverd from the original tree. Currently the cases are:
402404
// * Method types: the splice represents a method reference
403-
map.get(splice.qualifier.symbol).map(_.tpe.widen).getOrElse(splice.tpe)
405+
map.get(body.symbol).map(_.tpe.widen).getOrElse(splice.tpe)
404406
}
405407

406408
def isLiftedSymbol(sym: Symbol)(implicit ctx: Context): Boolean = map.contains(sym)

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ class Staging extends MacroTransform {
4444
tree match {
4545
case PackageDef(pid, _) if tree.symbol.owner == defn.RootClass =>
4646
val checker = new PCPCheckAndHeal(freshStagingContext) {
47-
override protected def addSpliceCast(tree: Tree)(implicit ctx: Context): Tree = tree
48-
4947
override protected def tryHeal(sym: Symbol, tp: Type, pos: SourcePosition)(implicit ctx: Context): Option[tpd.Tree] = {
5048
def symStr =
5149
if (!tp.isInstanceOf[ThisType]) sym.show

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,5 +157,5 @@ class SymUtils(val self: Symbol) extends AnyVal {
157157

158158
/** Is symbol a splice operation? */
159159
def isSplice(implicit ctx: Context): Boolean =
160-
self == defn.QuotedExpr_splice || self == defn.QuotedType_splice
160+
self == defn.InternalQuoted_exprSplice || self == defn.QuotedType_splice
161161
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ abstract class TreeMapWithStages(@constructorOnly ictx: Context) extends TreeMap
6464
}
6565
}
6666

67-
/** Transform the splice `splice`. */
68-
protected def transformSplice(splice: Select)(implicit ctx: Context): Tree
67+
/** Transform the splice `splice` which contains the spliced `body`. */
68+
protected def transformSplice(body: Tree, splice: Tree)(implicit ctx: Context): Tree
6969

7070
override def transform(tree: Tree)(implicit ctx: Context): Tree = {
7171
reporting.trace(i"StagingTransformer.transform $tree at $level", show = true) {
@@ -93,7 +93,7 @@ abstract class TreeMapWithStages(@constructorOnly ictx: Context) extends TreeMap
9393
case tree @ Spliced(splicedTree) =>
9494
dropEmptyBlocks(splicedTree) match {
9595
case Quoted(t) => transform(t) // ${ 'x } --> x
96-
case _ => transformSplice(tree)
96+
case _ => transformSplice(splicedTree, tree)
9797
}
9898

9999
case Block(stats, _) =>

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

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -968,21 +968,11 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
968968
override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = {
969969
assert(tree.hasType, tree)
970970
val qual1 = typed(tree.qualifier, selectionProto(tree.name, pt, this))
971-
val res =
972-
if (tree.symbol == defn.QuotedExpr_splice && level == 0) expandMacro(qual1, tree.span)
973-
else untpd.cpy.Select(tree)(qual1, tree.name).withType(tree.typeOpt)
971+
val res = untpd.cpy.Select(tree)(qual1, tree.name).withType(tree.typeOpt)
974972
ensureAccessible(res.tpe, tree.qualifier.isInstanceOf[untpd.Super], tree.sourcePos)
975973
res
976974
}
977975

978-
private def expandMacro(body: Tree, span: Span)(implicit ctx: Context) = {
979-
assert(level == 0)
980-
val inlinedFrom = enclosingInlineds.last
981-
val evaluatedSplice = Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext)(ctx.withSource(inlinedFrom.source))
982-
if (ctx.reporter.hasErrors) EmptyTree
983-
else evaluatedSplice.withSpan(span)
984-
}
985-
986976
override def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context): Tree =
987977
typed(tree.cond, defn.BooleanType) match {
988978
case cond1 @ ConstantValue(b: Boolean) =>
@@ -1001,8 +991,13 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
1001991
}
1002992
}
1003993

1004-
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree =
1005-
constToLiteral(betaReduce(super.typedApply(tree, pt)))
994+
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
995+
constToLiteral(betaReduce(super.typedApply(tree, pt))) match {
996+
case res: Apply if res.symbol == defn.InternalQuoted_exprSplice && level == 0 =>
997+
expandMacro(res.args.head, tree.span)
998+
case res => res
999+
}
1000+
}
10061001

10071002
override def typedMatchFinish(tree: untpd.Match, sel: Tree, wideSelType: Type, cases: List[untpd.CaseDef], pt: Type)(implicit ctx: Context) =
10081003
if (!tree.isInline || ctx.owner.isInlineMethod) // don't reduce match of nested inline method yet
@@ -1159,4 +1154,13 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
11591154
inlineTermBindings(termBindings1.asInstanceOf[List[ValOrDefDef]], tree1)
11601155
}
11611156
}
1157+
1158+
private def expandMacro(body: Tree, span: Span)(implicit ctx: Context) = {
1159+
assert(level == 0)
1160+
val inlinedFrom = enclosingInlineds.last
1161+
val evaluatedSplice = Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext)(ctx.withSource(inlinedFrom.source))
1162+
if (ctx.reporter.hasErrors) EmptyTree
1163+
else evaluatedSplice.withSpan(span)
1164+
}
1165+
11621166
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ object PrepareInlineable {
270270

271271
var isMacro = false
272272
new TreeMapWithStages(freshStagingContext) {
273-
override protected def transformSplice(splice: tpd.Select)(implicit ctx: Context): tpd.Tree = {
273+
override protected def transformSplice(body: tpd.Tree, splice: tpd.Tree)(implicit ctx: Context): tpd.Tree = {
274274
isMacro = true
275275
splice
276276
}

0 commit comments

Comments
 (0)