Skip to content

Commit 76d46ee

Browse files
committed
Nullify unused result in async transform
1 parent ab41073 commit 76d46ee

File tree

4 files changed

+49
-20
lines changed

4 files changed

+49
-20
lines changed

src/compiler/scala/tools/nsc/transform/async/AnfTransform.scala

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,10 @@ private[async] trait AnfTransform extends TransformUtils {
9191
val simpleApply = treeCopy.Apply(tree, simpleFun, argExprss)
9292
simpleApply.attachments.remove[ContainsAwait.type]
9393
if (isAwait(fun)) {
94-
val valDef = defineVal(transformState.name.await(), treeCopy.Apply(tree, fun, argExprss), tree.pos)
95-
val ref = gen.mkAttributedStableRef(valDef.symbol).setType(tree.tpe)
94+
val valDef = defineVal(transformState.name.await(), treeCopy.Apply(tree, fun, argExprss), tree.pos, isLocalVar = true)
95+
val ref = gen.mkAttributedStableRef(valDef.symbol)
96+
.setType(tree.tpe)
97+
.updateAttachment(ResRef)
9698
currentStats += valDef
9799
atPos(tree.pos)(ref)
98100
} else {
@@ -101,13 +103,15 @@ private[async] trait AnfTransform extends TransformUtils {
101103

102104
case Block(stats, expr) =>
103105
// First, transform the block contents into a separate List[Tree]
104-
val (trees, _) = withNewControlFlowBlock {
105-
stats.foreach(stat => {
106-
val expr = transform(stat);
107-
if (!isLiteralUnit(expr)) currentStats += expr
108-
})
106+
val (trees, _) = withNewControlFlowBlock[Unit] {
107+
for (stat <- stats)
108+
transform(stat) match {
109+
case t0 if t0.hasAttachment[ResRef.type] =>
110+
currentStats += typedPos(t0.pos)(Assign(t0, gen.mkZero(t0.symbol.info)))
111+
case t0 if !isLiteralUnit(t0) => currentStats += t0
112+
case _ =>
113+
}
109114
currentStats += transform(expr)
110-
()
111115
}
112116

113117
// Identify groups of statements compiled from pattern matches and process them separately to
@@ -125,7 +129,7 @@ private[async] trait AnfTransform extends TransformUtils {
125129

126130
// However, we let `onTail` add the expr to `currentStats` (that was more efficient than using `ts.dropRight(1).foreach(addToStats)`)
127131
// Compensate by removing it from the buffer and returning the expr.
128-
// If the expr it itself a unit-typed LabelDef, move it to the stats and leave a Unit expression in its place
132+
// If the expr is itself a unit-typed LabelDef, move it to the stats and leave a Unit expression in its place
129133
// to make life easier for transformMatchOrIf
130134
currentStats.remove(currentStats.size - 1) match {
131135
case ld: LabelDef if ld.tpe.typeSymbol == definitions.BoxedUnitClass =>
@@ -222,7 +226,7 @@ private[async] trait AnfTransform extends TransformUtils {
222226
// after the preceding sibling, but rather will be the target of a control flow jump.
223227
private def transformNewControlFlowBlock(tree: Tree): Tree = {
224228
val savedStats = currentStats
225-
this.currentStats = new ListBuffer[Tree]
229+
this.currentStats = ListBuffer.empty[Tree]
226230
try transform(tree) match {
227231
case b@Block(stats, expr) =>
228232
treeCopy.Block(b, currentStats.prependToList(stats), expr)
@@ -237,7 +241,7 @@ private[async] trait AnfTransform extends TransformUtils {
237241

238242
private def withNewControlFlowBlock[T](f: => T): (List[Tree], T) = {
239243
val savedStats = currentStats
240-
this.currentStats = new ListBuffer[Tree]
244+
this.currentStats = ListBuffer.empty[Tree]
241245
try {
242246
val result = f
243247
(currentStats.toList, result)
@@ -355,15 +359,18 @@ private[async] trait AnfTransform extends TransformUtils {
355359
} else t
356360
}
357361

358-
def defineVal(name: global.TermName, rhs: global.Tree, pos: Position): ValDef = {
359-
val sym = currentOwner.newTermSymbol(name, pos, Flags.SYNTHETIC).setInfo(rhs.tpe)
362+
def defineVal(name: global.TermName, rhs: global.Tree, pos: Position, isLocalVar: Boolean = false): ValDef = {
363+
val flags = if (isLocalVar) Flags.MUTABLE | Flags.SYNTHETIC else Flags.SYNTHETIC
364+
val sym = currentOwner.newTermSymbol(name, pos, flags).setInfo(rhs.tpe)
360365
ValDef(sym, rhs.changeOwner((currentOwner, sym))).setType(NoType)
361366
}
362367

363368
def defineVar(name: TermName, tp: Type, pos: Position): ValDef = {
364369
val sym = currentOwner.newTermSymbol(name, pos, Flags.MUTABLE | Flags.SYNTHETIC).setInfo(tp)
365370
ValDef(sym, gen.mkZero(tp).setPos(pos)).setType(NoType)
366371
}
372+
373+
private object ResRef extends PlainAttachment
367374
}
368375

369376
private def typedAssign(lhs: Tree, varSym: Symbol) =

src/compiler/scala/tools/nsc/transform/async/ExprBuilder.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212

1313
package scala.tools.nsc.transform.async
1414

15-
import scala.collection.mutable
16-
import scala.collection.mutable.ListBuffer
15+
import scala.collection.mutable, mutable.ListBuffer
1716

1817
trait ExprBuilder extends TransformUtils with AsyncAnalysis {
1918
import global._
@@ -57,7 +56,7 @@ trait ExprBuilder extends TransformUtils with AsyncAnalysis {
5756
override def toString: String = mkToString //+ " (was: " + initToString + ")"
5857
// private val initToString = mkToString
5958
def insertNullAssignments(preNulls: Iterator[Symbol], postNulls: Iterator[Symbol]): Unit = {
60-
val stats1 = mutable.ListBuffer[Tree]()
59+
val stats1 = ListBuffer.empty[Tree]
6160
def addNullAssigments(syms: Iterator[Symbol]): Unit = {
6261
for (fieldSym <- syms) {
6362
stats1 += typedCurrentPos(Assign(currentTransformState.memberRef(fieldSym), gen.mkZero(fieldSym.info)))

test/async/run/a265.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//> using options -Xasync -Xsource:3-cross
2+
//> abusing options -Xasync -Xsource:3-cross -Vprint:typer,async
3+
4+
import concurrent.*, ExecutionContext.Implicits.{given, *}, duration.Duration.Inf
5+
import scala.tools.testkit.AssertUtil.assertNotReachable
6+
import scala.tools.testkit.async.Async.*
7+
import org.junit.Assert.*
8+
9+
object Test {
10+
def main(args: Array[String]): Unit = {
11+
val data = "hello, world"
12+
val r = async {
13+
//println(await(Future(data)))
14+
await(Future(data))
15+
"goodbye, all!" // check local var is null
16+
}
17+
assertNotReachable(data, r) {
18+
assertEquals("goodbye, all!", Await.result(r, Inf))
19+
}
20+
}
21+
}

test/junit/scala/tools/nsc/async/AnnotationDrivenAsyncTest.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,9 @@ class AnnotationDrivenAsyncTest {
448448
"""val x = id(1)
449449
|--------------------------------------------------------------------------------
450450
|case 0 => {\n val awaitable$async: scala.tools.nsc.async.CustomFuture = scala.tools.nsc.async.CustomFuture._successful(scala.Int.box(Test.this.id(1)));\n tr = self.getCompleted(awaitable$async);\n self.state_=(1);\n if (null.!=(tr))\n while$()\n else\n {\n self.onComplete(awaitable$async);\n return ()\n }\n}
451-
|<synthetic> val await$1: Object = {\n val tryGetResult$async: Object = self.tryGet(tr);\n if (self.eq(tryGetResult$async))\n return ()\n else\n tryGetResult$async.$asInstanceOf[Object]()\n}
452-
|self.x = scala.Int.unbox(await$1)
451+
|<synthetic> var await$1: Object = {\n val tryGetResult$async: Object = self.tryGet(tr);\n if (self.eq(tryGetResult$async))\n return ()\n else\n tryGetResult$async.$asInstanceOf[Object]()\n}
452+
|<synthetic> val x$1: Object = await$1
453+
|self.x = scala.Int.unbox(x$1)
453454
|
454455
|
455456
|val y = id(2)
@@ -458,8 +459,9 @@ class AnnotationDrivenAsyncTest {
458459
|tr = self.getCompleted(awaitable$async)
459460
|self.state_=(2)
460461
|if (null.!=(tr))\n while$()\nelse\n {\n self.onComplete(awaitable$async);\n return ()\n }
461-
|<synthetic> val await$2: Object = {\n val tryGetResult$async: Object = self.tryGet(tr);\n if (self.eq(tryGetResult$async))\n return ()\n else\n tryGetResult$async.$asInstanceOf[Object]()\n}
462-
|val y: Int = scala.Int.unbox(await$2)
462+
|<synthetic> var await$2: Object = {\n val tryGetResult$async: Object = self.tryGet(tr);\n if (self.eq(tryGetResult$async))\n return ()\n else\n tryGetResult$async.$asInstanceOf[Object]()\n}
463+
|<synthetic> val x$2: Object = await$2
464+
|val y: Int = scala.Int.unbox(x$2)
463465
|
464466
|
465467
|x.$plus(y)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy