From 98e2f26000aaaf5abb527f776426c4759b95cde8 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 21 Aug 2013 23:29:11 +0200 Subject: Use @uncheckedBounds to avoid introducing refchecks errors ... in code that would otherwise have smuggled through these slack LUBs in the types of trees but never in a TypeTree. More details in SI-7694. Fixes #29 --- src/main/scala/scala/async/internal/AnfTransform.scala | 6 +++--- src/main/scala/scala/async/internal/AsyncId.scala | 2 +- src/main/scala/scala/async/internal/AsyncTransform.scala | 11 ++++++++--- src/main/scala/scala/async/internal/ExprBuilder.scala | 8 ++++---- src/main/scala/scala/async/internal/TransformUtils.scala | 13 ++++++++++++- 5 files changed, 28 insertions(+), 12 deletions(-) (limited to 'src/main') diff --git a/src/main/scala/scala/async/internal/AnfTransform.scala b/src/main/scala/scala/async/internal/AnfTransform.scala index 6aeaba3..0f8bc67 100644 --- a/src/main/scala/scala/async/internal/AnfTransform.scala +++ b/src/main/scala/scala/async/internal/AnfTransform.scala @@ -119,8 +119,8 @@ private[async] trait AnfTransform { } private def defineVar(prefix: String, tp: Type, pos: Position): ValDef = { - val sym = currOwner.newTermSymbol(name.fresh(prefix), pos, MUTABLE | SYNTHETIC).setInfo(tp) - ValDef(sym, gen.mkZero(tp)).setType(NoType).setPos(pos) + val sym = currOwner.newTermSymbol(name.fresh(prefix), pos, MUTABLE | SYNTHETIC).setInfo(uncheckedBounds(tp)) + ValDef(sym, gen.mkZero(uncheckedBounds(tp))).setType(NoType).setPos(pos) } } @@ -145,7 +145,7 @@ private[async] trait AnfTransform { } private def defineVal(prefix: String, lhs: Tree, pos: Position): ValDef = { - val sym = currOwner.newTermSymbol(name.fresh(prefix), pos, SYNTHETIC).setInfo(lhs.tpe) + val sym = currOwner.newTermSymbol(name.fresh(prefix), pos, SYNTHETIC).setInfo(uncheckedBounds(lhs.tpe)) changeOwner(lhs, currentOwner, sym) ValDef(sym, changeOwner(lhs, currentOwner, sym)).setType(NoType).setPos(pos) } diff --git a/src/main/scala/scala/async/internal/AsyncId.scala b/src/main/scala/scala/async/internal/AsyncId.scala index 4334088..b9d82e2 100644 --- a/src/main/scala/scala/async/internal/AsyncId.scala +++ b/src/main/scala/scala/async/internal/AsyncId.scala @@ -41,7 +41,7 @@ object IdentityFutureSystem extends FutureSystem { def execContextType: Type = weakTypeOf[Unit] def createProm[A: WeakTypeTag]: Expr[Prom[A]] = reify { - new Prom() + new Prom[A]() } def promiseToFuture[A: WeakTypeTag](prom: Expr[Prom[A]]) = reify { diff --git a/src/main/scala/scala/async/internal/AsyncTransform.scala b/src/main/scala/scala/async/internal/AsyncTransform.scala index c755c87..78a0876 100644 --- a/src/main/scala/scala/async/internal/AsyncTransform.scala +++ b/src/main/scala/scala/async/internal/AsyncTransform.scala @@ -6,7 +6,12 @@ trait AsyncTransform { import global._ def asyncTransform[T](body: Tree, execContext: Tree, cpsFallbackEnabled: Boolean) - (implicit resultType: WeakTypeTag[T]): Tree = { + (resultType: WeakTypeTag[T]): Tree = { + + // We annotate the type of the whole expression as `T @uncheckedBounds` so as not to introduce + // warnings about non-conformant LUBs. See SI-7694 + // This implicit propatages the annotated type in the type tag. + implicit val uncheckedBoundsResultTag: WeakTypeTag[T] = WeakTypeTag[T](rootMirror, FixedMirrorTypeCreator(rootMirror, uncheckedBounds(resultType.tpe))) reportUnsupportedAwaits(body, report = !cpsFallbackEnabled) @@ -22,12 +27,12 @@ trait AsyncTransform { DefDef(NoMods, name.apply, Nil, applyVParamss, TypeTree(definitions.UnitTpe), Literal(Constant(()))) } - val stateMachineType = applied("scala.async.StateMachine", List(futureSystemOps.promType[T], futureSystemOps.execContextType)) + val stateMachineType = applied("scala.async.StateMachine", List(futureSystemOps.promType[T](uncheckedBoundsResultTag), futureSystemOps.execContextType)) val stateMachine: ClassDef = { val body: List[Tree] = { val stateVar = ValDef(Modifiers(Flag.MUTABLE | Flag.PRIVATE | Flag.LOCAL), name.state, TypeTree(definitions.IntTpe), Literal(Constant(0))) - val result = ValDef(NoMods, name.result, TypeTree(futureSystemOps.promType[T]), futureSystemOps.createProm[T].tree) + val result = ValDef(NoMods, name.result, TypeTree(futureSystemOps.promType[T](uncheckedBoundsResultTag)), futureSystemOps.createProm[T](uncheckedBoundsResultTag).tree) val execContextValDef = ValDef(NoMods, name.execContext, TypeTree(), execContext) val apply0DefDef: DefDef = { diff --git a/src/main/scala/scala/async/internal/ExprBuilder.scala b/src/main/scala/scala/async/internal/ExprBuilder.scala index e0da874..f43d1cb 100644 --- a/src/main/scala/scala/async/internal/ExprBuilder.scala +++ b/src/main/scala/scala/async/internal/ExprBuilder.scala @@ -284,7 +284,7 @@ trait ExprBuilder { def onCompleteHandler[T: WeakTypeTag]: Tree - def resumeFunTree[T]: DefDef + def resumeFunTree[T: WeakTypeTag]: DefDef } case class SymLookup(stateMachineClass: Symbol, applyTrParam: Symbol) { @@ -303,12 +303,12 @@ trait ExprBuilder { new AsyncBlock { def asyncStates = blockBuilder.asyncStates.toList - def mkCombinedHandlerCases[T]: List[CaseDef] = { + def mkCombinedHandlerCases[T: WeakTypeTag]: List[CaseDef] = { val caseForLastState: CaseDef = { val lastState = asyncStates.last val lastStateBody = Expr[T](lastState.body) val rhs = futureSystemOps.completeProm( - Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), reify(scala.util.Success(lastStateBody.splice))) + Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), reify(scala.util.Success[T](lastStateBody.splice))) mkHandlerCase(lastState.state, rhs.tree) } asyncStates.toList match { @@ -337,7 +337,7 @@ trait ExprBuilder { * } * } */ - def resumeFunTree[T]: DefDef = + def resumeFunTree[T: WeakTypeTag]: DefDef = DefDef(Modifiers(), name.resume, Nil, List(Nil), Ident(definitions.UnitClass), Try( Match(symLookup.memberRef(name.state), mkCombinedHandlerCases[T]), diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala index 70237bc..663ca45 100644 --- a/src/main/scala/scala/async/internal/TransformUtils.scala +++ b/src/main/scala/scala/async/internal/TransformUtils.scala @@ -244,8 +244,19 @@ private[async] trait TransformUtils { // Attributed version of `TreeGen#mkCastPreservingAnnotations` def mkAttributedCastPreservingAnnotations(tree: Tree, tp: Type): Tree = { atPos(tree.pos) { - val casted = gen.mkAttributedCast(tree, tp.withoutAnnotations.dealias) + val casted = gen.mkAttributedCast(tree, uncheckedBounds(tp.withoutAnnotations).dealias) Typed(casted, TypeTree(tp)).setType(tp) } } + + // ===================================== + // Copy/Pasted from Scala 2.10.3. See SI-7694. + private lazy val UncheckedBoundsClass = { + global.rootMirror.getClassIfDefined("scala.reflect.internal.annotations.uncheckedBounds") + } + final def uncheckedBounds(tp: Type): Type = { + if (tp.typeArgs.isEmpty || UncheckedBoundsClass == NoSymbol) tp + else tp.withAnnotation(AnnotationInfo marker UncheckedBoundsClass.tpe) + } + // ===================================== } -- cgit v1.2.3