Skip to content

Commit 4c674d2

Browse files
Merge pull request #6769 from dotty-staging/require-quote-context-warining
Require QuoteContext for all quotes
2 parents 3c99306 + 3ac8c5e commit 4c674d2

File tree

101 files changed

+295
-296
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+295
-296
lines changed

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

+21-12
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ object Splicer {
8080
/** Tree interpreter that evaluates the tree */
8181
private class Interpreter(pos: SourcePosition, classLoader: ClassLoader)(implicit ctx: Context) extends AbstractInterpreter {
8282

83+
def checking: Boolean = false
84+
8385
type Result = Object
8486

8587
/** Returns the interpreted result of interpreting the code a call to the symbol with default arguments.
@@ -277,6 +279,7 @@ object Splicer {
277279

278280
/** Tree interpreter that tests if tree can be interpreted */
279281
private class CheckValidMacroBody(implicit ctx: Context) extends AbstractInterpreter {
282+
def checking: Boolean = true
280283

281284
type Result = Unit
282285

@@ -312,6 +315,9 @@ object Splicer {
312315

313316
/** Abstract Tree interpreter that can interpret calls to static methods with quoted or inline arguments */
314317
private abstract class AbstractInterpreter(implicit ctx: Context) {
318+
319+
def checking: Boolean
320+
315321
type Env = Map[Name, Result]
316322
type Result
317323

@@ -370,20 +376,10 @@ object Splicer {
370376

371377
// Interpret `foo(j = x, i = y)` which it is expanded to
372378
// `val j$1 = x; val i$1 = y; foo(i = y, j = x)`
373-
case Block(stats, expr) =>
374-
var unexpected: Option[Result] = None
375-
val newEnv = stats.foldLeft(env)((accEnv, stat) => stat match {
376-
case stat: ValDef if stat.symbol.is(Synthetic) =>
377-
accEnv.updated(stat.name, interpretTree(stat.rhs)(accEnv))
378-
case stat =>
379-
if (unexpected.isEmpty)
380-
unexpected = Some(unexpectedTree(stat))
381-
accEnv
382-
})
383-
unexpected.getOrElse(interpretTree(expr)(newEnv))
379+
case Block(stats, expr) => interpretBlock(stats, expr)
384380
case NamedArg(_, arg) => interpretTree(arg)
385381

386-
case Inlined(_, Nil, expansion) => interpretTree(expansion)
382+
case Inlined(_, bindings, expansion) => interpretBlock(bindings, expansion)
387383

388384
case Typed(expr, _) =>
389385
interpretTree(expr)
@@ -395,6 +391,19 @@ object Splicer {
395391
unexpectedTree(tree)
396392
}
397393

394+
private def interpretBlock(stats: List[Tree], expr: Tree)(implicit env: Env) = {
395+
var unexpected: Option[Result] = None
396+
val newEnv = stats.foldLeft(env)((accEnv, stat) => stat match {
397+
case stat: ValDef if stat.symbol.is(Synthetic) || !checking =>
398+
accEnv.updated(stat.name, interpretTree(stat.rhs)(accEnv))
399+
case stat =>
400+
if (unexpected.isEmpty)
401+
unexpected = Some(unexpectedTree(stat))
402+
accEnv
403+
})
404+
unexpected.getOrElse(interpretTree(expr)(newEnv))
405+
}
406+
398407
object Call {
399408
def unapply(arg: Tree): Option[(RefTree, List[Tree])] = arg match {
400409
case Select(Call(fn, args), nme.apply) if defn.isImplicitFunctionType(fn.tpe.widenDealias.finalResultType) =>

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

+12-9
Original file line numberDiff line numberDiff line change
@@ -1962,15 +1962,18 @@ class Typer extends Namer
19621962
case untpd.TypSplice(innerType) if tree.isType =>
19631963
ctx.warning("Canceled splice directly inside a quote. '[ ${ XYZ } ] is equivalent to XYZ.", tree.sourcePos)
19641964
typed(innerType, pt)
1965-
case quoted if quoted.isType =>
1966-
ctx.compilationUnit.needsStaging = true
1967-
typedTypeApply(untpd.TypeApply(untpd.ref(defn.InternalQuoted_typeQuoteR), quoted :: Nil), pt)(quoteContext).withSpan(tree.span)
19681965
case quoted =>
19691966
ctx.compilationUnit.needsStaging = true
1970-
if (ctx.mode.is(Mode.Pattern) && level == 0)
1971-
typedQuotePattern(quoted, pt, tree.span)
1972-
else
1973-
typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprQuoteR), quoted), pt)(quoteContext).withSpan(tree.span)
1967+
1968+
val qctx = inferImplicitArg(defn.QuoteContextType, tree.span)
1969+
if (level == 0 && qctx.tpe.isInstanceOf[SearchFailureType])
1970+
ctx.error(missingArgMsg(qctx, defn.QuoteContextType, ""), ctx.source.atSpan(tree.span))
1971+
1972+
val tree1 =
1973+
if (quoted.isType) typedTypeApply(untpd.TypeApply(untpd.ref(defn.InternalQuoted_typeQuoteR), quoted :: Nil), pt)(quoteContext)
1974+
else if (ctx.mode.is(Mode.Pattern) && level == 0) typedQuotePattern(quoted, pt, qctx)
1975+
else typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprQuoteR), quoted), pt)(quoteContext)
1976+
tree1.withSpan(tree.span)
19741977
}
19751978
}
19761979

@@ -2019,7 +2022,7 @@ class Typer extends Namer
20192022
* ) => ...
20202023
* ```
20212024
*/
2022-
private def typedQuotePattern(quoted: untpd.Tree, pt: Type, quoteSpan: Span)(implicit ctx: Context): Tree = {
2025+
private def typedQuotePattern(quoted: untpd.Tree, pt: Type, qctx: tpd.Tree)(implicit ctx: Context): Tree = {
20232026
val exprPt = pt.baseType(defn.QuotedExprClass)
20242027
val quotedPt = if (exprPt.exists) exprPt.argTypesHi.head else defn.AnyType
20252028
val quoted1 = typedExpr(quoted, quotedPt)(quoteContext.addMode(Mode.QuotedPattern))
@@ -2068,7 +2071,7 @@ class Typer extends Namer
20682071
implicits =
20692072
ref(defn.InternalQuoted_exprQuoteR).appliedToType(shape.tpe).appliedTo(shape) ::
20702073
Literal(Constant(typeBindings.nonEmpty)) ::
2071-
implicitArgTree(defn.QuoteContextType, quoteSpan) :: Nil,
2074+
qctx :: Nil,
20722075
patterns = splicePat :: Nil,
20732076
proto = pt)
20742077
}

compiler/test-resources/repl-macros/i6007

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
scala> import scala.quoted._
12
scala> implicit def toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
23
def toolbox: quoted.Toolbox
3-
scala> val v = '{ (if true then Some(1) else None).map(v => v+1) }
4-
val v: quoted.Expr[Option[Int]] = Expr(<pickled tasty>)
4+
scala> def v given QuoteContext = '{ (if true then Some(1) else None).map(v => v+1) }
5+
def v given (x$1: quoted.QuoteContext): quoted.Expr[Option[Int]]
56
scala> scala.quoted.withQuoteContext(v.show)
67
val res0: String = (if (true) scala.Some.apply[scala.Int](1) else scala.None).map[scala.Int](((v: scala.Int) => v.+(1)))
78
scala> scala.quoted.run(v)

compiler/test-resources/repl/i5551

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
scala> import scala.quoted._
2-
3-
scala> def assertImpl(expr: Expr[Boolean]) = '{ if !($expr) then throw new AssertionError("failed assertion")}
4-
def assertImpl(expr: quoted.Expr[Boolean]): quoted.Expr[Unit]
5-
2+
scala> def assertImpl(expr: Expr[Boolean]) given (qctx: QuoteContext) = '{ if !($expr) then throw new AssertionError("failed assertion")}
3+
def assertImpl
4+
(expr: quoted.Expr[Boolean])
5+
given (qctx: quoted.QuoteContext): quoted.Expr[Unit]
66
scala> inline def assert(expr: => Boolean): Unit = ${ assertImpl('{expr}) }
77
def assert(expr: => Boolean): Unit
88

library/src-3.x/scala/tasty/reflect/utils/TreeUtils.scala

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ trait TreeUtils {
1010

1111
/** Bind the `rhs` to a `val` and use it in `body` */
1212
def let(rhs: Term)(body: Ident => Term): Term = {
13+
delegate for QuoteContext = new QuoteContext(reflect)
1314
type T // TODO probably it is better to use the Sealed contruct rather than let the user create their own existential type
1415
implicit val rhsTpe: quoted.Type[T] = rhs.tpe.seal.asInstanceOf[quoted.Type[T]]
1516
val rhsExpr = rhs.seal.cast[T]

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ package object quoted {
5454
implicit object ExprOps {
5555
def (x: T) toExpr[T: Liftable] given QuoteContext: Expr[T] = the[Liftable[T]].toExpr(x)
5656

57-
def (list: List[Expr[T]]) toExprOfList[T] given Type[T]: Expr[List[T]] = list match {
57+
def (list: List[Expr[T]]) toExprOfList[T: Type] given QuoteContext: Expr[List[T]] = list match {
5858
case x :: xs => '{ $x :: ${xs.toExprOfList} }
5959
case Nil => '{ Nil }
6060
}

tests/neg-custom-args/fatal-warnings/quote-simple-hole.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
class Test {
1+
import scala.quoted.QuoteContext
2+
3+
def test given QuoteContext = {
24
val x = '{0}
35
val y = '{ // error: Canceled splice directly inside a quote. '{ ${ XYZ } } is equivalent to XYZ.
46
$x

tests/neg-macros/quote-complex-top-splice.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ object Test {
2424
impl(1)
2525
}
2626

27-
def impl(i: Int): Expr[Unit] = '{}
27+
def impl(i: Int) given QuoteContext: Expr[Unit] = '{}
2828

2929
}

tests/neg-macros/quote-error/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import quoted._
22

33
object Macro_1 {
44
inline def foo(inline b: Boolean): Unit = ${fooImpl(b)}
5-
def fooImpl(b: Boolean): Expr[Unit] =
5+
def fooImpl(b: Boolean) given QuoteContext: Expr[Unit] =
66
if (b) '{println("foo(true)")}
77
else QuoteError("foo cannot be called with false")
88
}

tests/neg-macros/quote-exception/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import quoted._
22

33
object Macro_1 {
44
inline def foo(inline b: Boolean): Unit = ${fooImpl(b)}
5-
def fooImpl(b: Boolean): Expr[Unit] =
5+
def fooImpl(b: Boolean) given QuoteContext: Expr[Unit] =
66
if (b) '{println("foo(true)")}
77
else ???
88
}

tests/neg-macros/quote-this-b.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ class Foo {
66
}
77

88
object Foo {
9-
def impl[T](x: Any): Expr[Unit] = '{}
9+
def impl[T](x: Any) given QuoteContext: Expr[Unit] = '{}
1010
}

tests/neg-macros/quote-this.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import scala.quoted._
22

33
class Foo {
44

5-
def f: Unit = '{
5+
def f given QuoteContext: Unit = '{
66
def bar[T](x: T): T = x
77
bar[
88
this.type // error
@@ -22,5 +22,5 @@ class Foo {
2222
}
2323

2424
object Foo {
25-
def impl[T](x: Any): Expr[Unit] = '{}
25+
def impl[T](x: Any) given QuoteContext: Expr[Unit] = '{}
2626
}

tests/neg-macros/splice-in-top-level-splice-1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ import scala.quoted.autolift._
33

44
object Foo {
55
inline def foo(): Int = ${bar(${x})} // error
6-
def x: Expr[Int] = '{1}
6+
def x given QuoteContext: Expr[Int] = '{1}
77
def bar(i: Int) given QuoteContext: Expr[Int] = i
88
}

tests/neg-macros/splice-in-top-level-splice-2.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ import scala.quoted._
22

33
object Foo {
44
inline def foo(): Int = ${$x} // error
5-
def x: Expr[Expr[Int]] = '{ '{1} }
5+
def x given QuoteContext: Expr[Expr[Int]] = '{ '{1} }
66
}

tests/neg/i4044a.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import scala.quoted._
22

3-
class Test {
3+
def test given QuoteContext = {
44

55
val a = '{1}
66
'{

tests/neg/i4044b.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import scala.quoted._
22

3-
class Test {
3+
def test given QuoteContext = {
44

55
'{
66

tests/neg/i4774b.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import scala.quoted._
33

44
object Test {
5-
def loop[T](x: Expr[T])(implicit t: Type[T]): Expr[T] = '{
5+
def loop[T](x: Expr[T])(implicit t: Type[T], qctx: QuoteContext): Expr[T] = '{
66
val y: $t = $x;
77
${loop[$t]( // error
88
'y

tests/neg/i6530b.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import scala.quoted._
12
object Foo {
2-
val program = '{
3+
def program given QuoteContext = '{
34
val tpe: quoted.Type[Int] = ???
45
val expr: quoted.Expr[Int] = ???
56

tests/neg/quote-0.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import scala.quoted._
22

3-
class Test {
3+
def test given QuoteContext = {
44

55
val x: Int = 0
66

tests/neg/quote-1.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import scala.quoted._
22

33
class Test {
44

5-
def f[T](t: Type[T], x: Expr[T]) = '{
5+
def f[T](t: Type[T], x: Expr[T]) given QuoteContext = '{
66
val z2 = $x // error // error: wrong staging level
77
}
88

9-
def g[T](implicit t: Type[T], x: Expr[T]) = '{
9+
def g[T](implicit t: Type[T], x: Expr[T], qctx: QuoteContext) = '{
1010
val z2 = $x // ok
1111
}
1212

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ object Macro {
77
else ${ bar(false) }
88
}
99

10-
def bar(b: Boolean): Expr[Int] = if (b) '{1} else '{0}
10+
def bar(b: Boolean) given QuoteContext: Expr[Int] = if (b) '{1} else '{0}
1111
}

tests/neg/quote-spliceNonStaged.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ package quotes
22
import scala.quoted._
33

44
object Quotes_1 {
5-
def printHello: Expr[Unit] = '{ println("Hello") }
5+
def printHello given QuoteContext: Expr[Unit] = '{ println("Hello") }
66
$printHello // error
77
}

tests/neg/splice-non-expr.scala

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
import scala.quoted._
12
class Foo {
2-
'{
3+
def test given QuoteContext = '{
34
${3} // error
45
${new Object} // error
56
${"abc"} // error
67
${()} // error
78
${new Foo} // error
89
}
910

10-
def unary_~ : Int = 9
11+
def unary_$ : Int = 9
1112
}
+5-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
object Test {
2-
def main(args: Array[String]): Unit = {
3-
val a = '{
4-
def z: Int = 5
5-
Macro.ff(z, 5)
6-
}
7-
1+
import scala.quoted._
2+
def test given QuoteContext = {
3+
val a = '{
4+
def z: Int = 5
5+
Macro.ff(z, 5)
86
}
97
}

tests/pos-macros/i4023c/Macro_1.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import scala.quoted._
22
object Macro {
3-
inline def ff[T](x: T): T = ${ impl('x)('[T]) }
4-
def impl[T](x: Expr[T])(implicit t: Type[T]): Expr[T] = '{ $x: $t }
3+
inline def ff[T](x: T): T = ${ impl('x)('[T], the[QuoteContext]) }
4+
def impl[T](x: Expr[T])(implicit t: Type[T], qctx: QuoteContext): Expr[T] = '{ $x: $t }
55
}

tests/pos-macros/i4734/Macro_1.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import scala.quoted._
33

44
object Macros {
55
inline def unrolledForeach(f: Int => Int): Int =
6-
${unrolledForeachImpl('f)}
6+
${unrolledForeachImpl('f)}
77

8-
def unrolledForeachImpl(f: Expr[Int => Int]): Expr[Int] = '{
8+
def unrolledForeachImpl(f: Expr[Int => Int]) given QuoteContext: Expr[Int] = '{
99
val size: Int = 5
1010
($f)(3)
1111
}

tests/pos-macros/i6210/Macros_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ object Macro {
44
inline def test[A, B]: Any =
55
${ impl[A, B] }
66

7-
def impl[A : Type, B : Type]: Expr[Any] = {
7+
def impl[A : Type, B : Type] given QuoteContext: Expr[Any] = {
88
val t = '[Map[A, B]]
99
'{
1010
new Object().asInstanceOf[$t]
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import scala.quoted._
22

33
object Macros {
4-
def assertImpl(expr: Expr[Boolean]) =
4+
def assertImpl(expr: Expr[Boolean]) given QuoteContext =
55
'{ if !($expr) then throw new AssertionError(s"failed assertion: ${$expr}") }
66
}

tests/pos-with-compiler/quote-assert/quoted_2.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ object Test {
88
${ assertImpl('expr) }
99

1010

11-
val program = '{
11+
def program given QuoteContext = '{
1212
val x = 1
1313
assert(x != 0)
1414

1515
${ assertImpl('{x != 0}) }
1616
}
1717

1818
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
19-
program.run
19+
run(program)
2020
}

tests/pos/i4350.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import scala.quoted.Type
1+
import scala.quoted._
22

3-
class Foo[T: Type] {
3+
class Foo[T: Type] given QuoteContext {
44
'{null.asInstanceOf[T]}
55
}

0 commit comments

Comments
 (0)