Skip to content

Commit

Permalink
Fix scala#7142: Detect scope extrusions in macros and run
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasstucki committed Oct 31, 2019
1 parent ed42111 commit cbdef8a
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 1 deletion.
17 changes: 16 additions & 1 deletion compiler/src/dotty/tools/dotc/transform/Splicer.scala
Expand Up @@ -44,7 +44,11 @@ object Splicer {
try {
// Some parts of the macro are evaluated during the unpickling performed in quotedExprToTree
val interpretedExpr = interpreter.interpret[scala.quoted.QuoteContext => scala.quoted.Expr[Any]](tree)
interpretedExpr.fold(tree)(macroClosure => PickledQuotes.quotedExprToTree(macroClosure(QuoteContext())))
val interpretedTree = interpretedExpr.fold(tree)(macroClosure => PickledQuotes.quotedExprToTree(macroClosure(QuoteContext())))
freeVariables(interpretedTree).foreach {
x => ctx.error(em"$x was used outside the scope where it was defined", x.symbol.sourcePos)
}
interpretedTree
}
catch {
case ex: CompilationUnit.SuspendException =>
Expand All @@ -63,6 +67,17 @@ object Splicer {
}
}

private def freeVariables(tree: Tree)(given ctx: Context): List[Tree] =
def isFreeVariable(sym: Symbol): Boolean =
sym.exists && !sym.is(Package) && !sym.owner.isStaticOwner && !ctx.owner.ownersIterator.contains(sym.owner)
new TreeAccumulator[List[Tree]] {
def apply(x: List[Tree], tree: Tree)(given ctx: Context): List[Tree] = tree match {
case tree: Ident if isFreeVariable(tree.symbol) => tree :: x
case _ => foldOver(x, tree)
}
}.apply(Nil, tree)


/** Check that the Tree can be spliced. `${'{xyz}}` becomes `xyz`
* and for `$xyz` the tree of `xyz` is interpreted for which the
* resulting expression is returned as a `Tree`
Expand Down
9 changes: 9 additions & 0 deletions tests/neg-macros/i7142/Macro_1.scala
@@ -0,0 +1,9 @@
package macros
import scala.quoted._

def oops(given QuoteContext) = {
var v = '{0};
val q = '{ (x: Int) => ${ v = '{x}; v } } // error
'{$q($v)}
}
inline def test = ${oops}
4 changes: 4 additions & 0 deletions tests/neg-macros/i7142/Test_2.scala
@@ -0,0 +1,4 @@

object Test {
macros.test
}
8 changes: 8 additions & 0 deletions tests/neg-macros/i7142b/Macro_1.scala
@@ -0,0 +1,8 @@
package macros
import scala.quoted._
import scala.util.control.NonLocalReturns._

def oops(given QuoteContext): Expr[Int] =
returning('{ { (x: Int) => ${ throwReturn('x) }} apply 0 }) // error

inline def test = ${oops}
4 changes: 4 additions & 0 deletions tests/neg-macros/i7142b/Test_2.scala
@@ -0,0 +1,4 @@

object Test {
macros.test
}

0 comments on commit cbdef8a

Please sign in to comment.