Skip to content

Commit e42be8c

Browse files
Merge pull request #4868 from dotty-staging/refactor-splice-code
Move all logic handling splices into `splice`
2 parents 6b8b260 + 4778b75 commit e42be8c

File tree

7 files changed

+56
-29
lines changed

7 files changed

+56
-29
lines changed

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

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package transform
33

44
import core._
55
import Decorators._, Flags._, Types._, Contexts._, Symbols._, Constants._
6-
import Flags._
76
import ast.Trees._
87
import ast.{TreeTypeMap, untpd}
98
import util.Positions._
@@ -16,6 +15,7 @@ import typer.Implicits.SearchFailureType
1615
import scala.collection.mutable
1716
import dotty.tools.dotc.core.StdNames._
1817
import dotty.tools.dotc.core.quoted._
18+
import dotty.tools.dotc.util.SourcePosition
1919

2020

2121
/** Translates quoted terms and types to `unpickle` method calls.
@@ -242,10 +242,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
242242
!sym.is(Param) || levelOK(sym.owner)
243243
}
244244

245-
/** Issue a "splice outside quote" error unless we are in the body of a transparent method */
246-
def spliceOutsideQuotes(pos: Position)(implicit ctx: Context): Unit =
247-
ctx.error(i"splice outside quotes", pos)
248-
249245
/** Try to heal phase-inconsistent reference to type `T` using a local type definition.
250246
* @return None if successful
251247
* @return Some(msg) if unsuccessful where `msg` is a potentially empty error message
@@ -304,7 +300,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
304300
outer.checkType(pos).foldOver(acc, tp)
305301
}
306302
else {
307-
if (tp.isTerm) spliceOutsideQuotes(pos)
303+
if (tp.isTerm) ctx.error(i"splice outside quotes", pos)
308304
tp
309305
}
310306
case tp: NamedType =>
@@ -424,14 +420,28 @@ class ReifyQuotes extends MacroTransformWithImplicits {
424420
val body1 = nested(isQuote = false).transform(splice.qualifier)
425421
body1.select(splice.name)
426422
}
427-
else if (!inQuote && level == 0 && !ctx.owner.is(Transparent)) {
428-
spliceOutsideQuotes(splice.pos)
429-
splice
430-
}
431-
else {
423+
else if (level == 1) {
432424
val (body1, quotes) = nested(isQuote = false).split(splice.qualifier)
433425
makeHole(body1, quotes, splice.tpe).withPos(splice.pos)
434426
}
427+
else if (enclosingInlineds.nonEmpty) { // level 0 in an inlined call
428+
val spliceCtx = ctx.outer // drop the last `inlineContext`
429+
val pos: SourcePosition = Decorators.sourcePos(enclosingInlineds.head.pos)(spliceCtx)
430+
val evaluatedSplice = Splicer.splice(splice.qualifier, pos, macroClassLoader)(spliceCtx).withPos(splice.pos)
431+
if (ctx.reporter.hasErrors) splice else transform(evaluatedSplice)
432+
}
433+
else if (!ctx.owner.is(Transparent)) { // level 0 outside a transparent definition
434+
ctx.error(i"splice outside quotes or transparent method", splice.pos)
435+
splice
436+
}
437+
else if (Splicer.canBeSpliced(splice.qualifier)) { // level 0 inside a transparent definition
438+
nested(isQuote = false).split(splice.qualifier) // Just check PCP
439+
splice
440+
}
441+
else { // level 0 inside a transparent definition
442+
ctx.error("Malformed macro call. The contents of the ~ must call a static method and arguments must be quoted or transparent.".stripMargin, splice.pos)
443+
splice
444+
}
435445
}
436446

437447
/** Transforms the contents of a nested splice
@@ -549,18 +559,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
549559
val last = enteredSyms
550560
stats.foreach(markDef)
551561
mapOverTree(last)
552-
case Inlined(call, bindings, InlineSplice(spliced)) if !call.isEmpty =>
553-
val tree2 =
554-
if (level == 0) {
555-
val evaluatedSplice = Splicer.splice(spliced, tree.pos, macroClassLoader).withPos(tree.pos)
556-
if (ctx.reporter.hasErrors) EmptyTree
557-
else transform(cpy.Inlined(tree)(call, bindings, evaluatedSplice))
558-
}
559-
else super.transform(tree)
560-
561-
// due to value-discarding which converts an { e } into { e; () })
562-
if (tree.tpe =:= defn.UnitType) Block(tree2 :: Nil, Literal(Constant(())))
563-
else tree2
564562
case _: Import =>
565563
tree
566564
case tree: DefDef if tree.symbol.is(Macro) && level == 0 =>

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import dotty.tools.dotc.core.Constants.Constant
2020
import dotty.tools.dotc.tastyreflect.TastyImpl
2121

2222
import scala.util.control.NonFatal
23-
import dotty.tools.dotc.util.Positions.Position
2423
import dotty.tools.dotc.util.SourcePosition
2524

2625
import scala.reflect.ClassTag
@@ -35,7 +34,7 @@ object Splicer {
3534
*
3635
* See: `ReifyQuotes`
3736
*/
38-
def splice(tree: Tree, pos: Position, classLoader: ClassLoader)(implicit ctx: Context): Tree = tree match {
37+
def splice(tree: Tree, pos: SourcePosition, classLoader: ClassLoader)(implicit ctx: Context): Tree = tree match {
3938
case Quoted(quotedTree) => quotedTree
4039
case _ =>
4140
val interpreter = new Interpreter(pos, classLoader)
@@ -71,7 +70,7 @@ object Splicer {
7170
}
7271

7372
/** Tree interpreter that evaluates the tree */
74-
private class Interpreter(pos: Position, classLoader: ClassLoader)(implicit ctx: Context) extends AbstractInterpreter {
73+
private class Interpreter(pos: SourcePosition, classLoader: ClassLoader)(implicit ctx: Context) extends AbstractInterpreter {
7574

7675
type Result = Object
7776

@@ -105,7 +104,7 @@ object Splicer {
105104

106105
protected def interpretTastyContext()(implicit env: Env): Object =
107106
new TastyImpl(ctx) {
108-
override def rootPosition: SourcePosition = SourcePosition(ctx.source, pos)
107+
override def rootPosition: SourcePosition = pos
109108
}
110109

111110
protected def interpretStaticMethodCall(fn: Tree, args: => List[Object])(implicit env: Env): Object = {
@@ -222,7 +221,7 @@ object Splicer {
222221
}
223222

224223
/** Exception that stops interpretation if some issue is found */
225-
private class StopInterpretation(val msg: String, val pos: Position) extends Exception
224+
private class StopInterpretation(val msg: String, val pos: SourcePosition) extends Exception
226225

227226
}
228227

tests/neg/quote-exception/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ object Macro_1 {
44
transparent def foo(transparent b: Boolean): Unit = ~fooImpl(b)
55
def fooImpl(b: Boolean): Expr[Unit] =
66
if (b) '(println("foo(true)"))
7-
else ???
7+
else ???
88
}

tests/neg/quote-macro-2-splices.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import scala.quoted._
2+
3+
object Macro {
4+
5+
transparent def foo(b: Boolean): Int = { // error
6+
if (b) ~bar(true)
7+
else ~bar(false)
8+
}
9+
10+
def bar(b: Boolean): Expr[Int] = if (b) '(1) else '(0)
11+
}

tests/neg/quote-pcp-in-arg.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import scala.quoted._
2+
3+
object Foo {
4+
transparent def foo(x: Int): Int = ~bar('{ '(x); x }) // error
5+
def bar(i: Expr[Int]): Expr[Int] = i
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import scala.quoted._
2+
3+
object Foo {
4+
transparent def foo(): Int = ~bar(~x) // error
5+
def x: Expr[Int] = '(1)
6+
def bar(i: Int): Expr[Int] = i.toExpr
7+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import scala.quoted._
2+
3+
object Foo {
4+
transparent def foo(): Int = ~(~x) // error
5+
def x: Expr[Expr[Int]] = '( '(1) )
6+
}

0 commit comments

Comments
 (0)