Skip to content

Commit

Permalink
Small cleanups after code review
Browse files Browse the repository at this point in the history
 - More internal docs
 - Be more frugal with the `NoAwait` attachment, for some AST node
   types this is implied.
 - Just use `x`, rather than what was effectively
   `x.reverseMap(identity).reverse`
  • Loading branch information
retronym committed Sep 23, 2015
1 parent e3ff038 commit 168e10c
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 12 deletions.
14 changes: 11 additions & 3 deletions src/main/scala/scala/async/internal/AnfTransform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ private[async] trait AnfTransform {

case Block(stats, expr) =>
val trees = stats.flatMap(linearize.transformToList).filterNot(isLiteralUnit) ::: linearize.transformToList(expr)
eliminateLabelParameters(trees)
eliminateMatchEndLabelParameter(trees)

case ValDef(mods, name, tpt, rhs) =>
if (containsAwait(rhs)) {
Expand Down Expand Up @@ -273,7 +273,15 @@ private[async] trait AnfTransform {
}

// Replace the label parameters on `matchEnd` with use of a `matchRes` temporary variable
def eliminateLabelParameters(statsExpr: List[Tree]): List[Tree] = {
//
// CaseDefs are translated to labels without parmeters. A terminal label, `matchEnd`, accepts
// a parameter which is the result of the match (this is regular, so even Unit-typed matches have this).
//
// For our purposes, it is easier to:
// - extract a `matchRes` variable
// - rewrite the terminal label def to take no parameters, and instead read this temp variable
// - change jumps to the terminal label to an assignment and a no-arg label application
def eliminateMatchEndLabelParameter(statsExpr: List[Tree]): List[Tree] = {
import internal.{methodType, setInfo}
val caseDefToMatchResult = collection.mutable.Map[Symbol, Symbol]()

Expand Down Expand Up @@ -304,7 +312,7 @@ private[async] trait AnfTransform {
)
}
matchResults.toList match {
case Nil => statsExpr0.reverse
case Nil => statsExpr
case r1 :: Nil => (r1 +: statsExpr0.reverse) :+ atPos(tree.pos)(gen.mkAttributedIdent(r1.symbol))
case _ => c.error(macroPos, "Internal error: unexpected tree encountered during ANF transform " + statsExpr); statsExpr
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/scala/scala/async/internal/AsyncTransform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,11 @@ trait AsyncTransform {
}

val isSimple = asyncBlock.asyncStates.size == 1
if (isSimple)
val result = if (isSimple)
futureSystemOps.spawn(body, execContext) // generate lean code for the simple case of `async { 1 + 1 }`
else
startStateMachine
cleanupContainsAwaitAttachments(result)
}

def logDiagnostics(anfTree: Tree, states: Seq[String]) {
Expand Down
35 changes: 27 additions & 8 deletions src/main/scala/scala/async/internal/TransformUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -396,13 +396,18 @@ private[async] trait TransformUtils {
* in search of a sub tree that was decorated with the cached answer.
*/
final def containsAwaitCached(t: Tree): Tree => Boolean = {
def treeCannotContainAwait(t: Tree) = t match {
case _: Ident | _: TypeTree | _: Literal => true
case _ => false
}
def shouldAttach(t: Tree) = !treeCannotContainAwait(t)
val symtab = c.universe.asInstanceOf[scala.reflect.internal.SymbolTable]
def attachContainsAwait(t: Tree): Unit = {
def attachContainsAwait(t: Tree): Unit = if (shouldAttach(t)) {
val t1 = t.asInstanceOf[symtab.Tree]
t1.updateAttachment(ContainsAwait)
t1.removeAttachment[NoAwait.type]
}
def attachNoAwait(t: Tree): Unit = {
def attachNoAwait(t: Tree): Unit = if (shouldAttach(t)) {
val t1 = t.asInstanceOf[symtab.Tree]
t1.updateAttachment(NoAwait)
}
Expand All @@ -423,22 +428,36 @@ private[async] trait TransformUtils {
markContainsAwaitTraverser.traverse(t)

(t: Tree) => {
val symtab = c.universe.asInstanceOf[scala.reflect.internal.SymbolTable]
object traverser extends Traverser {
var containsAwait = false
override def traverse(tree: Tree): Unit = {
if (tree.asInstanceOf[symtab.Tree].hasAttachment[NoAwait.type])
()
else if (tree.asInstanceOf[symtab.Tree].hasAttachment[ContainsAwait.type])
containsAwait = true
else super.traverse(tree)
def castTree = tree.asInstanceOf[symtab.Tree]
if (!castTree.hasAttachment[NoAwait.type]) {
if (castTree.hasAttachment[ContainsAwait.type])
containsAwait = true
else if (!treeCannotContainAwait(t))
super.traverse(tree)
}
}
}
traverser.traverse(t)
traverser.containsAwait
}
}

final def cleanupContainsAwaitAttachments(t: Tree): t.type = {
val symtab = c.universe.asInstanceOf[scala.reflect.internal.SymbolTable]
t.foreach {t =>
t.asInstanceOf[symtab.Tree].removeAttachment[ContainsAwait.type]
t.asInstanceOf[symtab.Tree].removeAttachment[NoAwait.type]
}
t
}

// First modification to translated patterns:
// - Set the type of label jumps to `Unit`
// - Propagate this change to trees known to directly enclose them:
// ``If` / `Block`) adjust types of enclosing
final def adjustTypeOfTranslatedPatternMatches(t: Tree, owner: Symbol): Tree = {
import definitions.UnitTpe
typingTransform(t, owner) {
Expand Down

0 comments on commit 168e10c

Please sign in to comment.