Semantic Diff

#8919 Keep attributes in front of a record or open type representation

2 commits, rendered from their records.

Summary

RangeCommitsChangelogAreasJS output changesFormatsFailed checks
58da277de4eeba0d27f17c8056fd4c192e7b7ad9..pr-89192๐Ÿ› Bug fixsyntaxtests0none0

Changelog draft

๐Ÿ› Bug fix
  • Keep attributes and doc comments written in front of a record or .. type representation, attaching them to the type declaration instead of dropping them.

Files changed by more than one commit

compiler/syntax/src/res_core.mlbc9e90b55, cf0a2391d
tests/syntax_tests/data/parsing/grammar/typedefinition/expected/typeRepresentation.res.txtbc9e90b55, cf0a2391d
tests/syntax_tests/data/parsing/grammar/typedefinition/typeRepresentation.resbc9e90b55, cf0a2391d
tests/syntax_tests/data/printer/typeDef/attributes.resbc9e90b55, cf0a2391d
tests/syntax_tests/data/printer/typeDef/expected/attributes.res.txtbc9e90b55, cf0a2391d

58da277de4eeba0d27f17c8056fd4c192e7b7ad9..pr-8919

bc9e90b55 ยท Christoph Knittel ยท Oct 19, 2026

Keep attributes in front of a record or open type representation

๐Ÿ› Bug fixsyntaxtests

The parser accepts attributes and doc comments between = and a record declaration or .. (since #7787) but threw them away. They now go on the type declaration, after its leading attributes, so PPXs and the type checker see them; the formatter prints them in front of type. The attributed path also passes the inline-record context on, so nested record types inside such a record parse.

Example ReScript

@schematype t = @s.strict {  email: string,  name: string,}type u = @attr {x: {y: int}}
Before ReScript
@schematype t = {  email: string,  name: string,}// type u: "An inline record type declaration is only allowed in a// variant constructor's declaration or nested inside of a record type// declaration"
After ReScript
@schema @s.stricttype t = {  email: string,  name: string,}@attr type u = {x: {y: int}}
๐Ÿ› Bug fixKeep attributes and doc comments written in front of a record or .. type representation, attaching them to the type declaration instead of dropping them.

Review

No effect
Output: unchangedFormats: nonePPX: unchangedEditor: unchanged
Formatting
changedtype t = @a {...} and type t = @a .. now print as @a type t = ... instead of dropping @a
Tests
syntax tests/syntax_tests/data/~ parsing/grammar/typedefinition/typeRepresentation.res~ parsing/grammar/typedefinition/expected/typeRepresentation.res.txt~ parsing/grammar/typedefinition/expected/recordDeclaration.res.txt~ printer/typeDef/attributes.res~ printer/typeDef/expected/attributes.res.txt
7 files ยท +104 โˆ’58 ยท changelog 1 ยท syntax 1 ยท tests 5
Achanges/type-representation-attributes.fix.md+1โˆ’0
Mcompiler/syntax/src/res_core.ml+63โˆ’52
Mtests/syntax_tests/data/parsing/grammar/typedefinition/expected/recordDeclaration.res.txt+2โˆ’2
Mtests/syntax_tests/data/parsing/grammar/typedefinition/expected/typeRepresentation.res.txt+15โˆ’4
Mtests/syntax_tests/data/parsing/grammar/typedefinition/typeRepresentation.res+4โˆ’0
Mtests/syntax_tests/data/printer/typeDef/attributes.res+9โˆ’0
Mtests/syntax_tests/data/printer/typeDef/expected/attributes.res.txt+10โˆ’0
with Claude Opus 5.5
cf0a2391d ยท Christoph Knittel ยท Oct 20, 2026

Keep a doc comment in front of a record or open type representation

syntaxtests

A doc comment directly after = now goes through the same lookahead as an attribute: in front of { or .. it attaches to the type declaration, in front of a constructor it still attaches to that constructor. Before, only a doc comment after an attribute reached the declaration; one at the start was parsed as a constructor list and failed on { or ...

Example ReScript

type t = /** doc */ {x: int}type u = /** doc */ ..

Before output

syntax errors: a constructor is expected at `{` and at `..`

After ReScript

/** doc */type t = {x: int}/** doc */type u = ..
No effect
Output: unchangedFormats: nonePPX: unchangedEditor: unchanged
Formatting
changedtype t = /** doc */ {...} and type t = /** doc */ .. now parse and print with the doc comment in front of type
Tests
syntax tests/syntax_tests/data/~ parsing/grammar/typedefinition/typeRepresentation.res~ parsing/grammar/typedefinition/expected/typeRepresentation.res.txt~ printer/typeDef/attributes.res~ printer/typeDef/expected/attributes.res.txt
5 files ยท +71 โˆ’7 ยท syntax 1 ยท tests 4
Mcompiler/syntax/src/res_core.ml+12โˆ’6
Mtests/syntax_tests/data/parsing/grammar/typedefinition/expected/typeRepresentation.res.txt+22โˆ’1
Mtests/syntax_tests/data/parsing/grammar/typedefinition/typeRepresentation.res+9โˆ’0
Mtests/syntax_tests/data/printer/typeDef/attributes.res+8โˆ’0
Mtests/syntax_tests/data/printer/typeDef/expected/attributes.res.txt+20โˆ’0
with Claude Opus 5.5