Skip to content

Protect agains scope extrusion in macros #7142

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
LPTK opened this issue Aug 30, 2019 · 4 comments
Closed

Protect agains scope extrusion in macros #7142

LPTK opened this issue Aug 30, 2019 · 4 comments
Assignees

Comments

@LPTK
Copy link
Contributor

LPTK commented Aug 30, 2019

In the absence of either a way to track scopes in types (as done in Squid), or of an effect system to prevent effects from occurring inside unquotes, macros can currently crash the compiler due to scope extrusion.

minimized code

Macro definition:

package macros
import scala.quoted._

def oops given QuoteContext = {
  var v = '{0};
  val q = '{ x: Int => ${ v = '{x}; v } }
  '{$q($v)}
}
inline def test = ${oops}

Macro use:

package macrotest

def foo = macros.test
Stack trace
[error] Could not find proxy for x: Int in List(val x, method $anonfun, method foo, module class Test$package$, module class macrotest, module class <root>), encl = method foo, owners = method foo, package object Test$package, package macrotest, package <root>; enclosures = method foo, package object Test$package, package macrotest, package <root>
[error] dotty.tools.dotc.transform.LambdaLift$Lifter.searchIn$1(LambdaLift.scala:381)
[error] dotty.tools.dotc.transform.LambdaLift$Lifter.proxy(LambdaLift.scala:394)
[error] dotty.tools.dotc.transform.LambdaLift$Lifter.proxyRef(LambdaLift.scala:412)
[error] dotty.tools.dotc.transform.LambdaLift.transformIdent(LambdaLift.scala:526)
[error] dotty.tools.dotc.transform.MegaPhase.goIdent(MegaPhase.scala:551)
[error] dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:225)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:394)
[error] dotty.tools.dotc.transform.MegaPhase.transformTrees$$anonfun$1(MegaPhase.scala:420)
[error] scala.collection.immutable.List.mapConserve(List.scala:179)
[error] dotty.tools.dotc.transform.MegaPhase.transformTrees(MegaPhase.scala:420)
[error] dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:271)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:396)
[error] dotty.tools.dotc.transform.MegaPhase.transformTrees$$anonfun$1(MegaPhase.scala:420)
[error] scala.collection.immutable.List.mapConserve(List.scala:179)
[error] dotty.tools.dotc.transform.MegaPhase.transformTrees(MegaPhase.scala:420)
[error] dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:271)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:396)
[error] dotty.tools.dotc.transform.MegaPhase.transformTrees$$anonfun$1(MegaPhase.scala:420)
[error] scala.collection.immutable.List.mapConserve(List.scala:179)
[error] dotty.tools.dotc.transform.MegaPhase.transformTrees(MegaPhase.scala:420)
[error] dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:271)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:396)
[error] dotty.tools.dotc.transform.MegaPhase.mapDefDef$1(MegaPhase.scala:245)
[error] dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:248)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:394)
[error] dotty.tools.dotc.transform.MegaPhase.transformStat$2(MegaPhase.scala:404)
[error] dotty.tools.dotc.transform.MegaPhase.$anonfun$1(MegaPhase.scala:409)
[error] scala.collection.immutable.List.mapConserve(List.scala:179)
[error] dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:409)
[error] dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:339)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:396)
[error] dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:251)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:394)
[error] dotty.tools.dotc.transform.MegaPhase.transformStat$2(MegaPhase.scala:404)
[error] dotty.tools.dotc.transform.MegaPhase.$anonfun$1(MegaPhase.scala:409)
[error] scala.collection.immutable.List.mapConserve(List.scala:179)
[error] dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:409)
[error] dotty.tools.dotc.transform.MegaPhase.mapPackage$1(MegaPhase.scala:356)
[error] dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:359)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:396)
[error] dotty.tools.dotc.transform.MegaPhase.transformUnit(MegaPhase.scala:415)
[error] dotty.tools.dotc.transform.MegaPhase.run(MegaPhase.scala:427)
[error] dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:316)
[error] scala.collection.immutable.List.map(List.scala:286)
[error] dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:318)
[error] dotty.tools.dotc.Run.runPhases$4$$anonfun$4(Run.scala:158)
[error] dotty.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] dotty.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] scala.collection.IndexedSeqOptimized.foreach(IndexedSeqOptimized.scala:36)
[error] scala.collection.IndexedSeqOptimized.foreach$(IndexedSeqOptimized.scala:33)
[error] scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:198)
[error] dotty.tools.dotc.Run.runPhases$5(Run.scala:170)
[error] dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:178)
[error] dotty.runtime.function.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error] dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:102)
[error] dotty.tools.dotc.Run.compileUnits(Run.scala:185)
[error] dotty.tools.dotc.Run.compileSources(Run.scala:120)
[error] dotty.tools.dotc.Run.compile(Run.scala:104)
[error] dotty.tools.dotc.Driver.doCompile(Driver.scala:34)
[error] dotty.tools.dotc.Driver.process(Driver.scala:172)
[error] dotty.tools.dotc.Main.process(Main.scala)
[error] xsbt.CachedCompilerImpl.run(CachedCompilerImpl.java:69)
[error] xsbt.CompilerInterface.run(CompilerInterface.java:41)
[error] sun.reflect.GeneratedMethodAccessor11.invoke(Unknown Source)
[error] sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error] java.lang.reflect.Method.invoke(Method.java:498)
[error] sbt.internal.inc.AnalyzingCompiler.call(AnalyzingCompiler.scala:237)
[error] sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:111)
[error] sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:90)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$3(MixedAnalyzingCompiler.scala:82)
[error] scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error] sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:133)
[error] sbt.internal.inc.MixedAnalyzingCompiler.compileScala$1(MixedAnalyzingCompiler.scala:73)
[error] sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:116)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1(IncrementalCompilerImpl.scala:307)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1$adapted(IncrementalCompilerImpl.scala:307)
[error] sbt.internal.inc.Incremental$.doCompile(Incremental.scala:106)
[error] sbt.internal.inc.Incremental$.$anonfun$compile$4(Incremental.scala:87)
[error] sbt.internal.inc.IncrementalCommon.recompileClasses(IncrementalCommon.scala:116)
[error] sbt.internal.inc.IncrementalCommon.cycle(IncrementalCommon.scala:63)
[error] sbt.internal.inc.Incremental$.$anonfun$compile$3(Incremental.scala:89)
[error] sbt.internal.inc.Incremental$.manageClassfiles(Incremental.scala:134)
[error] sbt.internal.inc.Incremental$.compile(Incremental.scala:80)
[error] sbt.internal.inc.IncrementalCompile$.apply(Compile.scala:67)
[error] sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:311)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileIncrementally$1(IncrementalCompilerImpl.scala:269)
[error] sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:159)
[error] sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:238)
[error] sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:69)
[error] sbt.Defaults$.compileIncrementalTaskImpl(Defaults.scala:1549)
[error] sbt.Defaults$.$anonfun$compileIncrementalTask$1(Defaults.scala:1523)
[error] scala.Function1.$anonfun$compose$1(Function1.scala:44)
[error] sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:40)
[error] sbt.std.Transform$$anon$4.work(System.scala:67)
[error] sbt.Execute.$anonfun$submit$2(Execute.scala:269)
[error] sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:16)
[error] sbt.Execute.work(Execute.scala:278)
[error] sbt.Execute.$anonfun$submit$1(Execute.scala:269)
[error] sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:178)
[error] sbt.CompletionService$$anon$2.call(CompletionService.scala:37)
[error] java.util.concurrent.FutureTask.run(FutureTask.java:266)
[error] java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
[error] java.util.concurrent.FutureTask.run(FutureTask.java:266)
[error] java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
[error] java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
[error] java.lang.Thread.run(Thread.java:745)

