Skip to content

migrates to 2.11.0-RC1 #61

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3f0b47c
toolboxClasspath now works for snapshots
xeno-by Feb 12, 2014
a4c3b41
silences a warning in AsyncAnalysis
xeno-by Feb 12, 2014
4a35394
migrates to 2.11.0-RC1
xeno-by Feb 15, 2014
38a85e7
using compat._ to plug source compatibility breakages
xeno-by Feb 15, 2014
2216c68
removes logic that branches on forInteractive
xeno-by Feb 14, 2014
125b300
compat => internal
xeno-by Feb 14, 2014
1b76f83
injects context into AsyncBase
xeno-by Feb 14, 2014
4bfe12d
abort => c.abort
xeno-by Feb 14, 2014
42544e7
currentUnit.freshName => c.freshName (leads to less precise tests...)
xeno-by Feb 14, 2014
aeb95bc
removes "import global._" and "def Expr" in TransformUtils
xeno-by Feb 14, 2014
2f4b6a0
eliminates all usages of global in TransformUtils
xeno-by Feb 14, 2014
2b2a0fc
cleans up LiveVariables
xeno-by Feb 14, 2014
46621c4
cleans up Lifter
xeno-by Feb 14, 2014
b792b50
cleans up FutureSystem
xeno-by Feb 14, 2014
dca99c9
cleans up ExprBuilder
xeno-by Feb 14, 2014
84b9a42
cleans up AsyncTransform
xeno-by Feb 14, 2014
393e101
cleans up AsyncAnalysis
xeno-by Feb 14, 2014
fd98325
cleans up AnfTransform
xeno-by Feb 14, 2014
defca0c
gets rid of home-grown changeOwner
xeno-by Feb 14, 2014
a14d758
replaces mkAttributedCast
xeno-by Feb 14, 2014
69f3a4d
migrates transformAt to typingTransform
xeno-by Feb 14, 2014
76c9839
migrates UseFields to typingTransform
xeno-by Feb 14, 2014
18bea76
oh God, in-place typechecking!!!
xeno-by Feb 14, 2014
7e72ef0
migrates SelectiveAnfTransform to typingTransform
xeno-by Feb 14, 2014
cc47ec1
callSiteTyper and TypingTransformers are gone
xeno-by Feb 14, 2014
ac7ba71
AsyncMacro.macroApplication is gone
xeno-by Feb 14, 2014
bc51a19
AsyncMacro.global is gone
xeno-by Feb 15, 2014
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
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
scalaVersion := "2.10.3"
scalaVersion := "2.11.0-RC1"

