Skip to content

Commit 38416ae

Browse files
committed
Merge pull request #92 from retronym/merge/2.10.x-to-master-20140930
Merge 2.10.x to master (plus a test)
2 parents 0f8ea5c + f42efa3 commit 38416ae

File tree

4 files changed

+106
-8
lines changed

4 files changed

+106
-8
lines changed

src/main/scala/scala/async/internal/AnfTransform.scala

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ private[async] trait AnfTransform {
5151
expr match {
5252
case Apply(fun, args) if isAwait(fun) =>
5353
val valDef = defineVal(name.await, expr, tree.pos)
54-
stats :+ valDef :+ gen.mkAttributedStableRef(valDef.symbol).setType(tree.tpe).setPos(tree.pos)
54+
stats :+ valDef :+ atPos(tree.pos)(gen.mkAttributedStableRef(valDef.symbol)).setType(tree.tpe)
5555

5656
case If(cond, thenp, elsep) =>
5757
// if type of if-else is Unit don't introduce assignment,
@@ -68,7 +68,7 @@ private[async] trait AnfTransform {
6868
}
6969
})
7070
val ifWithAssign = treeCopy.If(tree, cond, branchWithAssign(thenp), branchWithAssign(elsep)).setType(definitions.UnitTpe)
71-
stats :+ varDef :+ ifWithAssign :+ gen.mkAttributedStableRef(varDef.symbol).setType(tree.tpe).setPos(tree.pos)
71+
stats :+ varDef :+ ifWithAssign :+ atPos(tree.pos)(gen.mkAttributedStableRef(varDef.symbol)).setType(tree.tpe)
7272
}
7373
case LabelDef(name, params, rhs) =>
7474
statsExprUnit
@@ -93,7 +93,7 @@ private[async] trait AnfTransform {
9393
}
9494
val matchWithAssign = treeCopy.Match(tree, scrut, casesWithAssign).setType(definitions.UnitTpe)
9595
require(matchWithAssign.tpe != null, matchWithAssign)
96-
stats :+ varDef :+ matchWithAssign :+ gen.mkAttributedStableRef(varDef.symbol).setPos(tree.pos).setType(tree.tpe)
96+
stats :+ varDef :+ matchWithAssign :+ atPos(tree.pos)(gen.mkAttributedStableRef(varDef.symbol)).setType(tree.tpe)
9797
}
9898
case _ =>
9999
stats :+ expr
@@ -102,7 +102,7 @@ private[async] trait AnfTransform {
102102

103103
private def defineVar(prefix: String, tp: Type, pos: Position): ValDef = {
104104
val sym = api.currentOwner.newTermSymbol(name.fresh(prefix), pos, MUTABLE | SYNTHETIC).setInfo(uncheckedBounds(tp))
105-
valDef(sym, gen.mkZero(uncheckedBounds(tp))).setType(NoType).setPos(pos)
105+
valDef(sym, mkZero(uncheckedBounds(tp))).setType(NoType).setPos(pos)
106106
}
107107
}
108108

@@ -128,8 +128,7 @@ private[async] trait AnfTransform {
128128

129129
def defineVal(prefix: String, lhs: Tree, pos: Position): ValDef = {
130130
val sym = api.currentOwner.newTermSymbol(name.fresh(prefix), pos, SYNTHETIC).setInfo(uncheckedBounds(lhs.tpe))
131-
lhs.changeOwner(api.currentOwner, sym)
132-
valDef(sym, lhs.changeOwner(api.currentOwner, sym)).setType(NoType).setPos(pos)
131+
internal.valDef(sym, internal.changeOwner(lhs, api.currentOwner, sym)).setType(NoType).setPos(pos)
133132
}
134133

135134
object anf {

src/main/scala/scala/async/internal/AsyncTransform.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ trait AsyncTransform {
8181
List(
8282
asyncBase.nullOut(c.universe)(c.Expr[String](Literal(Constant(fieldSym.name.toString))), c.Expr[Any](Ident(fieldSym))).tree
8383
),
84-
Assign(gen.mkAttributedStableRef(thisType(fieldSym.owner), fieldSym), gen.mkZero(fieldSym.info))
84+
Assign(gen.mkAttributedStableRef(thisType(fieldSym.owner), fieldSym), mkZero(fieldSym.info))
8585
)
8686
}
8787
val asyncState = asyncBlock.asyncStates.find(_.state == state).get

src/main/scala/scala/async/internal/TransformUtils.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,32 @@ private[async] trait TransformUtils {
327327
else NoPrefix
328328
}
329329

330+
private def derivedValueClassUnbox(cls: Symbol) =
331+
(cls.info.decls.find(sym => sym.isMethod && sym.asTerm.isParamAccessor) getOrElse NoSymbol)
332+
333+
def mkZero(tp: Type): Tree = {
334+
if (tp.typeSymbol.asClass.isDerivedValueClass) {
335+
val argZero = mkZero(derivedValueClassUnbox(tp.typeSymbol).infoIn(tp).resultType)
336+
val baseType = tp.baseType(tp.typeSymbol) // use base type here to dealias / strip phantom "tagged types" etc.
337+
338+
// By explicitly attributing the types and symbols here, we subvert privacy.
339+
// Otherwise, ticket86PrivateValueClass would fail.
340+
341+
// Approximately:
342+
// q"new ${valueClass}[$..targs](argZero)"
343+
val target: Tree = gen.mkAttributedSelect(
344+
c.typecheck(atMacroPos(
345+
New(TypeTree(baseType)))), tp.typeSymbol.asClass.primaryConstructor)
346+
347+
val zero = gen.mkMethodCall(target, argZero :: Nil)
348+
349+
// restore the original type which we might otherwise have weakened with `baseType` above
350+
gen.mkCast(zero, tp)
351+
} else {
352+
gen.mkZero(tp)
353+
}
354+
}
355+
330356
// =====================================
331357
// Copy/Pasted from Scala 2.10.3. See SI-7694.
332358
private lazy val UncheckedBoundsClass = {

src/test/scala/scala/async/run/toughtype/ToughType.scala

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,82 @@ class ToughTypeSpec {
239239
val result = Await.result(f, 5.seconds)
240240
result mustEqual (new IntWrapper("foo"))
241241
}
242+
243+
@Test def ticket86NestedValueClass() {
244+
import ExecutionContext.Implicits.global
245+
246+
val f = async {
247+
val a = Future.successful(new IntWrapper("42"))
248+
await(await(a).plusStr)
249+
}
250+
val result = Await.result(f, 5.seconds)
251+
result mustEqual "42!"
252+
}
253+
254+
@Test def ticket86MatchedValueClass(): Unit = {
255+
import ExecutionContext.Implicits.global
256+
257+
def doAThing(param: IntWrapper) = Future(None)
258+
259+
val fut = async {
260+
Option(new IntWrapper("value!")) match {
261+
case Some(valueHolder) =>
262+
await(doAThing(valueHolder))
263+
case None =>
264+
None
265+
}
266+
}
267+
268+
val result = Await.result(fut, 5.seconds)
269+
result mustBe None
270+
}
271+
272+
@Test def ticket86MatchedParameterizedValueClass(): Unit = {
273+
import ExecutionContext.Implicits.global
274+
275+
def doAThing(param: ParamWrapper[String]) = Future(None)
276+
277+
val fut = async {
278+
Option(new ParamWrapper("value!")) match {
279+
case Some(valueHolder) =>
280+
await(doAThing(valueHolder))
281+
case None =>
282+
None
283+
}
284+
}
285+
286+
val result = Await.result(fut, 5.seconds)
287+
result mustBe None
288+
}
289+
290+
@Test def ticket86PrivateValueClass(): Unit = {
291+
import ExecutionContext.Implicits.global
292+
293+
def doAThing(param: PrivateWrapper) = Future(None)
294+
295+
val fut = async {
296+
Option(PrivateWrapper.Instance) match {
297+
case Some(valueHolder) =>
298+
await(doAThing(valueHolder))
299+
case None =>
300+
None
301+
}
302+
}
303+
304+
val result = Await.result(fut, 5.seconds)
305+
result mustBe None
306+
}
242307
}
243308

244-
class IntWrapper(val value: String) extends AnyVal
309+
class IntWrapper(val value: String) extends AnyVal {
310+
def plusStr = Future.successful(value + "!")
311+
}
312+
class ParamWrapper[T](val value: T) extends AnyVal
313+
314+
class PrivateWrapper private (private val value: String) extends AnyVal
315+
object PrivateWrapper {
316+
def Instance = new PrivateWrapper("")
317+
}
245318

246319

247320
trait A

0 commit comments

Comments
 (0)