Another way to trigger the crash:

import scala.util.control.NonLocalReturns._

def oops given QuoteContext: Expr[Int] =
  returning('{ {x: Int => ${ throwReturn('x) }} apply 0 })
@odersky
Copy link
Contributor

odersky commented Sep 26, 2019

I think this is for after 3.0 since we have to figure out what to do on effects first.

nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Oct 31, 2019
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Oct 31, 2019
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Nov 1, 2019
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Nov 12, 2019
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jan 15, 2020
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jan 16, 2020
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jan 16, 2020
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jan 16, 2020
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jan 16, 2020
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jan 16, 2020
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jan 16, 2020
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jan 16, 2020
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jan 16, 2020
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jan 20, 2020
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jan 20, 2020
nicolasstucki added a commit that referenced this issue Jan 23, 2020
Fix #7142: Detect scope extrusions in macros and run
@LPTK
Copy link
Contributor Author

LPTK commented Jan 23, 2020

@nicolasstucki here's a related scope extrusion problem, which still causes a crash. I'm afraid the issue needs to be reopened:

package macros
import scala.quoted._

var saved = Option.empty[Expr[Int]]

def oops(given QuoteContext) = {
  if (saved.isEmpty) '{ (x: Int) => ${ saved = Some('{x}); 'x } }
  else saved.get
}
inline def test = ${oops}

