Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

#### :bug: Bug fix

- Fix formatter breaking the opening brace of a functor module type's result signature onto a new line (e.g. `module Make: Pattern => {`). https://github.com/rescript-lang/rescript/pull/8519

#### :memo: Documentation

#### :nail_care: Polish
Expand Down
10 changes: 9 additions & 1 deletion compiler/syntax/src/res_printer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -931,11 +931,19 @@ and print_mod_type ~state mod_type cmt_tbl =
if Parens.mod_type_functor_return return_type then add_parens doc
else doc
in
(* When the functor result is a signature, keep its opening brace on the
same line as `=>` instead of breaking onto a new line, mirroring how
module-expression functors are printed (see print_mod_functor). *)
let arrow_sep =
match return_type.pmty_desc with
| Pmty_signature _ -> Doc.space
| _ -> Doc.line
in
Doc.group
(Doc.concat
[
parameters_doc;
Doc.group (Doc.concat [Doc.text " =>"; Doc.line; return_doc]);
Doc.group (Doc.concat [Doc.text " =>"; arrow_sep; return_doc]);
])
| Pmty_typeof mod_expr ->
Doc.concat
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ module M3: {
include M'
}

module G0: (X: {}) =>
{
module G0: (X: {}) => {
module N': {
let x: int
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ module type Functor = (@attr1 SetLike, @attr2 BtreeLike) => @attr3 NeoTree
module type Functor = (SetLike => Set) with type t = A.t
module type Functor = SetLike => (Set with type t = A.t)

module type B = () =>
{
module type B = () => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry I should be more explicit @MavenRain, can you also add a similar test here? Just need to be sure that both .res and .resi are handled correctly.


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module Make: Pattern => {
let fmt: event => string
}

module Curried: (A, B) => {
let x: int
}

module Nested: (A, B) => {
let y: int
}

module Empty: () => {}

module ResultIdent: A => B

module ResultWith: A => (B with type t = int)

module ThisIsAVeryLongFunctorModuleTypeNameThatExceedsTheEightyCharacterLimit: Pattern => {
let fmt: event => string
}

module SecondVeryLongFunctorModuleTypeNameWithMultipleShortParameters: (A, B) => {
let x: int
}

module YetAnotherVeryLongFunctorModuleTypeNameHere: SomeVeryLongParameterModuleTypeName =>
SomeVeryLongResultingModuleTypeName
27 changes: 27 additions & 0 deletions tests/syntax_tests/data/printer/modType/functorInterface.resi
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module Make: Pattern => {
let fmt: event => string
}

module Curried: (A, B) => {
let x: int
}

module Nested: A => B => {
let y: int
}

module Empty: () => {}

module ResultIdent: A => B

module ResultWith: A => (B with type t = int)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MavenRain can you add module name with a longer name as well (more than 80 characters in one line) to test how the formatter handles that case?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added three long-name cases (each over 80 columns) to functorInterface.resi plus their golden output:

module ThisIsAVeryLongFunctorModuleTypeNameThatExceedsTheEightyCharacterLimit: Pattern => {
  let fmt: event => string
}

module SecondVeryLongFunctorModuleTypeNameWithMultipleShortParameters: (A, B) => {
  let x: int
}

module YetAnotherVeryLongFunctorModuleTypeNameHere: SomeVeryLongParameterModuleTypeName =>
SomeVeryLongResultingModuleTypeName

How the formatter handles them:

  • Signature results keep the brace hugged even past 80 columns (91 and 82 columns above). For Name: Pattern => { there is no break point that could rescue the width anyway: before this fix the printer emitted the same overlong header minus the brace and then put { alone on the next line, so hugging costs 2 characters on an already-overlong line and matches how module-expression functors print.
  • Long non-signature results still wrap at the breakable line after => (third case); that path is untouched by this PR.
  • One trait the new golden makes visible: the second case's short parameter tuple stays flat rather than breaking to rescue the width. That behavior is not new here: master prints the same header flat (just with { pushed to the next line), and module-expression functors keep short parameter tuples flat on comparable over-80-column headers as well. The fix only changes where the brace goes.

The full corpus regeneration shows no other golden moved, and the printer + idempotency roundtrip suite still passes; the new cases are idempotent. Reverting the fix breaks the new golden on exactly the two long-name signature cases, so they do exercise the changed code path.


module ThisIsAVeryLongFunctorModuleTypeNameThatExceedsTheEightyCharacterLimit: Pattern => {
let fmt: event => string
}

module SecondVeryLongFunctorModuleTypeNameWithMultipleShortParameters: (A, B) => {
let x: int
}

module YetAnotherVeryLongFunctorModuleTypeNameHere: SomeVeryLongParameterModuleTypeName => SomeVeryLongResultingModuleTypeName