aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2014-07-01 16:45:33 -0400
committerJason Zaugg <jzaugg@gmail.com>2014-07-18 16:03:02 +0200
commit1df849070694756533003c9c331cd04d0c3136e8 (patch)
tree7b42b9eded651b47739d5bb62ef4f8268cb058f3 /src/main
parentf77d11962a3bf73c813a42a05e842ce710588c3f (diff)
downloadscala-async-1df849070694756533003c9c331cd04d0c3136e8.tar.gz
scala-async-1df849070694756533003c9c331cd04d0c3136e8.tar.bz2
scala-async-1df849070694756533003c9c331cd04d0c3136e8.zip
Fix regression around type skolems and if exprs.
If we start with: async({ val res = await[S[_$1 with String]](s); if (true) await[Int](0) res }) Typechecking the application (before macro expansion) yields (where the trees are printed in the form `expr{tpe}`): async[S[_$1#5738 with String#137]]({ val res: S[_$1#5490 with String] forSome { type _$1#5490 } = await[S[_$1#5487 with String]]( s{S[_$1#5487 with String]} ){S[_$1#5487 with String]}; if (true) await(0) else () res{S[_$1#5738 with String]} }{S[_$1#5738 with String]}){S[_$1#5738 with String]} Note that the type of the second last line contains a skolemized symbol `_$1#5738` of the existential `_$1#5490`. This is created by this case in `Typer#adapt`: case et @ ExistentialType(_, _) if ((mode & (EXPRmode | LHSmode)) == EXPRmode) => adapt(tree setType et.skolemizeExistential(context.owner, tree), mode, pt, original) Our ANF rewrites part of this code to: <synthetic> val await$1: S[_$1#5487 with String] = await[S[_$1#5487 with String]](awaitable$1); val res: S[_$1#5490 with String] forSome { type _$1 } = await$1; And later, the state machine transformation splits the last line into a blank field and an assignment. Typechecking the `Assign` node led to the an type error. This commit manually attributes the types to the `Assign` node so as to avoid these problem. It also reigns in an overeager rewriting of `If` nodes in the ANF transform, which was due to a bug in the label detection logic introduced in 4fc5463538. Thanks to @gnovark for yet another devilish test case and analysis of the problem with label detection. I worked on a more principled fix on: https://github.com/retronym/async/compare/ticket/79-2?expand=1 in which I try to use `repackExistential` to convert skolemized types to existentials for use as the types of synthetic vals introduced by the ANF transform. This ran into a deeper problem with existential subtyping in the compiler itself though.
Diffstat (limited to 'src/main')
-rw-r--r--src/main/scala/scala/async/internal/AsyncTransform.scala9
-rw-r--r--src/main/scala/scala/async/internal/TransformUtils.scala2
2 files changed, 7 insertions, 4 deletions
diff --git a/src/main/scala/scala/async/internal/AsyncTransform.scala b/src/main/scala/scala/async/internal/AsyncTransform.scala
index c8d2234..a24a823 100644
--- a/src/main/scala/scala/async/internal/AsyncTransform.scala
+++ b/src/main/scala/scala/async/internal/AsyncTransform.scala
@@ -156,9 +156,12 @@ trait AsyncTransform {
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)
+ val lhs = atPos(tree.pos) {
+ gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym)
+ }
+ val assign = treeCopy.Assign(tree, lhs, transform(rhs)).setType(definitions.UnitTpe)
+ changeOwner(assign, tree.symbol, currentOwner)
+ assign
}
case _: DefTree if liftedSyms(tree.symbol) =>
EmptyTree
diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala
index f228e1d..bef52f1 100644
--- a/src/main/scala/scala/async/internal/TransformUtils.scala
+++ b/src/main/scala/scala/async/internal/TransformUtils.scala
@@ -100,7 +100,7 @@ private[async] trait TransformUtils {
case ld: LabelDef => ld.symbol
}.toSet
t.exists {
- case rt: RefTree => !(labelDefs contains rt.symbol)
+ case rt: RefTree => rt.symbol != null && rt.symbol.isLabel && !(labelDefs contains rt.symbol)
case _ => false
}
}