object Test {
  macros.test
  macros.test // crash
}
Compilation output
exception while typing x of class class dotty.tools.dotc.ast.Trees$Ident # 74815
exception while typing {
  x
} of class class dotty.tools.dotc.ast.Trees$Inlined # 19567
exception while typing final module class Test$() extends Object(), _root_.scala.Serializable { this: Test.type =>
  {
    {
      {
        def $anonfun(x: Int): Int =
          {
            {
              x
            }
          }
        closure($anonfun)
      }
    }
  }
  {
    x
  }
} of class class dotty.tools.dotc.ast.Trees$TypeDef # 19569
exception while typing package <empty> {
  final lazy module val Test: Test$ = new Test$()
  final module class Test$() extends Object(), _root_.scala.Serializable { this: Test.type =>
    {
      {
        {
          def $anonfun(x: Int): Int =
            {
              {
                x
              }
            }
          closure($anonfun)
        }
      }
    }
    {
      x
    }
  }
} of class class dotty.tools.dotc.ast.Trees$PackageDef # 19570
*** error while checking tests/neg-macros/i7142/Test_2.scala after phase typer ***
java.lang.AssertionError: assertion failed: undefined symbol value x at line 11 while compiling tests/neg-macros/i7142/Test_2.scala
Fatal compiler crash when compiling: tests/neg-macros/i7142:
assertion failed: undefined symbol value x at line 11
dotty.DottyPredef$.assertFail(DottyPredef.scala:17)
dotty.tools.dotc.transform.TreeChecker$Checker.assertDefined(TreeChecker.scala:207)
dotty.tools.dotc.transform.TreeChecker$Checker.typedIdent(TreeChecker.scala:342)
dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2130)
dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2208)
dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:123)
dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:304)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2247)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2243)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2259)
dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:289)
dotty.tools.dotc.typer.Typer.typedInlined(Typer.scala:1361)
dotty.tools.dotc.transform.TreeChecker$Checker.typedInlined$$anonfun$1(TreeChecker.scala:463)
dotty.tools.dotc.transform.TreeChecker$Checker.withDefinedSyms(TreeChecker.scala:171)
dotty.tools.dotc.transform.TreeChecker$Checker.typedInlined(TreeChecker.scala:463)
dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2172)
dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2209)
dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:123)
dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:304)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2247)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2259)
dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:289)
dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:2303)
dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:2325)
dotty.tools.dotc.transform.TreeChecker$Checker.typedStats(TreeChecker.scala:478)
dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:1812)
dotty.tools.dotc.transform.TreeChecker$Checker.typedClassDef(TreeChecker.scala:418)
dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2141)
dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2208)
dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:123)
dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:304)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2247)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2259)
dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:289)
dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:2281)
dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:2325)
dotty.tools.dotc.transform.TreeChecker$Checker.typedStats(TreeChecker.scala:478)
dotty.tools.dotc.typer.Typer.typedPackageDef(Typer.scala:1938)
dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2182)
dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2209)
dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:123)
dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:304)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2247)
dotty.tools.dotc.typer.Typer.typed(Typer.scala:2259)
dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:289)
dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:2367)
dotty.tools.dotc.transform.TreeChecker.check(TreeChecker.scala:124)
dotty.tools.dotc.transform.TreeChecker.run(TreeChecker.scala:97)
dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:315)
scala.collection.immutable.List.map(List.scala:219)
dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:316)
dotty.tools.dotc.Run.runPhases$4$$anonfun$4(Run.scala:167)
dotty.runtime.function.JProcedure1.apply(JProcedure1.java:15)
dotty.runtime.function.JProcedure1.apply(JProcedure1.java:10)
scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323)
dotty.tools.dotc.Run.runPhases$5(Run.scala:177)
dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:185)
dotty.runtime.function.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:65)
dotty.tools.dotc.Run.compileUnits(Run.scala:192)
dotty.tools.dotc.Run.compileSources(Run.scala:129)
dotty.tools.dotc.Run.compile(Run.scala:112)
dotty.tools.dotc.Driver.doCompile(Driver.scala:36)
dotty.tools.dotc.Driver.process(Driver.scala:189)
dotty.tools.dotc.Driver.process(Driver.scala:158)
dotty.tools.vulpix.ParallelTesting$Test.compile(ParallelTesting.scala:483)
dotty.tools.vulpix.ParallelTesting$CompilationLogic.compileTestSource$$anonfun$2$$anonfun$1(ParallelTesting.scala:208)
scala.collection.immutable.List.map(List.scala:223)
dotty.tools.vulpix.ParallelTesting$CompilationLogic.compileTestSource$$anonfun$1(ParallelTesting.scala:208)
scala.util.Try$.apply(Try.scala:210)
dotty.tools.vulpix.ParallelTesting$CompilationLogic.dotty$tools$vulpix$ParallelTesting$CompilationLogic$$compileTestSource(ParallelTesting.scala:209)
dotty.tools.vulpix.ParallelTesting$$anon$2.checkTestSource$$anonfun$1(ParallelTesting.scala:252)
dotty.runtime.function.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
dotty.tools.vulpix.ParallelTesting$Test.tryCompile(ParallelTesting.scala:424)
dotty.tools.vulpix.ParallelTesting$$anon$2.checkTestSource(ParallelTesting.scala:255)
dotty.tools.vulpix.ParallelTesting$Test$LoggedRunnable.run(ParallelTesting.scala:323)
dotty.tools.vulpix.ParallelTesting$$anon$2.run(ParallelTesting.scala:250)
java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1386)
java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

