Semantic Diff

#9078 Word signature mismatch errors in ReScript terms

2 commits

cd641cbc06120a7d0a0a62776a3301e536cae415..pr-9078

cbcd4f637 · Christoph Knittel + Claude · Oct 27, 2026, 19:53 UTC

Indent multi-line types and signatures in error messages

The outcome printer rendered a type, signature or module type to a string and handed it to Format as one piece, so every line after the first started at column 0 instead of under its heading, and a short multi-line signature could share a line with the text around it. Each line break is now a newline of the enclosing Format box, and a multi-line piece makes that box break around it.

modifiedDiagnostic module mismatch

module type S = {  type t}module M: {  module F: (X: S) => S with type t = X.t} = {  module F = (X: S) => {    type t = int  }}
diagnostic
Before
Modules do not match:  {module F: (X: S) => {  type t = int}

}

is not included in…Modules do not match: {type t = int

} is not included in {

type t = X.t

}

diagnostic
After
Modules do not match:  {    module F: (X: S) => {      type t = int    }  }is not included in…Modules do not match:  {    type t = int  }is not included in  {    type t = X.t  }

Part of #9074.

Review

  • Which messages change? Every one that prints a multi-line type, signature or module type, mostly signature mismatches; their snapshots change only in layout.
  • Does this change single-line types in messages? No. A doc that fits on one line is printed as before; only the line breaks of multi-line ones are emitted differently.
1db203e9b · cknitt + Claude · Oct 27, 2026, 12:41 UTC

Word signature mismatch errors in ReScript terms

Why

Inclusion errors still used OCaml wording: variant constructors were called fields, functor positions were written as module F(X) : ..., names were quoted as x', and extension constructors were printed with two spaces after +=`.

modifiedDiagnostic variant constructor mismatch

module M: {  type rec t<_> = Int(int): t<int> | Str(string): t<string>} = {  type rec t<_> = Int(int): t<int> | Str(string): t<int>}
diagnostic
Before
After
The types for field Str are not equal.The types for constructor Str are not equal.

modifiedDiagnostic functor position

module type S = {  type t}module M: {  module F: (X: S) => S with type t = X.t} = {  module F = (X: S) => {    type t = int  }}
diagnostic
Before
After
At position module F(X) : <here>At position module F: (X) => <here>

modifiedDiagnostic missing value

diagnostic
Before
After
The value `b' is required but not providedThe value `b` is required but not provided

modifiedDiagnostic extension constructor

diagnostic
Before
After
type t += Boom(string)type t += Boom(string)

Review

  • Do record fields keep their wording? Yes. Only the comparison of variant constructors uses the new constructor errors; inline record fields of a constructor are still compared as fields.