// Uncomment to test with a locally built copy of Scala.
// scalaHome := Some(file("/code/scala2/build/pack"))
Expand Down
470 changes: 233 additions & 237 deletions src/main/scala/scala/async/internal/AnfTransform.scala

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions src/main/scala/scala/async/internal/AsyncAnalysis.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import scala.collection.mutable
trait AsyncAnalysis {
self: AsyncMacro =>

import global._
import c.universe._

/**
* Analyze the contents of an `async` block in order to:
Expand All @@ -21,14 +21,14 @@ trait AsyncAnalysis {
def reportUnsupportedAwaits(tree: Tree): Unit = {
val analyzer = new UnsupportedAwaitAnalyzer
analyzer.traverse(tree)
analyzer.hasUnsupportedAwaits
// analyzer.hasUnsupportedAwaits // XB: not used?!
}

private class UnsupportedAwaitAnalyzer extends AsyncTraverser {
var hasUnsupportedAwaits = false

override def nestedClass(classDef: ClassDef) {
val kind = if (classDef.symbol.isTrait) "trait" else "class"
val kind = if (classDef.symbol.asClass.isTrait) "trait" else "class"
reportUnsupportedAwait(classDef, s"nested ${kind}")
}

Expand Down Expand Up @@ -59,10 +59,10 @@ trait AsyncAnalysis {
reportUnsupportedAwait(tree, "try/catch")
super.traverse(tree)
case Return(_) =>
abort(tree.pos, "return is illegal within a async block")
c.abort(tree.pos, "return is illegal within a async block")
case ValDef(mods, _, _, _) if mods.hasFlag(Flag.LAZY) =>
// TODO lift this restriction
abort(tree.pos, "lazy vals are illegal within an async block")
c.abort(tree.pos, "lazy vals are illegal within an async block")
case CaseDef(_, guard, _) if guard exists isAwait =>
// TODO lift this restriction
reportUnsupportedAwait(tree, "pattern guard")
Expand All @@ -87,7 +87,7 @@ trait AsyncAnalysis {

private def reportError(pos: Position, msg: String) {
hasUnsupportedAwaits = true
abort(pos, msg)
c.abort(pos, msg)
}
}
}
28 changes: 8 additions & 20 deletions src/main/scala/scala/async/internal/AsyncBase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,34 +42,22 @@ abstract class AsyncBase {
def asyncImpl[T: c.WeakTypeTag](c: Context)
(body: c.Expr[T])
(execContext: c.Expr[futureSystem.ExecContext]): c.Expr[futureSystem.Fut[T]] = {
import c.universe._
import c.universe._, c.internal._, decorators._
val asyncMacro = AsyncMacro(c, self)

val isPresentationCompiler = asyncMacro.global.forInteractive

val code = asyncMacro.asyncTransform[T](
body.tree.asInstanceOf[asyncMacro.global.Tree],
execContext.tree.asInstanceOf[asyncMacro.global.Tree]
)(implicitly[c.WeakTypeTag[T]].asInstanceOf[asyncMacro.global.WeakTypeTag[T]]).asInstanceOf[Tree]

val code = asyncMacro.asyncTransform[T](body.tree, execContext.tree)(c.weakTypeTag[T])
AsyncUtils.vprintln(s"async state machine transform expands to:\n ${code}")
val result = if (isPresentationCompiler) {
asyncMacro.suppressExpansion()
c.macroApplication
} else {
// Mark range positions for synthetic code as transparent to allow some wiggle room for overlapping ranges
for (t <- code)
t.pos = t.pos.makeTransparent
code
}
c.Expr[futureSystem.Fut[T]](result)

// Mark range positions for synthetic code as transparent to allow some wiggle room for overlapping ranges
for (t <- code) t.setPos(t.pos.makeTransparent)
c.Expr[futureSystem.Fut[T]](code)
}

protected[async] def awaitMethod(u: Universe)(asyncMacroSymbol: u.Symbol): u.Symbol = {
import u._
asyncMacroSymbol.owner.typeSignature.member(newTermName("await"))
}
}

protected[async] def nullOut(u: Universe)(name: u.Expr[String], v: u.Expr[Any]): u.Expr[Unit] =
u.reify { () }
}
14 changes: 6 additions & 8 deletions src/main/scala/scala/async/internal/AsyncId.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package scala.async.internal
import language.experimental.macros
import scala.reflect.macros.Context
import scala.reflect.api.Universe
import scala.reflect.internal.SymbolTable

object AsyncId extends AsyncBase {
lazy val futureSystem = IdentityFutureSystem
Expand Down Expand Up @@ -52,12 +51,11 @@ object IdentityFutureSystem extends FutureSystem {
type ExecContext = Unit
type Tryy[A] = scala.util.Try[A]

def mkOps(c: SymbolTable): Ops {val universe: c.type} = new Ops {
val universe: c.type = c
def mkOps(c0: Context): Ops {val c: c0.type} = new Ops {
val c: c0.type = c0
import c.universe._

import universe._

def execContext: Expr[ExecContext] = Expr[Unit](Literal(Constant(())))
def execContext: Expr[ExecContext] = c.Expr[Unit](Literal(Constant(())))

def promType[A: WeakTypeTag]: Type = weakTypeOf[Prom[A]]
def tryType[A: WeakTypeTag]: Type = weakTypeOf[scala.util.Try[A]]
Expand All @@ -76,12 +74,12 @@ object IdentityFutureSystem extends FutureSystem {
def onComplete[A, U](future: Expr[Fut[A]], fun: Expr[Tryy[A] => U],
execContext: Expr[ExecContext]): Expr[Unit] = reify {
fun.splice.apply(util.Success(future.splice))
Expr[Unit](Literal(Constant(()))).splice
c.Expr[Unit](Literal(Constant(()))).splice
}

def completeProm[A](prom: Expr[Prom[A]], value: Expr[Tryy[A]]): Expr[Unit] = reify {
prom.splice.a = value.splice.get
Expr[Unit](Literal(Constant(()))).splice
c.Expr[Unit](Literal(Constant(()))).splice
}

def tryyIsFailure[A](tryy: Expr[Tryy[A]]): Expr[Boolean] = reify {
Expand Down
46 changes: 10 additions & 36 deletions src/main/scala/scala/async/internal/AsyncMacro.scala
Original file line number Diff line number Diff line change
@@ -1,51 +1,25 @@
package scala.async.internal

import scala.tools.nsc.Global
import scala.tools.nsc.transform.TypingTransformers

object AsyncMacro {
def apply(c: reflect.macros.Context, base: AsyncBase): AsyncMacro = {
def apply(c0: reflect.macros.Context, base: AsyncBase): AsyncMacro { val c: c0.type } = {
import language.reflectiveCalls
val powerContext = c.asInstanceOf[c.type { val universe: Global; val callsiteTyper: universe.analyzer.Typer }]
new AsyncMacro {
val global: powerContext.universe.type = powerContext.universe
val callSiteTyper: global.analyzer.Typer = powerContext.callsiteTyper
val macroApplication: global.Tree = c.macroApplication.asInstanceOf[global.Tree]
new AsyncMacro { self =>
val c: c0.type = c0
// This member is required by `AsyncTransform`:
val asyncBase: AsyncBase = base
val asyncBase: AsyncBase = base
// These members are required by `ExprBuilder`:
val futureSystem: FutureSystem = base.futureSystem
val futureSystemOps: futureSystem.Ops {val universe: global.type} = futureSystem.mkOps(global)
val futureSystem: FutureSystem = base.futureSystem
val futureSystemOps: futureSystem.Ops {val c: self.c.type} = futureSystem.mkOps(c)
}
}
}

private[async] trait AsyncMacro
extends TypingTransformers
with AnfTransform with TransformUtils with Lifter
extends AnfTransform with TransformUtils with Lifter
with ExprBuilder with AsyncTransform with AsyncAnalysis with LiveVariables {

val global: Global
val callSiteTyper: global.analyzer.Typer
val macroApplication: global.Tree

lazy val macroPos = macroApplication.pos.makeTransparent
def atMacroPos(t: global.Tree) = global.atPos(macroPos)(t)

def suppressExpansion() {
// Have your cake : Scala IDE sees original trees and hyperlinking, etc within async blocks "Just Works"
// Eat it too : (domain specific errors like "unsupported use of await"
//
// TODO remove this once we unsupport 2.10.x, scalac 2.11 does this automatically.

import global.Tree
type Suppress = { def suppressMacroExpansion(a: Tree): Tree }
try {
global.asInstanceOf[Suppress].suppressMacroExpansion(macroApplication)
} catch {
case _: NoSuchMethodException =>
global.analyzer.asInstanceOf[Suppress].suppressMacroExpansion(macroApplication)
}
}
val c: scala.reflect.macros.Context

lazy val macroPos = c.macroApplication.pos.makeTransparent
def atMacroPos(t: c.Tree) = c.universe.atPos(macroPos)(t)
}
89 changes: 41 additions & 48 deletions src/main/scala/scala/async/internal/AsyncTransform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package scala.async.internal
trait AsyncTransform {
self: AsyncMacro =>

import global._
import c.universe._
import c.internal._
import decorators._

val asyncBase: AsyncBase

Expand All @@ -13,7 +15,7 @@ trait AsyncTransform {
// 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 propagates the annotated type in the type tag.
implicit val uncheckedBoundsResultTag: WeakTypeTag[T] = WeakTypeTag[T](rootMirror, FixedMirrorTypeCreator(rootMirror, uncheckedBounds(resultType.tpe)))
implicit val uncheckedBoundsResultTag: WeakTypeTag[T] = c.WeakTypeTag[T](uncheckedBounds(resultType.tpe))

reportUnsupportedAwaits(body)

Expand Down Expand Up @@ -55,7 +57,7 @@ trait AsyncTransform {
val template = Template(List(tryToUnit, typeOf[() => Unit]).map(TypeTree(_)), emptyValDef, body)

val t = ClassDef(NoMods, name.stateMachineT, Nil, template)
callSiteTyper.typedPos(macroPos)(Block(t :: Nil, Literal(Constant(()))))
typingTransform(atPos(macroPos)(Block(t :: Nil, Literal(Constant(())))))((tree, api) => api.typecheck(tree))
t
}

Expand All @@ -78,9 +80,9 @@ trait AsyncTransform {
val fieldSym = fld.symbol
Block(
List(
asyncBase.nullOut(global)(Expr[String](Literal(Constant(fieldSym.name.toString))), Expr[Any](Ident(fieldSym))).tree
asyncBase.nullOut(c.universe)(c.Expr[String](Literal(Constant(fieldSym.name.toString))), c.Expr[Any](Ident(fieldSym))).tree
),
Assign(gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym), gen.mkZero(fieldSym.info))
Assign(gen.mkAttributedStableRef(thisType(fieldSym.owner), fieldSym), gen.mkZero(fieldSym.info))
)
}
val asyncState = asyncBlock.asyncStates.find(_.state == state).get
Expand All @@ -102,7 +104,7 @@ trait AsyncTransform {
ValDef(NoMods, name.stateMachine, TypeTree(), Apply(Select(New(Ident(stateMachine.symbol)), nme.CONSTRUCTOR), Nil)),
futureSystemOps.spawn(Apply(selectStateMachine(name.apply), Nil), selectStateMachine(name.execContext))
),
futureSystemOps.promiseToFuture(Expr[futureSystem.Prom[T]](selectStateMachine(name.result))).tree)
futureSystemOps.promiseToFuture(c.Expr[futureSystem.Prom[T]](selectStateMachine(name.result))).tree)
}

val isSimple = asyncBlock.asyncStates.size == 1
Expand All @@ -121,7 +123,7 @@ trait AsyncTransform {
}

AsyncUtils.vprintln(s"In file '$location':")
AsyncUtils.vprintln(s"${macroApplication}")
AsyncUtils.vprintln(s"${c.macroApplication}")
AsyncUtils.vprintln(s"ANF transform expands to:\n $anfTree")
states foreach (s => AsyncUtils.vprintln(s))
}
Expand All @@ -141,79 +143,70 @@ trait AsyncTransform {
liftedSyms.foreach {
sym =>
if (sym != null) {
sym.owner = stateMachineClass
sym.setOwner(stateMachineClass)
if (sym.isModule)
sym.moduleClass.owner = stateMachineClass
sym.asModule.moduleClass.setOwner(stateMachineClass)
}
}
// Replace the ValDefs in the splicee with Assigns to the corresponding lifted
// fields. Similarly, replace references to them with references to the field.
//
// This transform will only be run on the RHS of `def foo`.
class UseFields extends MacroTypingTransformer {
override def transform(tree: Tree): Tree = tree match {
case _ if currentOwner == stateMachineClass =>
super.transform(tree)
case ValDef(_, _, _, rhs) if liftedSyms(tree.symbol) =>
atOwner(currentOwner) {
val fieldSym = tree.symbol
val set = Assign(gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym), transform(rhs))
changeOwner(set, tree.symbol, currentOwner)
localTyper.typedPos(tree.pos)(set)
}
case _: DefTree if liftedSyms(tree.symbol) =>
EmptyTree
case Ident(name) if liftedSyms(tree.symbol) =>
val useFields: (Tree, TypingTransformApi) => Tree = (tree, api) => tree match {
case _ if api.currentOwner == stateMachineClass =>
api.default(tree)
case ValDef(_, _, _, rhs) if liftedSyms(tree.symbol) =>
api.atOwner(api.currentOwner) {
val fieldSym = tree.symbol
atPos(tree.pos) {
gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym).setType(tree.tpe)
}
case _ =>
super.transform(tree)
}
val set = Assign(gen.mkAttributedStableRef(thisType(fieldSym.owner.asClass), fieldSym), api.recur(rhs))
set.changeOwner(tree.symbol, api.currentOwner)
api.typecheck(atPos(tree.pos)(set))
}
case _: DefTree if liftedSyms(tree.symbol) =>
EmptyTree
case Ident(name) if liftedSyms(tree.symbol) =>
val fieldSym = tree.symbol
atPos(tree.pos) {
gen.mkAttributedStableRef(thisType(fieldSym.owner.asClass), fieldSym).setType(tree.tpe)
}
case _ =>
api.default(tree)
}

val liftablesUseFields = liftables.map {
case vd: ValDef => vd
case x =>
val useField = new UseFields()
//.substituteSymbols(fromSyms, toSyms)
useField.atOwner(stateMachineClass)(useField.transform(x))
case x => typingTransform(x, stateMachineClass)(useFields)
}

tree.children.foreach {
t =>
new ChangeOwnerAndModuleClassTraverser(callSiteTyper.context.owner, tree.symbol).traverse(t)
}
tree.children.foreach(_.changeOwner(enclosingOwner, tree.symbol))
val treeSubst = tree

/* Fixes up DefDef: use lifted fields in `body` */
def fixup(dd: DefDef, body: Tree, ctx: analyzer.Context): Tree = {
def fixup(dd: DefDef, body: Tree, api: TypingTransformApi): Tree = {
val spliceeAnfFixedOwnerSyms = body
val useField = new UseFields()
val newRhs = useField.atOwner(dd.symbol)(useField.transform(spliceeAnfFixedOwnerSyms))
val typer = global.analyzer.newTyper(ctx.make(dd, dd.symbol))
treeCopy.DefDef(dd, dd.mods, dd.name, dd.tparams, dd.vparamss, dd.tpt, typer.typed(newRhs))
val newRhs = typingTransform(spliceeAnfFixedOwnerSyms, dd.symbol)(useFields)
val newRhsTyped = api.atOwner(dd, dd.symbol)(api.typecheck(newRhs))
treeCopy.DefDef(dd, dd.mods, dd.name, dd.tparams, dd.vparamss, dd.tpt, newRhsTyped)
}

liftablesUseFields.foreach(t => if (t.symbol != null) stateMachineClass.info.decls.enter(t.symbol))

val result0 = transformAt(treeSubst) {
case t@Template(parents, self, stats) =>
(ctx: analyzer.Context) => {
(api: TypingTransformApi) => {
treeCopy.Template(t, parents, self, liftablesUseFields ++ stats)
}
}
val result = transformAt(result0) {
case dd@DefDef(_, name.apply, _, List(List(_)), _, _) if dd.symbol.owner == stateMachineClass =>
(ctx: analyzer.Context) =>
val typedTree = fixup(dd, changeOwner(applyBody, callSiteTyper.context.owner, dd.symbol), ctx)
(api: TypingTransformApi) =>
val typedTree = fixup(dd, applyBody.changeOwner(enclosingOwner, dd.symbol), api)
typedTree

case dd@DefDef(_, name.resume, _, _, _, _) if dd.symbol.owner == stateMachineClass =>
(ctx: analyzer.Context) =>
val changed = changeOwner(resumeBody, callSiteTyper.context.owner, dd.symbol)
val res = fixup(dd, changed, ctx)
(api: TypingTransformApi) =>
val changed = resumeBody.changeOwner(enclosingOwner, dd.symbol)
val res = fixup(dd, changed, api)
res
}
result
Expand Down
Loading