Skip to content

Commit 12306f1

Browse files
committed
Move all logic handling splices into splice
THis is possible now that we have access to information about the outer inlined tree nodes via enclosingInlineds. In particular we can recover the position where the macro was inlined.
1 parent 05c5ba1 commit 12306f1

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.
@@ -230,10 +230,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
230230
!sym.is(Param) || levelOK(sym.owner)
231231
}
232232

233-
/** Issue a "splice outside quote" error unless we are in the body of a transparent method */
234-
def spliceOutsideQuotes(pos: Position)(implicit ctx: Context): Unit =
235-
ctx.error(i"splice outside quotes", pos)
236-
237233
/** Try to heal phase-inconsistent reference to type `T` using a local type definition.
238234
* @return None if successful
239235
* @return Some(msg) if unsuccessful where `msg` is a potentially empty error message
@@ -292,7 +288,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
292288
outer.checkType(pos).foldOver(acc, tp)
293289
}
294290
else {
295-
if (tp.isTerm) spliceOutsideQuotes(pos)
291+
if (tp.isTerm) ctx.error(i"splice outside quotes", pos)
296292
tp
297293
}
298294
case tp: NamedType =>
@@ -418,14 +414,28 @@ class ReifyQuotes extends MacroTransformWithImplicits {
418414
val body1 = nested(isQuote = false).transform(splice.qualifier)
419415
body1.select(splice.name)
420416
}
421-
else if (!inQuote && level == 0 && !ctx.owner.is(Transparent)) {
422-
spliceOutsideQuotes(splice.pos)
423-
splice
424-
}
425-
else {
417+
else if (level == 1) {
426418
val (body1, quotes) = nested(isQuote = false).split(splice.qualifier)
427419
makeHole(body1, quotes, splice.tpe).withPos(splice.pos)
428420
}
421+
else if (enclosingInlineds.nonEmpty) { // level 0 in an inline call
422+
val spliceCtx = ctx.outer // drop the last `inlineContext`
423+
val pos: SourcePosition = Decorators.sourcePos(enclosingInlineds.head.pos)(spliceCtx)
424+
val evaluatedSplice = Splicer.splice(splice.qualifier, pos, macroClassLoader)(spliceCtx).withPos(splice.pos)
425+
if (ctx.reporter.hasErrors) splice else transform(evaluatedSplice)
426+
}
427+
else if (!ctx.owner.is(Transparent)) { // level 0 outside a transparent definition
428+
ctx.error(i"splice outside quotes or transparent method", splice.pos)
429+
splice
430+
}
431+
else if (Splicer.canBeSpliced(splice.qualifier)) { // level 0 inside a transparent definition
432+
nested(isQuote = false).split(splice.qualifier) // Just check PCP
433+
splice
434+
}
435+
else { // level 0 inside a transparent definition
436+
ctx.error("Malformed macro call. The contents of the ~ must call a static method and arguments must be quoted or transparent.".stripMargin, splice.pos)
437+
splice
438+
}
429439
}
430440

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