| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
| |
This commit disabled live variable analysis for intermediate values of type Nothing.
Fixes #104
|
|
|
|
|
|
|
| |
We were leaking untyped trees out of the macro, which crashed
in refchecks.
This commit proactively typechecks the tree returned by `mkZero`.
|
|\
| |
| |
| |
| |
| |
| |
| |
| | |
merge/2.10.x-to-master-20141219
Conflicts:
src/main/scala/scala/async/internal/AsyncTransform.scala
src/main/scala/scala/async/internal/ExprBuilder.scala
src/test/scala/scala/async/TreeInterrogation.scala
|
| |
| |
| |
| |
| |
| | |
A worthy optimization, suggested by @danarmak.
Closes #73
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Previously, as sequence of state transitions that did not pass through
an asynchrous boundary incurred stack frames. The trivial loop in
the enclosed test case would then overflow the stack.
This commit merges the `resume` and `apply(tr: Try[Any])` methods into
a `apply`. It changes the body of this method to be an infinite loop
with returns at the terminal points in the state machine (or at a
terminal failure.)
To allow merging of these previously separate matches, states that
contain an await are now allocated two state ids: one for the setup
code that calls `onComplete`, and one for the code in the continuation
that records the result and advances the state machine.
Fixes #93
|
| |
| |
| |
| | |
E.g. type param, abstrat type.
|
| | |
|
|\|
| |
| |
| |
| |
| |
| | |
Conflicts:
src/main/scala/scala/async/internal/AnfTransform.scala
src/main/scala/scala/async/internal/AsyncTransform.scala
src/test/scala/scala/async/run/toughtype/ToughType.scala
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
`TreeGen#mkZero` returns `q"null"` for derived value classes.
```
scala> class V(val a: String) extends AnyVal
defined class V
scala> showRaw(gen.mkZero(typeOf[V]))
res0: String = Literal(Constant(null))
```
We use this API in async to generate the initial value for
ANF-lifted temporary variables.
However, this leads to NPEs, as after posterasure, we call the
unbox method on a null reference:
```
% cat sandbox/Macro.scala; scalac-hash v2.10.4 sandbox/Macro.scala; scala-hash v2.10.4 -e 'val x = Macros.myMacro'
import scala.reflect.macros.Context
import scala.language.experimental.macros
object Macros {
def macroImpl(c: Context): c.Expr[C] = {
import c.universe._
val e1 = c.Expr[C](Literal(Constant(null)).setType(typeOf[C]))
reify(e1.splice.asInstanceOf[C @annotation.unchecked.uncheckedVariance])
}
def myMacro: C = macro macroImpl
}
class C(val a: String) extends AnyVal
java.lang.NullPointerException
at Main$$anon$1.<init>(scalacmd4059893593754060829.scala:1)
at Main$.main(scalacmd4059893593754060829.scala:1)
at Main.main(scalacmd4059893593754060829.scala)
```
This commit installs a custom version of `mkZero` that instead
returns `q"new C[$..targs](${mkZero(wrappedType)})`.
Thanks to @ewiner for pinpointing the problem.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
This progressed along with the fix for #66.
`TreeGen.mkZero` is a bit of a minefield: first with `Nothing` and
now with Value Classes. I wonder if we can provoke the same sort of
bug in the compiler in places where this is used.
Closes #83
|
|\|
| |
| |
| |
| |
| |
| |
| | |
merge/2.10.x-to-master-20140721
Conflicts:
src/main/scala/scala/async/internal/AsyncTransform.scala
src/main/scala/scala/async/internal/Lifter.scala
|
| |\
| | |
| | | |
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.
|
| |\ \
| | | |
| | | | |
Fix asymptotic performance issues in live variables analysis.
|
| | |/
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
Fix possibly-exponential runtime for DFS graph searches.
Improve DFA fixpoint algorithm to correctly compute worklist
of only changed nodes for each iteration.
Added test that takes > 2 minutes to compile without these
improvements.
|
| |/
| |
| |
| |
| |
| |
| | |
`gen.mkZero(NothingTpe)` gives the tree `Predef.???`. Instead, we should leave
the `await` field uninitialized with `ValDef(..., rhs = EmptyTree)`.
Fixes #66
|
| |
| |
| |
| |
| |
| |
| |
| |
| | |
- remove unneeded `setType(NoType)`, which was leftover from my
first attempts to find this bug.
- fix typo in error message
- optimize imports
(cherry picked from commit 5c6ea29966fa80faae13892da50fc68ed1bf9ae7)
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
We were incorrectly typechecking the `ClassDef` of the state machine
in the macro in a way that discarded the resulting trees, and only
kept around the symbol.
The led to the the macro engine retypechecking
that node, which somehow led to duplicated lazy val initiaializer
`DefDef`-s in the template, which manifest as a `VerifyError`.
This commit:
- rescues the typechecked `ClassDef` node from the eager
typechecking by the macro
- loosens the restriction on lazy vals in async blocks. They are
still prohibited if they contain an await on the RHS
- Adds a test that shows evalution is indeed lazy.
(cherry picked from commit cc4587b1985519f7049d0feb0783d8e22c10f792)
Conflicts:
src/main/scala/scala/async/internal/AsyncAnalysis.scala
src/main/scala/scala/async/internal/AsyncTransform.scala
|
| |
| |
| |
| |
| |
| | |
Works on the 2.10.x branch, so just backprting the test.
Cherry picked from 6f6546ebfc26564843621e79d840209a5103d3c8.
|
| | |
|
| |
| |
| |
| |
| |
| |
| | |
- remove unneeded `setType(NoType)`, which was leftover from my
first attempts to find this bug.
- fix typo in error message
- optimize imports
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
We were incorrectly typechecking the `ClassDef` of the state machine
in the macro in a way that discarded the resulting trees, and only
kept around the symbol.
The led to the the macro engine retypechecking
that node, which somehow led to duplicated lazy val initiaializer
`DefDef`-s in the template, which manifest as a `VerifyError`.
This commit:
- rescues the typechecked `ClassDef` node from the eager
typechecking by the macro
- loosens the restriction on lazy vals in async blocks. They are
still prohibited if they contain an await on the RHS
- Adds a test that shows evalution is indeed lazy.
Fixes #52
|
| |
| |
| |
| |
| |
| | |
Predicate the `asClass` cast with an `isClass` check.
Fixes #63
|
| | |
|
|/ |
|
|
|
|
| |
2013 must have been unlucky.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The new tree shapes handled for do/while look like:
// type checked
async({
val b = false;
doWhile$1(){
await(());
if (b)
doWhile$1()
else
()
};
()
})
We had to change ExprBuilder to create states for the if/else
that concludes the doWhile body, and also loosen the assertion
that the label jump must be the last thing we see.
We also have to look for more than just `containsAwait` when
deciding whether an `If` needs to be transformed into states;
it might also contain a jump to the enclosing label that is on
the other side of an `await`, and hence needs to be a state
transition instead.
|
|
|
|
|
|
|
|
|
| |
These stem from the handling of the internal/external view
or method type parameters by `thisMethodType` in `Namers`.
I've now preseversed the orginal ValDefs favoured the latter
when constructing the new DefDef, and made construction of
all liftables consistent in this regard.
|
|
|
|
|
| |
Once they escape, we leave the references in the state
machines fields untouched.
|
|
|
|
|
|
|
|
|
|
| |
- Remove the CPS fallback version of async. That was not intended
to be part of 1.0.
- Lookup the await method beside the macro, rather than requiring
all calls to go to AsyncBase.await.
- Create a minimal version of Async that just contains await/async
and delegates to the macro implementation in internal._
- Add scaladoc.
|
|
|
|
|
|
| |
We were relying on an internal API that no longer exists.
We also need to tweak the way our tests infer scalaBinaryVersion.
|
|
|
|
|
| |
- Zero out fields of type Any
- Zero out fields of value class type
|
|
|
|
|
|
|
| |
- Adds a hook that lets a derived macro insert additional code
when zero-ing out a lifted field.
- Adds a variant of the `AsyncId` macro that logs zeroed-out fields.
- Adds a test using this mechanism
|
|
|
|
|
|
|
| |
Append a `()`, as we do for `Unit` returning `if`-s and `try-s`
We don't currently support `await` in try/catch, otherwise I'd
write tests for that case, too.
|
|\
| |
| | |
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
|
| |
| |
| |
| |
| | |
These are are at odds with the junit-interface SBT test framework
under SBT 0.13.+, and appear to be superfluous.
|
|/
|
|
|
|
| |
- removed outdated comments in ANF transform
- added a few comments
- removed some unnecessary imports
|
|
|
|
| |
Avoids runtime errors like: "java.lang.Double cannot be cast to scala.runtime.BoxedUnit"
|
| |
|
| |
|
|
|
|
| |
This case already works.
|
| |
|
|
|
|
|
| |
Also support AsyncId.async[Nothing], which was triggering a NPE
in the generated `null.asInstanceOf[Nothing]`.
|
|
|
|
|
| |
When convering If and Match nodes to ANF, set the type to Unit.
Otherwise, erasure might end up casting BoxedUnit to a real type.
|
|
|
|
|
| |
If we intend to keep CPS fallback around for any length of time
it should probably move there too.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
- Avoid reset + retypecheck, instead hang onto the original types/symbols
- Eliminated duplication between AsyncDefinitionUseAnalyzer and ExprBuilder
- Instead, decide what do lift *after* running ExprBuilder
- Account for transitive references local classes/objects and lift them
as needed.
- Make the execution context an regular implicit parameter of the macro
- Fixes interaction with existential skolems and singleton types
Fixes #6, #13, #16, #17, #19, #21.
|
|
|
|
| |
This allows us to cross build against 2.10.x and 2.11.x.
|