Skip to content

-Xasync when used with js.Promise potentially generates invalid code #4249

@aappddeevv

Description

@aappddeevv

This is a bit experimental and I'm not sure I fully understand the -Xasync FSM code generation, but while it works for Option and Future (via the tests) invalid code seems to be generated for scala.js+js.Promise because it is assumed you can extract the value out. A couple of notes from retronym on scala/contributors made me think this might work but I'm not sure it does under scala.js or any effect that cannot be queried.

Here's a repo with the code https://github.com/aappddeevv/scalajs-promise-async. The issue is that even for the simplest case (sbt tests/testOnly ttg.scalajs.async.SmokeTest) the code generated would never work even if my implementation is wrong.

We can't extract a value directly from a js.Promise so the impl must always work with js.Promise . However, the code generated in case 3 is clearly doing a cast via $uI which will always fail.

It's highly likely the problem is my code, but at first blush it seems like this won't ever work for js.Promise.

// code for adding 3 Int js.Promises together.
class $c_Lttg_scalajs_async_SmokeTest$stateMachine$async$1 extends $c_Lttg_scalajs_async_PromiseStateMachine {
  constructor() {
    super();
    this.Lttg_scalajs_async_SmokeTest$stateMachine$async$1__f_result1 = 0;
    this.Lttg_scalajs_async_SmokeTest$stateMachine$async$1__f_result2 = 0;
    $ct_Lttg_scalajs_async_PromiseStateMachine__(this)
  };
  apply__sjs_js_Thenable__V(tr$async) {
    while (true) {
      try {
        switch (this.Lttg_scalajs_async_PromiseStateMachine__f_state$async) {
          case 0: {
            const awaitable$async = Promise.resolve(1);
            tr$async = this.getCompleted__sjs_js_Promise__sjs_js_Promise(awaitable$async);
            this.Lttg_scalajs_async_PromiseStateMachine__f_state$async = 1;
            if ((tr$async !== null)) {
              /*<skip>*/
            } else {
              this.onComplete__sjs_js_Thenable__V(awaitable$async);
              return (void 0)
            };
            break
          }
          case 1: {
            const tryGetResult$async = this.tryGet__sjs_js_Promise__O(tr$async);
            if ((this === tryGetResult$async)) {
              return (void 0)
            };
            this.Lttg_scalajs_async_SmokeTest$stateMachine$async$1__f_result1 = $uI(tryGetResult$async);
            const awaitable$async$2 = Promise.resolve(2);
            tr$async = this.getCompleted__sjs_js_Promise__sjs_js_Promise(awaitable$async$2);
            this.Lttg_scalajs_async_PromiseStateMachine__f_state$async = 2;
            if ((tr$async !== null)) {
              /*<skip>*/
            } else {
              this.onComplete__sjs_js_Thenable__V(awaitable$async$2);
              return (void 0)
            };
            break
          }
          case 2: {
            const tryGetResult$async$2 = this.tryGet__sjs_js_Promise__O(tr$async);
            if ((this === tryGetResult$async$2)) {
              return (void 0)
            };
            this.Lttg_scalajs_async_SmokeTest$stateMachine$async$1__f_result2 = $uI(tryGetResult$async$2);
            const awaitable$async$3 = Promise.resolve(3);
            tr$async = this.getCompleted__sjs_js_Promise__sjs_js_Promise(awaitable$async$3);
            this.Lttg_scalajs_async_PromiseStateMachine__f_state$async = 3;
            if ((tr$async !== null)) {
              /*<skip>*/
            } else {
              this.onComplete__sjs_js_Thenable__V(awaitable$async$3);
              return (void 0)
            };
            break
          }
          case 3: {
            const tryGetResult$async$3 = this.tryGet__sjs_js_Promise__O(tr$async);
            if ((this === tryGetResult$async$3)) {
              return (void 0)
            };
            $uI(tryGetResult$async$3);
            this.completeSuccess__O__V(((this.Lttg_scalajs_async_SmokeTest$stateMachine$async$1__f_result1 + this.Lttg_scalajs_async_SmokeTest$stateMachine$async$1__f_result2) | 0));
            return (void 0);
            break
          }
          default: {
            const i = this.Lttg_scalajs_async_PromiseStateMachine__f_state$async;
            throw $ct_jl_IllegalStateException__T__(new $c_jl_IllegalStateException(), ("" + i))
          }
        }
      } catch (e) {
        const e$2 = $m_sjsr_package$().wrapJavaScriptException__O__jl_Throwable(e);
        this.completeFailure__jl_Throwable__V(e$2);
        return (void 0)
      }
    }
  };
  apply__O__O(v1) {
    this.apply__sjs_js_Thenable__V(v1)
  };
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionThis is a question on using Scala.js. Closed because it should go to Stack Overflow or gitter.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions