From 103ec8cb5229f1bd6cda68ef4126e4b875895b90 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 7 Feb 2019 15:44:18 +1000 Subject: [PATCH] Fix ownership corruption problem in the awaited expression Previously, `whyDoYouHateMe` was incorrectly owned by `jerk`, rather than `pointlessSymbolOwner` after the ANF transform, which in turn led to: ``` java.util.NoSuchElementException: value whyDoHateMe at scala.collection.mutable.AnyRefMap$ExceptionDefault.apply(AnyRefMap.scala:425) at scala.collection.mutable.AnyRefMap$ExceptionDefault.apply(AnyRefMap.scala:424) at scala.collection.mutable.AnyRefMap.apply(AnyRefMap.scala:180) at scala.tools.nsc.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder$locals$.load(BCodeSkelBuilder.scala:390) at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.genLoad(BCodeBodyBuilder.scala:354) ``` --- .../scala/async/internal/AnfTransform.scala | 2 +- .../scala/async/run/late/LateExpansion.scala | 52 ++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/main/scala/scala/async/internal/AnfTransform.scala b/src/main/scala/scala/async/internal/AnfTransform.scala index fa230999..d697aee9 100644 --- a/src/main/scala/scala/async/internal/AnfTransform.scala +++ b/src/main/scala/scala/async/internal/AnfTransform.scala @@ -255,7 +255,7 @@ private[async] trait AnfTransform { case ValDef(mods, name, tpt, rhs) => if (containsAwait(rhs)) { - val stats :+ expr = api.atOwner(api.currentOwner.owner)(linearize.transformToList(rhs)) + val stats :+ expr = linearize.transformToList(rhs) stats.foreach(_.changeOwner(api.currentOwner, api.currentOwner.owner)) stats :+ treeCopy.ValDef(tree, mods, name, tpt, expr) } else List(tree) diff --git a/src/test/scala/scala/async/run/late/LateExpansion.scala b/src/test/scala/scala/async/run/late/LateExpansion.scala index 5261209b..57bcbfa1 100644 --- a/src/test/scala/scala/async/run/late/LateExpansion.scala +++ b/src/test/scala/scala/async/run/late/LateExpansion.scala @@ -443,6 +443,56 @@ class LateExpansion { """) } + @Test def testByNameOwner(): Unit = { + val result = run( + """ + import scala.async.run.late.{autoawait,lateasync} + object Bleh { + @autoawait @lateasync def asyncCall(): Int = 0 + def byName[T](fn: => T): T = fn + } + object Boffo { + @autoawait @lateasync def jerk(): Unit = { + val pointlessSymbolOwner = 1 match { + case _ => + Bleh.asyncCall() + Bleh.byName { + val whyDoHateMe = 1 + whyDoHateMe + } + } + } + } + object Test { + @lateasync def test() = Boffo.jerk() + } + """) + } + + @Test def testByNameOwner2(): Unit = { + val result = run( + """ + import scala.async.run.late.{autoawait,lateasync} + object Bleh { + @autoawait @lateasync def bleh = Bleh + def byName[T](fn: => T): T = fn + } + object Boffo { + @autoawait @lateasync def slob(): Unit = { + val pointlessSymbolOwner = { + Bleh.bleh.byName { + val whyDoHateMeToo = 1 + whyDoHateMeToo + } + } + } + } + object Test { + @lateasync def test() = Boffo.slob() + } + """) + } + private def createTempDir(): File = { val f = File.createTempFile("output", "") f.delete() @@ -455,9 +505,9 @@ class LateExpansion { try { val reporter = new StoreReporter val settings = new Settings(println(_)) - //settings.processArgumentString("-Xprint:refchecks,patmat,postpatmat,jvm -nowarn") settings.outdir.value = out.getAbsolutePath settings.embeddedDefaults(getClass.getClassLoader) + // settings.processArgumentString("-Xprint:patmat,postpatmat,jvm -nowarn") val isInSBT = !settings.classpath.isSetByUser if (isInSBT) settings.usejavacp.value = true val global = new Global(settings, reporter) {