Skip to content

Commit b351e73

Browse files
committed
Require QuoteContext warning on quotes
1 parent 65901c5 commit b351e73

File tree

92 files changed

+238
-244
lines changed

Some content is hidden

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

92 files changed

+238
-244
lines changed

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

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -360,20 +360,10 @@ object Splicer {
360360

361361
// Interpret `foo(j = x, i = y)` which it is expanded to
362362
// `val j$1 = x; val i$1 = y; foo(i = y, j = x)`
363-
case Block(stats, expr) =>
364-
var unexpected: Option[Result] = None
365-
val newEnv = stats.foldLeft(env)((accEnv, stat) => stat match {
366-
case stat: ValDef if stat.symbol.is(Synthetic) =>
367-
accEnv.updated(stat.name, interpretTree(stat.rhs)(accEnv))
368-
case stat =>
369-
if (unexpected.isEmpty)
370-
unexpected = Some(unexpectedTree(stat))
371-
accEnv
372-
})
373-
unexpected.getOrElse(interpretTree(expr)(newEnv))
363+
case Block(stats, expr) => interpretBlock(stats, expr)
374364
case NamedArg(_, arg) => interpretTree(arg)
375365

376-
case Inlined(_, Nil, expansion) => interpretTree(expansion)
366+
case Inlined(_, bindings, expansion) => interpretBlock(bindings, expansion)
377367

378368
case Typed(expr, _) =>
379369
interpretTree(expr)
@@ -385,6 +375,19 @@ object Splicer {
385375
unexpectedTree(tree)
386376
}
387377

378+
private def interpretBlock(stats: List[Tree], expr: Tree)(implicit env: Env) = {
379+
var unexpected: Option[Result] = None
380+
val newEnv = stats.foldLeft(env)((accEnv, stat) => stat match {
381+
case stat: ValDef if stat.symbol.is(Synthetic) =>
382+
accEnv.updated(stat.name, interpretTree(stat.rhs)(accEnv))
383+
case stat =>
384+
if (unexpected.isEmpty)
385+
unexpected = Some(unexpectedTree(stat))
386+
accEnv
387+
})
388+
unexpected.getOrElse(interpretTree(expr)(newEnv))
389+
}
390+
388391
object Call {
389392
def unapply(arg: Tree): Option[(RefTree, List[Tree])] = arg match {
390393
case Select(Call(fn, args), nme.apply) if defn.isImplicitFunctionType(fn.tpe.widenDealias.finalResultType) =>

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,6 +1955,13 @@ class Typer extends Namer
19551955
* while tracking the quotation level in the context.
19561956
*/
19571957
def typedQuote(tree: untpd.Quote, pt: Type)(implicit ctx: Context): Tree = track("typedQuote") {
1958+
/** Fails if there is no implicit QuoteContext */
1959+
def checkQuoteContext(): Unit = {
1960+
val qctx = inferImplicitArg(defn.QuoteContextType, tree.span)
1961+
if (level == 0 && qctx.tpe.isInstanceOf[SearchFailureType])
1962+
ctx.error(missingArgMsg(qctx, defn.QuoteContextType, ""), ctx.source.atSpan(tree.span))
1963+
}
1964+
19581965
tree.quoted match {
19591966
case untpd.Splice(innerExpr) if tree.isTerm =>
19601967
ctx.warning("Canceled splice directly inside a quote. '{ ${ XYZ } } is equivalent to XYZ.", tree.sourcePos)
@@ -1963,9 +1970,11 @@ class Typer extends Namer
19631970
ctx.warning("Canceled splice directly inside a quote. '[ ${ XYZ } ] is equivalent to XYZ.", tree.sourcePos)
19641971
typed(innerType, pt)
19651972
case quoted if quoted.isType =>
1973+
checkQuoteContext()
19661974
ctx.compilationUnit.needsStaging = true
19671975
typedTypeApply(untpd.TypeApply(untpd.ref(defn.InternalQuoted_typeQuoteR), quoted :: Nil), pt)(quoteContext).withSpan(tree.span)
19681976
case quoted =>
1977+
checkQuoteContext()
19691978
ctx.compilationUnit.needsStaging = true
19701979
if (ctx.mode.is(Mode.Pattern) && level == 0)
19711980
typedQuotePattern(quoted, pt, tree.span)

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

Lines changed: 3 additions & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 3 additions & 2 deletions
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
}
Lines changed: 5 additions & 7 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 1 addition & 1 deletion
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]
Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 2 additions & 2 deletions
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
}

tests/pos/i4380a.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import scala.quoted._
33
object Test {
44

55
trait Producer[A] { self =>
6-
def step(k: (A => Expr[Unit])): Expr[Unit]
6+
def step(k: (A => Expr[Unit])) given QuoteContext: Expr[Unit]
77
}
88

99
trait Foo[A]
@@ -13,7 +13,7 @@ object Test {
1313
stream match {
1414
case Bar(producer, nestedf) => {
1515
new Producer[Expr[A]] {
16-
def step(k: Expr[A] => Expr[Unit]): Expr[Unit] = '{
16+
def step(k: Expr[A] => Expr[Unit]) given QuoteContext: Expr[Unit] = '{
1717
val adv: Unit => Unit = { _ => ${producer.step((el) => nestedf(el))} }
1818
}
1919
}

tests/pos/i4396a.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
class Test {
1+
import scala.quoted._
2+
def test given QuoteContext = {
23
'{ Option(4) match { case Some(a) => a; case None => 1 }}
3-
}
4+
}

tests/pos/i4396b.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
class Test {
1+
import scala.quoted._
2+
def test given QuoteContext = {
23
'{ case class Foo() }
34
}

tests/pos/i4539.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
object Foo {
1+
import scala.quoted._
2+
def test given QuoteContext = {
23
val q = '[String]
34
'[String]
45
}

tests/pos/i4539b.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
object Foo {
1+
import scala.quoted._
2+
def test given QuoteContext = {
23
def f = {
34
{
45
'[String]

tests/pos/i4774a.scala

Lines changed: 1 addition & 1 deletion
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('y)}
88
}

tests/pos/i4774c.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
import scala.quoted._
33

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

tests/pos/i4774d.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
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; ${loop('y)} }
77
}

tests/pos/i4774e.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
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
'{ def y = $x; ${ loop('y) } }
77

8-
def loop2[T](x: Expr[T])(implicit t: Type[T]): Expr[T] =
9-
'{ def y() = $x; ${ loop('{y()}) } }
8+
def loop2[T](x: Expr[T])(implicit t: Type[T], qctx: QuoteContext): Expr[T] =
9+
'{ def y() = $x; ${ loop('{y()}) } }
1010
}

tests/pos/i4774f.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
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
'{ def y: T = $x; ${ loop('y) } }
77

8-
def loop2[T](x: Expr[T])(implicit t: Type[T]): Expr[T] =
8+
def loop2[T](x: Expr[T])(implicit t: Type[T], qctx: QuoteContext): Expr[T] =
99
'{ def y(): T = $x; ${ loop2('{y()}) } }
1010
}

0 commit comments

Comments
 (0)