From f1d9667189ebad285553e912a2eac4a64093c8bf Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 6 Jul 2015 15:06:49 +1000 Subject: [backport] Avoid masking real errors with NotImplemented awaiting Future[Nothing] This commit disabled live variable analysis for intermediate values of type Nothing. Fixes #104 (cherry picked from commit 6353443a0adec384172c38efac3bc96b9d2cbad2) --- .../scala/scala/async/internal/LiveVariables.scala | 2 +- .../scala/async/run/live/LiveVariablesSpec.scala | 26 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/scala/scala/async/internal/LiveVariables.scala b/src/main/scala/scala/async/internal/LiveVariables.scala index 23063ba..79ba18e 100644 --- a/src/main/scala/scala/async/internal/LiveVariables.scala +++ b/src/main/scala/scala/async/internal/LiveVariables.scala @@ -56,7 +56,7 @@ trait LiveVariables { // determine which fields should be live also at the end (will not be nulled out) val noNull: Set[Symbol] = liftedSyms.filter { sym => - sym.tpe.typeSymbol.isPrimitiveValueClass || liftables.exists { tree => + sym.tpe.typeSymbol.isPrimitiveValueClass || sym.tpe.typeSymbol == definitions.NothingClass || liftables.exists { tree => !liftedSyms.contains(tree.symbol) && tree.exists(_.symbol == sym) } } diff --git a/src/test/scala/scala/async/run/live/LiveVariablesSpec.scala b/src/test/scala/scala/async/run/live/LiveVariablesSpec.scala index 17d33af..09d01c1 100644 --- a/src/test/scala/scala/async/run/live/LiveVariablesSpec.scala +++ b/src/test/scala/scala/async/run/live/LiveVariablesSpec.scala @@ -263,4 +263,30 @@ class LiveVariablesSpec { } baz() } + + // https://github.com/scala/async/issues/104 + @Test def dontNullOutVarsOfTypeNothing_t104(): Unit = { + implicit val ec: scala.concurrent.ExecutionContext = null + import scala.async.Async._ + import scala.concurrent.duration.Duration + import scala.concurrent.{Await, Future} + import scala.concurrent.ExecutionContext.Implicits.global + def errorGenerator(randomNum: Double) = { + Future { + if (randomNum < 0) { + throw new IllegalStateException("Random number was too low!") + } else { + throw new IllegalStateException("Random number was too high!") + } + } + } + def randomTimesTwo = async { + val num = _root_.scala.math.random + if (num < 0 || num > 1) { + await(errorGenerator(num)) + } + num * 2 + } + Await.result(randomTimesTwo, TestLatch.DefaultTimeout) // was: NotImplementedError + } } -- cgit v1.2.3 From e1377aa06ffe817d15315bbce3a6a636f2dd1f0e Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 7 Jul 2015 09:35:05 +1000 Subject: Avoid compiler warning when awaiting Future[Unit] During the ANF transform, we were generating a tree of the shape: { val temp: Unit = await(futureOfUnit) temp () } I tried to simplifiy this to avoid creating the temporary value, but this proved difficult as it would have required changes to the subsequent state machine transformation. Even replacing `temp` with `()` made the state machine transform harder. So for now, I've just inserted `temp.asInstanceOf[Unit]` to hide from the compiler warning. Fixes #74 (cherry picked from commit f3f058991b207a07041672a7e119422d9054788d) --- .../scala/scala/async/internal/AnfTransform.scala | 12 +++++++- src/test/scala/scala/async/run/WarningsSpec.scala | 35 ++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/test/scala/scala/async/run/WarningsSpec.scala diff --git a/src/main/scala/scala/async/internal/AnfTransform.scala b/src/main/scala/scala/async/internal/AnfTransform.scala index bf66fde..3c8c837 100644 --- a/src/main/scala/scala/async/internal/AnfTransform.scala +++ b/src/main/scala/scala/async/internal/AnfTransform.scala @@ -73,7 +73,17 @@ private[async] trait AnfTransform { expr match { case Apply(fun, args) if isAwait(fun) => val valDef = defineVal(name.await, expr, tree.pos) - stats :+ valDef :+ atPos(tree.pos)(gen.mkAttributedStableRef(valDef.symbol)).setType(tree.tpe) + val ref = gen.mkAttributedStableRef(valDef.symbol).setType(tree.tpe) + val ref1 = if (ref.tpe =:= definitions.UnitTpe) + // https://github.com/scala/async/issues/74 + // Use a cast to hide from "pure expression does nothing" error + // + // TODO avoid creating a ValDef for the result of this await to avoid this tree shape altogether. + // This will require some deeper changes to the later parts of the macro which currently assume regular + // tree structure around `await` calls. + gen.mkCast(ref, definitions.UnitTpe) + else ref + stats :+ valDef :+ atPos(tree.pos)(ref1) case If(cond, thenp, elsep) => // if type of if-else is Unit don't introduce assignment, diff --git a/src/test/scala/scala/async/run/WarningsSpec.scala b/src/test/scala/scala/async/run/WarningsSpec.scala new file mode 100644 index 0000000..3a7843a --- /dev/null +++ b/src/test/scala/scala/async/run/WarningsSpec.scala @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012-2014 Typesafe Inc. + */ + +package scala.async +package run + +import org.junit.Test + +import scala.async.internal.AsyncId +import scala.concurrent.Await +import scala.concurrent.duration._ +import scala.language.{postfixOps, reflectiveCalls} + + +class WarningsSpec { + + @Test + // https://github.com/scala/async/issues/74 + def noPureExpressionInStatementPositionWarning_t74() { + val tb = mkToolbox(s"-cp ${toolboxClasspath} -Xfatal-warnings") + // was: "a pure expression does nothing in statement position; you may be omitting necessary parentheses" + tb.eval(tb.parse { + """ + | import scala.async.internal.AsyncId._ + | async { + | if ("".isEmpty) { + | await(println("hello")) + | () + | } else 42 + | } + """.stripMargin + }) + } +} -- cgit v1.2.3