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

Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 20 additions & 13 deletions src/compiler/scala/tools/nsc/transform/async/AnfTransform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ private[async] trait AnfTransform extends TransformUtils {
val simpleApply = treeCopy.Apply(tree, simpleFun, argExprss)
simpleApply.attachments.remove[ContainsAwait.type]
if (isAwait(fun)) {
val valDef = defineVal(transformState.name.await(), treeCopy.Apply(tree, fun, argExprss), tree.pos)
val ref = gen.mkAttributedStableRef(valDef.symbol).setType(tree.tpe)
val valDef = defineVal(transformState.name.await(), treeCopy.Apply(tree, fun, argExprss), tree.pos, isLocalVar = true)
val ref = gen.mkAttributedStableRef(valDef.symbol)
.setType(tree.tpe)
.updateAttachment(ResRef)
currentStats += valDef
atPos(tree.pos)(ref)
} else {
Expand All @@ -101,13 +103,15 @@ private[async] trait AnfTransform extends TransformUtils {

case Block(stats, expr) =>
// First, transform the block contents into a separate List[Tree]
val (trees, _) = withNewControlFlowBlock {
stats.foreach(stat => {
val expr = transform(stat);
if (!isLiteralUnit(expr)) currentStats += expr
})
val (trees, _) = withNewControlFlowBlock[Unit] {
for (stat <- stats)
transform(stat) match {
case t0 if t0.hasAttachment[ResRef.type] =>
currentStats += typedPos(t0.pos)(Assign(t0, gen.mkZero(t0.symbol.info)))
case t0 if !isLiteralUnit(t0) => currentStats += t0
case _ =>
}
currentStats += transform(expr)
()
}

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

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

private def withNewControlFlowBlock[T](f: => T): (List[Tree], T) = {
val savedStats = currentStats
this.currentStats = new ListBuffer[Tree]
this.currentStats = ListBuffer.empty[Tree]
try {
val result = f
(currentStats.toList, result)
Expand Down Expand Up @@ -355,15 +359,18 @@ private[async] trait AnfTransform extends TransformUtils {
} else t
}

def defineVal(name: global.TermName, rhs: global.Tree, pos: Position): ValDef = {
val sym = currentOwner.newTermSymbol(name, pos, Flags.SYNTHETIC).setInfo(rhs.tpe)
def defineVal(name: global.TermName, rhs: global.Tree, pos: Position, isLocalVar: Boolean = false): ValDef = {
val flags = if (isLocalVar) Flags.MUTABLE | Flags.SYNTHETIC else Flags.SYNTHETIC
val sym = currentOwner.newTermSymbol(name, pos, flags).setInfo(rhs.tpe)
ValDef(sym, rhs.changeOwner((currentOwner, sym))).setType(NoType)
}

def defineVar(name: TermName, tp: Type, pos: Position): ValDef = {
val sym = currentOwner.newTermSymbol(name, pos, Flags.MUTABLE | Flags.SYNTHETIC).setInfo(tp)
ValDef(sym, gen.mkZero(tp).setPos(pos)).setType(NoType)
}

private object ResRef extends PlainAttachment
}

private def typedAssign(lhs: Tree, varSym: Symbol) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@

package scala.tools.nsc.transform.async

import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.collection.mutable, mutable.ListBuffer

trait ExprBuilder extends TransformUtils with AsyncAnalysis {
import global._
Expand Down Expand Up @@ -57,7 +56,7 @@ trait ExprBuilder extends TransformUtils with AsyncAnalysis {
override def toString: String = mkToString //+ " (was: " + initToString + ")"
// private val initToString = mkToString
def insertNullAssignments(preNulls: Iterator[Symbol], postNulls: Iterator[Symbol]): Unit = {
val stats1 = mutable.ListBuffer[Tree]()
val stats1 = ListBuffer.empty[Tree]
def addNullAssigments(syms: Iterator[Symbol]): Unit = {
for (fieldSym <- syms) {
stats1 += typedCurrentPos(Assign(currentTransformState.memberRef(fieldSym), gen.mkZero(fieldSym.info)))
Expand Down
21 changes: 21 additions & 0 deletions test/async/run/a265.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//> using options -Xasync -Xsource:3-cross
//> abusing options -Xasync -Xsource:3-cross -Vprint:typer,async

import concurrent.*, ExecutionContext.Implicits.{given, *}, duration.Duration.Inf
import scala.tools.testkit.AssertUtil.assertNotReachable
import scala.tools.testkit.async.Async.*
import org.junit.Assert.*

object Test {
def main(args: Array[String]): Unit = {
val data = "hello, world"
val r = async {
//println(await(Future(data)))
await(Future(data))
"goodbye, all!" // check local var is null
}
assertNotReachable(data, r) {
assertEquals("goodbye, all!", Await.result(r, Inf))
}
}
}
10 changes: 6 additions & 4 deletions test/junit/scala/tools/nsc/async/AnnotationDrivenAsyncTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -450,8 +450,9 @@ class AnnotationDrivenAsyncTest {
|tr = self.getCompleted(awaitable$async)
|self.state_=(1)
|if (null.!=(tr))\n while$()\nelse\n {\n self.onComplete(awaitable$async);\n return ()\n }
|<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}
|self.x = scala.Int.unbox(await$1)
|<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}
|<synthetic> val x$1: Object = await$1
|self.x = scala.Int.unbox(x$1)
|
|
|val y = id(2)
Expand All @@ -460,8 +461,9 @@ class AnnotationDrivenAsyncTest {
|tr = self.getCompleted(awaitable$async)
|self.state_=(2)
|if (null.!=(tr))\n while$()\nelse\n {\n self.onComplete(awaitable$async);\n return ()\n }
|<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}
|val y: Int = scala.Int.unbox(await$2)
|<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}
|<synthetic> val x$2: Object = await$2
|val y: Int = scala.Int.unbox(x$2)
|
|
|x.$plus(y)
Expand Down