@LPTK
Copy link
Contributor Author

LPTK commented Jan 23, 2020

And here's another one to watch out for:

package macros
import scala.quoted._

var saved = Option.empty[Expr[Any]]

def oops(c: Expr[Any])(given QuoteContext) = {
  if saved.isEmpty then
    saved = Some(c)
    c
  else saved.get
}
inline def test(c: Any) = ${oops('c)}

object Test {
  class A(x: Int) {
    macros.test(x)
  }
  class B(y: String) {
    macros.test(y)
  }
}

exception while typing final module class Test$() extends Object(), _root_.scala.Serializable { this: Test.type =>
  class A(x: Int) extends Object() {
    private[this] val x: Int
    {
      {
        A.this.x
      }
    }
  }
  class B(y: String) extends Object() {
    private[this] val y: String
    {
      {
        A.this.x
      }
    }
  }
} of class class dotty.tools.dotc.ast.Trees$TypeDef # 20675
...
*** error while checking tests/neg-macros/i7142/Test_2.scala after phase typer ***
java.lang.AssertionError: assertion failed: error while typing A.this, value <local B> is not contained in class A while compiling tests/neg-macros/i7142/Test_2.scala
Fatal compiler crash when compiling: tests/neg-macros/i7142:
assertion failed: error while typing A.this, value <local B> is not contained in class A
dotty.DottyPredef$.assertFail(DottyPredef.scala:17)
dotty.tools.dotc.transform.TreeChecker$Checker.typedThis(TreeChecker.scala:383)
...

nicolasstucki added a commit that referenced this issue Feb 5, 2020
Fix #7142: Detect escaped variables across macro expansion
@LPTK
Copy link
Contributor Author

LPTK commented Feb 5, 2020

@nicolasstucki @liufengyun, the second example still crashes the compiler!

// Macro_1.scala

package macros
import scala.quoted._

var saved = Option.empty[Expr[Any]]

def oops(c: Expr[Any])(given QuoteContext) = {
  if saved.isEmpty then
    saved = Some(c)
    c
  else saved.get
}
inline def test(c: Any) = ${oops('c)}
// Test_2.scala

object Test {
  class A(x: Int) {
    macros.test(x)
  }
  class B(y: String) {
    macros.test(y)
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants