`await` is rejected in a `@this async` function, which compiles to an `async function`

オープン
#9,229 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
72/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
javascript, ocaml
領域
backend, compilers

調査の方向性

Start in compiler/frontend/bs_builtin_ppx.ml, where expr_mapper handles the Pexp_fun case with @this; compare its async_context handling with the plain Pexp_fun branch. Check the compiler tests for @this async functions and add coverage for await in the body. Done means the example compiles while await remains rejected in non-async @this functions and plain nested functions.

索引モデルが issue の本文から書いたものです。

説明

An await in the body of a function that has both @this and async is rejected with "Await on expression not in an async context", although the function is typed as returning a promise and is compiled to a JavaScript async function.

type obj = {name: string}

let m = @this async (self: obj, x: promise<int>) => {
  let v = await x
  self.name ++ Int.toString(v)
}
  We've found a bug for you!
  ThisAsyncAwait.res:4:11-17

  2 │ 
  3 │ let m = @this async (self: obj, x: promise<int>) => {
  4 │   let v = await x
  5 │   self.name ++ Int.toString(v)
  6 │ }

  Await on expression not in an async context

Without the await, a @this async function has type @this (obj, int) => promise<string> and compiles to an async function, where await is valid:

let m = @this async (self: obj, x: int) => self.name ++ Int.toString(x)
async function m(x) {
  let self = this ;
  return self.name + x.toString();
}

module M = await List and for await x of xs {...} in the body of a @this async function are rejected with the same error. To use await, the body has to go into a separate async function that the method calls:

let helper = async (self: obj, x: promise<int>) => {
  let v = await x
  self.name ++ Int.toString(v)
}

let m = @this (self: obj, x: promise<int>) => helper(self, x)
async function helper(self, x) {
  let v = await x;
  return self.name + v.toString();
}

function m(x) {
  let self = this ;
  return helper(self, x);
}

In compiler/frontend/bs_builtin_ppx.ml, expr_mapper handles a Pexp_fun with @this (the Meth_callback case of Ast_attributes.process_attributes_rev) by setting async_context := false and then calling Ast_uncurry_gen.to_method_callback ~async, which maps the body under that context and builds the function with ~async and Ast_async.make_function_async ~async. So the body is checked as non-async even when the function it is emitted into is async. The false dates from when a @this function could not be async; #7702 passed ~async to to_method_callback but left the context unchanged. Setting async_context := async in that branch, as the plain Pexp_fun branch above it does, fixes it: the example at the top then compiles to async function m(x) with let v = await x;, and m.call({name: "n"}, Promise.resolve(41)) resolves to "n41". await in a @this function without async, or in a plain function inside a @this async one, is still rejected.

Reproduced with 12.0.0-beta.3, 12.3.1, 13.0.0-alpha.6 and master (fc7444266). A @this async function compiles to an async function with a promise result since #7702 (12.0.0-beta.3), the fix for #7681. Before that, in 12.0.0-beta.2 and 11.1.4, it compiled to a plain function, and await in it was rejected as well.

#6100 reported this error together with the dropped async attribute; #6105 fixed the attribute. Its first example, where the async function is the one returned by the @this function (@this self => async arg => await ...), compiles since 13.0.0-alpha.6; the form above, with @this and async on the same function, does not.

Related: #6100, #7681, #7702.

主要言語
OCaml
スター
7.5k
フォーク
485
平均マージ
17時間 9分
マージ済み PR(30日)
264

環境構築

Codespaces で開く

このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

rescript-lang/rescript のほかの issue

rescript-lang/rescript の issue をすべて見る

似ている issue

Backend & API Design の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。