Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d92d257

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

File tree

3 files changed

+43
-16
lines changed

3 files changed

+43
-16
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+
}

0 commit comments

Comments
 (0)