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

Đang mở
#9,229 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
72/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
javascript, ocaml
Lĩnh vực
backend, compilers

Hướng nghiên cứu

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.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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.

Ngôn ngữ chính
OCaml
Star
7.5k
Fork
484
Merge trung bình
17 giờ 9 phút
Pull request đã merge (30 ngày)
264

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của rescript-lang/rescript

Tất cả issue của rescript-lang/rescript

Issue tương tự

Thêm issue về Backend & API Design

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.