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

Abierto
#9,229 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
3/5
Tiempo estimado
1-2 días
Aptitud para principiantes
72/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
javascript, ocaml

Línea de trabajo

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.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

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.

Lenguaje dominante
OCaml
Estrellas
7.5k
Forks
485
Merge medio
17 h 9 min
PR fusionados (30 d)
264

Preparar el entorno

Abrir en Codespaces

Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de rescript-lang/rescript

Todos los issues de rescript-lang/rescript

Issues similares

Más issues de Backend & API Design

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.