diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ee29f0853..9c4e84f4d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,9 @@ - Removed empty line at the end of `switch` statement - Removed empty `default` case from `switch` statement in the generated code +#### :bug: Bug Fix +- Fix issue where long layout break added a trailing comma in partial application `...`. https://github.com/rescript-lang/rescript-compiler/pull/6949 + # 12.0.0-alpha.1 #### :rocket: New Feature diff --git a/jscomp/syntax/src/res_parsetree_viewer.ml b/jscomp/syntax/src/res_parsetree_viewer.ml index 4b26dc55ec..75d0228442 100644 --- a/jscomp/syntax/src/res_parsetree_viewer.ml +++ b/jscomp/syntax/src/res_parsetree_viewer.ml @@ -57,6 +57,13 @@ let process_partial_app_attribute attrs = in process false [] attrs +let has_partial_attribute attrs = + List.exists + (function + | {Location.txt = "res.partial"}, _ -> true + | _ -> false) + attrs + type function_attributes_info = {async: bool; attributes: Parsetree.attributes} let process_function_attributes attrs = diff --git a/jscomp/syntax/src/res_parsetree_viewer.mli b/jscomp/syntax/src/res_parsetree_viewer.mli index 6661dfc923..0cd2053694 100644 --- a/jscomp/syntax/src/res_parsetree_viewer.mli +++ b/jscomp/syntax/src/res_parsetree_viewer.mli @@ -17,6 +17,8 @@ val functor_type : val process_partial_app_attribute : Parsetree.attributes -> bool * Parsetree.attributes +val has_partial_attribute : Parsetree.attributes -> bool + type function_attributes_info = {async: bool; attributes: Parsetree.attributes} (* determines whether a function is async and/or uncurried based on the given attributes *) diff --git a/jscomp/syntax/src/res_printer.ml b/jscomp/syntax/src/res_printer.ml index fbb397f83e..ae8055d7b5 100644 --- a/jscomp/syntax/src/res_printer.ml +++ b/jscomp/syntax/src/res_printer.ml @@ -4146,7 +4146,13 @@ and print_pexp_apply ~state expr cmt_tbl = let partial, attrs = ParsetreeViewer.process_partial_app_attribute attrs in let args = if partial then - let dummy = Ast_helper.Exp.constant (Ast_helper.Const.int 0) in + let loc = + {Asttypes.txt = "res.partial"; Asttypes.loc = expr.pexp_loc} + in + let attr = (loc, Parsetree.PTyp (Ast_helper.Typ.any ())) in + let dummy = + Ast_helper.Exp.constant ~attrs:[attr] (Ast_helper.Const.int 0) + in args @ [(Asttypes.Labelled "...", dummy)] else args in @@ -4730,6 +4736,18 @@ and print_arguments ~state ?(partial = false) in Doc.concat [Doc.lparen; arg_doc; Doc.rparen] | args -> + (* Avoid printing trailing comma when there is ... in function application *) + let has_partial_attr, printed_args = + List.fold_right + (fun arg (flag, acc) -> + let _, expr = arg in + let has_partial_attr = + ParsetreeViewer.has_partial_attribute expr.Parsetree.pexp_attributes + in + let doc = print_argument ~state arg cmt_tbl in + (flag || has_partial_attr, doc :: acc)) + args (false, []) + in Doc.group (Doc.concat [ @@ -4738,13 +4756,9 @@ and print_arguments ~state ?(partial = false) (Doc.concat [ Doc.soft_line; - Doc.join - ~sep:(Doc.concat [Doc.comma; Doc.line]) - (List.map - (fun arg -> print_argument ~state arg cmt_tbl) - args); + Doc.join ~sep:(Doc.concat [Doc.comma; Doc.line]) printed_args; ]); - (if partial then Doc.nil else Doc.trailing_comma); + (if partial || has_partial_attr then Doc.nil else Doc.trailing_comma); Doc.soft_line; Doc.rparen; ]) diff --git a/jscomp/syntax/tests/printer/expr/apply.res b/jscomp/syntax/tests/printer/expr/apply.res index 9d44d720d3..3c9d1aed48 100644 --- a/jscomp/syntax/tests/printer/expr/apply.res +++ b/jscomp/syntax/tests/printer/expr/apply.res @@ -73,3 +73,37 @@ f(. { resolve(.) resolve(. ()) + +let g = f( + a => LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx(a), + b, + c +) + +let g = f( + a => LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx(a), + b, + c, + ... +) + +let g = f( + a => LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx(a), + b, + c => LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx(d, ...), + ... +) + +let g = f( + a => LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx(a, ...), + b, + c => LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx(d), + ... +) + + +let g = f( + a => LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx(a), + b, + c => LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx(d, ...) +) diff --git a/jscomp/syntax/tests/printer/expr/expected/apply.res.txt b/jscomp/syntax/tests/printer/expr/expected/apply.res.txt index c04b627ad2..f37f83f248 100644 --- a/jscomp/syntax/tests/printer/expr/expected/apply.res.txt +++ b/jscomp/syntax/tests/printer/expr/expected/apply.res.txt @@ -93,3 +93,54 @@ f({ resolve() resolve() + +let g = f( + a => LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx(a), + b, + c, +) + +let g = + f( + a => + LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx(a), + b, + c, + ... + ) + +let g = + f( + a => + LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx(a), + b, + c => + LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx( + d, + ... + ), + ... + ) + +let g = + f( + a => + LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx( + a, + ... + ), + b, + c => + LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx(d), + ... + ) + +let g = f( + a => LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx(a), + b, + c => + LongModuleName.functionWithAlongNameThatWrapsTheEditorToTheNextLinexxxxxxxxxxxxxxxxxxxxxx( + d, + ... + ), +)