aboutsummaryrefslogtreecommitdiff
path: root/src
Commit message (Collapse)AuthorAgeFilesLines
* Merge pull request #133 from retronym/backport/1502.10.xJason Zaugg2015-07-306-24/+109
|\ | | | | Backport fix for #150 to 2.10.x
| * [backport] Make nsc.Global based tests work under SBTJason Zaugg2015-07-301-17/+3
| | | | | | | | | | | | And remove unused code. (cherry picked from commit 7238bc1982cb1d87157c650115a2ae92a58430c9)
| * [backport] Stop test compiler before code generationJason Zaugg2015-07-301-3/+3
| | | | | | | | | | | | | | This avoids leaving .class files in the working directory after running the test. (cherry picked from commit 5bb93b0b7357259eb588437a45063bf43595028a)
| * [backport] Avoid dead code warning with async(throw T)Jason Zaugg2015-07-303-2/+21
| | | | | | | | | | | | | | | | By declararing the parameter of `async` as by-name. Fixes #150 (the bug in the original ticket.) (cherry picked from commit 4b1dbeef9ec73612867afc5dd9c925faa8cbc30d)
| * [backport] Avoid dead code warnings in generated code.Jason Zaugg2015-07-303-4/+58
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If we blindly splicing `{..$stats, ..$generatedCode}`, and the last expression in `$stats` is of type `Nothing`, we'll incur a dead code warning when typechecking the block. This commit: - introduces a helper method to augment user-written stats with synthetic code - Emit a try/finally in that code (so we advance the state, even if we are about to exit the state machine in the async-block global exception handler - Hide `Nothing` typed expressions from the dead code analysis by wrapping them in an `expr: Any` Fixes #150 (the part reported in the comments, not the original ticket.)
| * [backport] Cleanup code generation by avoiding redundant blocksJason Zaugg2015-07-302-19/+45
| | | | | | | | | | | | | | | | | | Don't bother adding `{ ...; () }` if we can use the original tree(s) instead, e.g. if the last tree in `...` conforms to `Unit`. This makes the debug output of the macro a little easier to read. (cherry picked from commit de641dc265f34b06e17dfa7c64be00219f72b670)
* | Avoid masking user exception with ??? for Nothing typed expressionsJason Zaugg2015-07-273-2/+52
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Code like: val x = if (cond) throw new A else throw new B Was being transformed to: val ifRes = ??? if (cond) ifRes = throw new A else ifRes = throw new B val x = ifRes by way of the use of `gen.mkZero` which throws `???` if the requested type is `Nothing` This commit special cases `Nothing` typed expressions in a similar manner to `Unit` type expressions. The example above is now translated to: if (cond) throw new A else throw new B val x = throw new IllegalStateException() Fixes #120 (cherry picked from commit 80aaf18d5111322baee73dad30eb0a81cdd62314)
* | Avoid leaking untyped trees out of macroJason Zaugg2015-07-271-1/+1
|/ | | | | | | | | | | | The stack trace and bisection in #119 made me notice that we are failing to typecheck the cast we generated in the fix for #74. The ticket doesn't have a reproduction, so I'm submitting this without a test case. Fixes #119 (cherry picked from commit a037da192dbea32cffa8c5c8d33e7c56af0c353f)
* Merge pull request #115 from retronym/backport/74v0.9.4_2.10Jason Zaugg2015-07-072-1/+46
|\ | | | | Avoid compiler warning when awaiting Future[Unit]
| * Avoid compiler warning when awaiting Future[Unit]Jason Zaugg2015-07-072-1/+46
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 (cherry picked from commit f3f058991b207a07041672a7e119422d9054788d)
* | [backport] Avoid masking real errors with NotImplemented awaiting ↵Jason Zaugg2015-07-062-1/+27
| | | | | | | | | | | | | | | | | | | | Future[Nothing] This commit disabled live variable analysis for intermediate values of type Nothing. Fixes #104 (cherry picked from commit 6353443a0adec384172c38efac3bc96b9d2cbad2)
* | Fix compiler crash with value class in result positionJason Zaugg2015-07-062-2/+16
|/ | | | | | | | | We were leaking untyped trees out of the macro, which crashed in refchecks. This commit proactively typechecks the tree returned by `mkZero`. (cherry picked from commit f4275e22e000541eb619808723b70bd64b9b4873)
* Make `f(await(completedFuture))` execute `f` synchronouslyJason Zaugg2014-12-164-35/+85
| | | | | | A worthy optimization, suggested by @danarmak. Closes #73
* Remove extraneous method in generated code.Jason Zaugg2014-12-151-7/+2
|
* Avoid unbounded stack consumption for synchronous control flowJason Zaugg2014-12-157-54/+87
| | | | | | | | | | | | | | | | | | 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
* Avoid assigning null to vars of derived value typeJason Zaugg2014-09-294-7/+83
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | `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.
* Merge pull request #80 from retronym/ticket/79Jason Zaugg2014-07-213-4/+70
|\ | | | | Fix regression around type skolems and if exprs.
| * Fix regression around type skolems and if exprs.Jason Zaugg2014-07-183-4/+70
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* | Merge pull request #82 from retronym/topic/live-variable-speedupPhilipp Haller2014-07-182-28/+120
|\ \ | | | | | | Fix asymptotic performance issues in live variables analysis.
| * | Fix asymptotic performance issues in live variables analysis.Gene Novark2014-07-152-28/+120
| |/ | | | | | | | | | | | | | | | | 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.
* / Avoid NotImplementedError awaiting a Future[Nothing]Jason Zaugg2014-06-142-2/+17
|/ | | | | | | `gen.mkZero(NothingTpe)` gives the tree `Predef.???`. Instead, we should leave the `await` field uninitialized with `ValDef(..., rhs = EmptyTree)`. Fixes #66
* Incorporate pull request feedbackJason Zaugg2014-03-274-8/+3
| | | | | | | | | - 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)
* [backport] Allow lazy vals without await in the initializerJason Zaugg2014-03-274-8/+45
| | | | | | | | | | | | | | | | | | | | | | | | 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
* [backport] Test case for "not a class" crasher in live variableJason Zaugg2014-03-121-0/+28
| | | | | | Works on the 2.10.x branch, so just backprting the test. Cherry picked from 6f6546ebfc26564843621e79d840209a5103d3c8.
* Unhardcode use of scala.util.TryJason Zaugg2014-01-282-5/+2
| | | | In favour of the type defined by the active FutureSystem.
* Merge pull request #56 from retronym/topic/still-todoJason Zaugg2014-01-141-1/+1
|\ | | | | Update TODO comment about pres. compiler friendliness.
| * Update TODO comment about pres. compiler friendliness.Jason Zaugg2014-01-141-1/+1
| |
* | Update copyright years.Jason Zaugg2014-01-1432-33/+33
|/ | | | 2013 must have been unlucky.
* Minor fixes in Async`s scaladoc.akomar2014-01-121-2/+2
|
* Merge pull request #47 from retronym/topic/pres2Jason Zaugg2013-11-221-6/+5
|\ | | | | Another take at the 2.10/2.11 spanning suppressMacroAttachment
| * Another take at the 2.10/2.11 spanning suppressMacroAttachmentJason Zaugg2013-11-201-6/+5
| | | | | | | | It was only working on the former.
* | Fix crashers in do/while and while(await(..))Jason Zaugg2013-11-225-34/+73
|/ | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* Merge pull request #42 from retronym/topic/hooksJason Zaugg2013-11-204-12/+58
|\ | | | | Hooks for custom async implementations
| * Abstract over use of scala.util.TryJason Zaugg2013-11-134-11/+52
| | | | | | | | | | Custom implementation of the async macro may choose to use a different data type to represent `Throwable | A`.
| * Add a hook for post-ANF transformationJason Zaugg2013-11-132-1/+6
| | | | | | | | For use by custom implementations of the async macro.
* | Less hacky check for presentation compiler.Jason Zaugg2013-11-201-1/+1
| | | | | | | | "There's a method for that!"
* | Return original macro application under presentation compiler.Jason Zaugg2013-11-202-7/+30
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Right now, the body of an async block suffers from diminished IDE support: most notably hyperlinking doesn't work [1]. During the course of the blackbox/whitebox macro discussion, we've often talked about how the former give us the latitude to simply disable macro expansion in the IDE so we could get these features working again, at the cost of losing domain specific errors, such as "await must not be used under a nested function". But why not have our cake and eat too? This commit detects if we are running the presentation compiler and, after running our regular macro, returns the original macro application. We need to annotate that tree to prevent the typechecker from stubbornly calling our macro again. EXPERIMENTAL NOTE: This logic shouldn't live in macros: this is just a short term measure. If these experiments in async prove successful, we'll roll something similar into the macro expansion engine itself. TODO: as a performance optimization, we could just run the "unsupported await" checks, and avoid doing the more expensive state machine transformation. [1] https://www.assembla.com/spaces/scala-ide/tickets/1001449-code-navigation-fails-when-macros-are-used#/activity/ticket:
* | Fix a NPE in the presentation compilerJason Zaugg2013-11-201-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We were using a TypingTransformer and we called `atOwner` before we had called `transform`. This meant that `currTree` was null, which was observed when that was passed to `Context#make`. IDE ticket: https://scala-ide-portfolio.assembla.com/spaces/scala-ide/tickets/1001971#/activity/ticket: Stack trace: exception during macro expansion: java.lang.NullPointerException at scala.tools.nsc.interactive.ContextTrees$class.addContext(ContextTrees.scala:78) at scala.tools.nsc.interactive.Global.addContext(Global.scala:28) at scala.tools.nsc.interactive.Global.registerContext(Global.scala:268) at scala.tools.nsc.typechecker.Contexts$Context.make(Contexts.scala:295) at scala.tools.nsc.typechecker.Contexts$Context.make0(Contexts.scala:320) at scala.tools.nsc.typechecker.Contexts$Context.make(Contexts.scala:327) at scala.tools.nsc.typechecker.Typers$Typer.atOwner(Typers.scala:5662) at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:33) at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:28) at scala.async.internal.AsyncTransform$class.fixup$1(AsyncTransform.scala:191)
* | Clean-ups found during review of PR #43Philipp Haller2013-11-141-10/+2
| |
* | Fix crasher in icode due to symbol mismatches in lifted methodsJason Zaugg2013-11-142-37/+94
|/ | | | | | | | | 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.
* Don't aggressively null out captured varsJason Zaugg2013-11-125-18/+205
| | | | | Once they escape, we leave the references in the state machines fields untouched.
* Remove left-overs of CPS fallback logicPhilipp Haller2013-11-072-5/+3
| | | | Completes removal performed in #37.
* Remove scala.async.StateMachineJason Zaugg2013-11-072-19/+8
| | | | | | The generated code can simply extends Function1 and Function0. This class was a hacky means to get the macro working a long time ago.
* Minimize the public APIJason Zaugg2013-11-0715-279/+73
| | | | | | | | | | - 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.
* Scala 2.11 compatibilityJason Zaugg2013-11-072-1/+17
| | | | | | We were relying on an internal API that no longer exists. We also need to tweak the way our tests infer scalaBinaryVersion.
* Add more doc commentsPhilipp Haller2013-10-221-1/+8
|
* Avoid zero-ing out dead fields of primitive value class typePhilipp Haller2013-10-223-14/+126
| | | | | - Zero out fields of type Any - Zero out fields of value class type
* Enables testing the resetting of lifted local variablesPhilipp Haller2013-10-226-8/+81
| | | | | | | - 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
* Fix looping issue when computing last usages of fieldsPhilipp Haller2013-10-222-23/+20
| | | | | - A missing condition could cause an infinite loop - Various clean-ups
* Liveness analysis to avoid memory retention issuesPhilipp Haller2013-10-224-18/+248
| | | | | | | | - Iterative, backwards data-flow analysis - Make sure fields captured by nested defs are never zeroed out. This is done elegantly by declaring such fields a being live at the exit of the final state; thus, they will never be zeroed out.