diff --git a/lib/Conf.ml b/lib/Conf.ml index f99ad5ae6e..dfd1ebc121 100644 --- a/lib/Conf.ml +++ b/lib/Conf.ml @@ -96,6 +96,7 @@ let conventional_profile from = ; parens_ite= elt false ; parens_tuple= elt `Always ; parens_tuple_patterns= elt `Multi_line_only + ; parens_tuple_labeled_arg_types= elt false ; parse_docstrings= elt true ; parse_toplevel_phrases= elt false ; sequence_blank_line= elt `Preserve_one @@ -164,6 +165,7 @@ let ocamlformat_profile from = ; parens_ite= elt false ; parens_tuple= elt `Always ; parens_tuple_patterns= elt `Multi_line_only + ; parens_tuple_labeled_arg_types= elt false ; parse_docstrings= elt false ; parse_toplevel_phrases= elt false ; sequence_blank_line= elt `Compact @@ -231,6 +233,7 @@ let janestreet_profile from = ; parens_ite= elt true ; parens_tuple= elt `Multi_line_only ; parens_tuple_patterns= elt `Multi_line_only + ; parens_tuple_labeled_arg_types= elt true ; parse_docstrings= elt false ; parse_toplevel_phrases= elt false ; sequence_blank_line= elt `Compact diff --git a/lib/Conf_t.ml b/lib/Conf_t.ml index 59f0c6b458..d5b13545f6 100644 --- a/lib/Conf_t.ml +++ b/lib/Conf_t.ml @@ -104,6 +104,7 @@ type fmt_opts = ; parens_ite: bool elt ; parens_tuple: [`Always | `Multi_line_only] elt ; parens_tuple_patterns: [`Always | `Multi_line_only] elt + ; parens_tuple_labeled_arg_types: bool elt ; parse_docstrings: bool elt ; parse_toplevel_phrases: bool elt ; sequence_blank_line: [`Compact | `Preserve_one] elt diff --git a/lib/Conf_t.mli b/lib/Conf_t.mli index 853e321d8e..82c63b98d9 100644 --- a/lib/Conf_t.mli +++ b/lib/Conf_t.mli @@ -102,6 +102,7 @@ type fmt_opts = ; parens_ite: bool elt ; parens_tuple: [`Always | `Multi_line_only] elt ; parens_tuple_patterns: [`Always | `Multi_line_only] elt + ; parens_tuple_labeled_arg_types: bool elt ; parse_docstrings: bool elt ; parse_toplevel_phrases: bool elt ; sequence_blank_line: [`Compact | `Preserve_one] elt diff --git a/lib/Fmt_ast.ml b/lib/Fmt_ast.ml index e1d6ff5c37..fbf0dba991 100644 --- a/lib/Fmt_ast.ml +++ b/lib/Fmt_ast.ml @@ -801,9 +801,15 @@ and fmt_arrow_param ~return c ctx | Ptyp_tuple ((Some _, _) :: _) -> true | _ -> false in - let core_type = - Params.parens_if labeled_tuple_ret_parens c.conf (fmt_core_type c xtI) + (* Jane Street: With our profile only, parenthesize the body of a labeled + parameter type if it is a tuple, to distinguish from labeled tuples. *) + let labeled_arg_tuple_parens = + c.conf.fmt_opts.parens_tuple_labeled_arg_types.v && (not return) + && (match tI.ptyp_desc with Ptyp_tuple _ -> true | _ -> false) + && match lI with Nolabel -> false | Labelled _ | Optional _ -> true in + let parens = labeled_tuple_ret_parens || labeled_arg_tuple_parens in + let core_type = fmt_core_type ~parens c xtI in let arg = match arg_label lI with | None -> core_type @@ -849,7 +855,7 @@ and fmt_arrow_type c ~ctx ?indent ~parens ~parent_has_parens args fmt_ret_typ gets support for them, we should remove tydecl_param and go with whatever their solution is. *) and fmt_core_type c ?(box = true) ?pro ?(pro_space = true) ?constraint_ctx - ?(tydecl_param = false) ({ast= typ; ctx} as xtyp) = + ?(tydecl_param = false) ?(parens = false) ({ast= typ; ctx} as xtyp) = protect c (Typ typ) @@ let {ptyp_desc; ptyp_attributes; ptyp_loc; _} = typ in @@ -883,7 +889,7 @@ and fmt_core_type c ?(box = true) ?pro ?(pro_space = true) ?constraint_ctx (Params.parens_if (not tydecl_param) c.conf (k $ fmt_attributes c ~pre:Cut atrs) ) ) @@ - let parens = (not tydecl_param) && parenze_typ xtyp in + let parens = parens || ((not tydecl_param) && parenze_typ xtyp) in hvbox_if box 0 @@ Params.parens_if (match typ.ptyp_desc with Ptyp_tuple _ -> false | _ -> parens) diff --git a/test/passing/tests/labeled_tuples.ml b/test/passing/tests/labeled_tuples.ml index cd94542c96..942937b2a1 100644 --- a/test/passing/tests/labeled_tuples.ml +++ b/test/passing/tests/labeled_tuples.ml @@ -269,3 +269,16 @@ let _ = f (Foo (~x:5, 1)) let _ = f (Foo (5, 1)) let _ = f (Foo (5, ~x:1)) let _ = f (Foo (5, ~y:1)) + +(* As a result of labeled tuples, we've decided to add parens around labeled function + argument types when they are tuples, for disambiguation. *) +type t = x:(int * bool) -> string +type t = x:(int * y:bool) -> string +type t = x:(y:int * z:bool) -> string + +type t = + x: + (long_type_name_for_multiline1 + * long_type_name_for_multiline2 + * long_type_name_for_multiline3) + -> string diff --git a/test/passing/tests/labeled_tuples_regressions.mli b/test/passing/tests/labeled_tuples_regressions.mli index 63f6dc92fb..90b2b33aa7 100644 --- a/test/passing/tests/labeled_tuples_regressions.mli +++ b/test/passing/tests/labeled_tuples_regressions.mli @@ -1,6 +1,6 @@ (* https://github.com/janestreet/ocamlformat/pull/49 *) val f - : foo:int * very_long_type_name_so_we_get_multiple_lines + : foo:(int * very_long_type_name_so_we_get_multiple_lines) -> (* cmt *) bar:('long_type_var_1, 'long_type_var_2) Long_module_name.t -> additional_somewhat_long_type_name