diff --git a/CHANGELOG.md b/CHANGELOG.md index a48a253c..999809eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ - Fix issue where the JSX prop has type annotation of the first class module https://github.com/rescript-lang/syntax/pull/666 - Fix issue where a spread `...x` in non-last position would not be reported as syntax error https://github.com/rescript-lang/syntax/pull/673/ - Fix issue where the formatter would delete `async` in a function with labelled arguments. +- Fix several printing issues with `async` including an infinite loop https://github.com/rescript-lang/syntax/pull/680 #### :eyeglasses: Spec Compliance diff --git a/src/res_parsetree_viewer.ml b/src/res_parsetree_viewer.ml index d728d687..8ab7b31e 100644 --- a/src/res_parsetree_viewer.ml +++ b/src/res_parsetree_viewer.ml @@ -136,7 +136,7 @@ let funExpr expr = collectNewTypes (stringLoc :: acc) returnExpr | returnExpr -> (List.rev acc, returnExpr) in - let rec collect attrsBefore acc expr = + let rec collect n attrsBefore acc expr = match expr with | { pexp_desc = @@ -152,13 +152,17 @@ let funExpr expr = pexp_attributes = []; } -> let parameter = Parameter {attrs = []; lbl; defaultExpr; pat = pattern} in - collect attrsBefore (parameter :: acc) returnExpr + collect (n + 1) attrsBefore (parameter :: acc) returnExpr | {pexp_desc = Pexp_newtype (stringLoc, rest); pexp_attributes = attrs} -> let stringLocs, returnExpr = collectNewTypes [stringLoc] rest in let param = NewTypes {attrs; locs = stringLocs} in - collect attrsBefore (param :: acc) returnExpr - | {pexp_desc = Pexp_fun _; pexp_attributes = [({txt = "bs"}, _)]} -> - (* stop here, the uncurried attribute always indicates the beginning of an arrow function + collect (n + 1) attrsBefore (param :: acc) returnExpr + | {pexp_desc = Pexp_fun _; pexp_attributes} + when pexp_attributes + |> List.exists (fun ({Location.txt}, _) -> + txt = "bs" || txt = "res.async") + && n > 0 -> + (* stop here, the uncurried or async attribute always indicates the beginning of an arrow function * e.g. `(. a) => (. b)` instead of `(. a, . b)` *) (attrsBefore, List.rev acc, expr) | { @@ -175,7 +179,7 @@ let funExpr expr = let parameter = Parameter {attrs = attrs_other; lbl; defaultExpr; pat = pattern} in - collect (attrs_async @ attrsBefore) (parameter :: acc) returnExpr + collect (n + 1) (attrs_async @ attrsBefore) (parameter :: acc) returnExpr | expr -> (attrsBefore, List.rev acc, expr) in match expr with @@ -183,8 +187,8 @@ let funExpr expr = pexp_desc = Pexp_fun (Nolabel, _defaultExpr, _pattern, _returnExpr); pexp_attributes = attrs; } as expr -> - collect attrs [] {expr with pexp_attributes = []} - | expr -> collect [] [] expr + collect 0 attrs [] {expr with pexp_attributes = []} + | expr -> collect 0 [] [] expr let processBracesAttr expr = match expr.pexp_attributes with diff --git a/src/res_printer.ml b/src/res_printer.ml index 60066d09..df2d66c2 100644 --- a/src/res_printer.ml +++ b/src/res_printer.ml @@ -4698,7 +4698,7 @@ and printExprFunParameters ~customLayout ~inCallback ~async ~uncurried let txtDoc = let var = printIdentLike stringLoc.txt in let var = if hasConstraint then addParens var else var in - if async then addAsync (Doc.concat [Doc.lparen; var; Doc.rparen]) else var + if async then addAsync var else var in printComments txtDoc cmtTbl stringLoc.loc (* let f = () => () *) diff --git a/tests/printer/expr/asyncAwait.res b/tests/printer/expr/asyncAwait.res index 962cfa91..32c77349 100644 --- a/tests/printer/expr/asyncAwait.res +++ b/tests/printer/expr/asyncAwait.res @@ -82,6 +82,17 @@ let _ = await { Js.Promise.resolve(x) } -let f = async (~x, ~y) => x + y -let f = async (@foo ~x, @bar ~y) => x + y -let f = @foo async ( @bar ~x as @zz z, ~y) => x + y +let f1 = async (~x, ~y) => x + y +let f2 = async (@foo ~x, @bar ~y) => x + y +let f3 = @foo async (@bar ~x as @zz z, ~y) => x + y +let f4 = async x => x +let f5 = async x => async y => 3 +let f6 = async (~x1, ~x2) => async y => 3 +let f7 = async x => async (~y) => 3 +let f8 = async (~x1, ~x2) => async (~y) => 3 +let f9 = x => async (~y) => 3 +let f10 = x => async y => 3 +let f11 = (. ~x) => (. ~y) => 3 + +let f12 = @a (@b x) => 3 +let f13 = @a @b (~x) => 3 diff --git a/tests/printer/expr/expected/asyncAwait.res.txt b/tests/printer/expr/expected/asyncAwait.res.txt index c4b56323..01dab207 100644 --- a/tests/printer/expr/expected/asyncAwait.res.txt +++ b/tests/printer/expr/expected/asyncAwait.res.txt @@ -8,7 +8,7 @@ let sequentialAwait = async () => { let f = async () => () let f = async (. ()) => () -let f = async (f) => f() +let f = async f => f() let f = async (a, b) => a + b let f = async (. a, b) => a + b @@ -104,6 +104,17 @@ let _ = await { Js.Promise.resolve(x) } -let f = async (~x, ~y) => x + y -let f = async (@foo ~x, @bar ~y) => x + y -let f = async (@bar @foo ~x as @zz z, ~y) => x + y +let f1 = async (~x, ~y) => x + y +let f2 = async (@foo ~x, @bar ~y) => x + y +let f3 = async (@bar @foo ~x as @zz z, ~y) => x + y +let f4 = async x => x +let f5 = async x => async y => 3 +let f6 = async (~x1, ~x2) => async y => 3 +let f7 = async x => async (~y) => 3 +let f8 = async (~x1, ~x2) => async (~y) => 3 +let f9 = x => async (~y) => 3 +let f10 = x => async y => 3 +let f11 = (. ~x) => (. ~y) => 3 + +let f12 = @a x => 3 +let f13 = (@a @b ~x) => 3 diff --git a/tests/printer/expr/expected/fun.res.txt b/tests/printer/expr/expected/fun.res.txt index 8c2d973d..a1ff38fa 100644 --- a/tests/printer/expr/expected/fun.res.txt +++ b/tests/printer/expr/expected/fun.res.txt @@ -73,7 +73,7 @@ let f = @attr (@attrOnA a, @attrOnB b) => @attr2 (@attrOnC c, @attrOnD d) => () let f = @attr (. a, b) => @attr2 (. c, d) => () let f = (@attr ~a, @attr ~b) => () -let f = (. @attr ~a, . @attr ~b) => () +let f = (. @attr ~a) => (. @attr ~b) => () let f = ( thisIsAVeryLongNaaaaaaaaaaaaaaaaaaameeeeeeeeeeeee,