Skip to content

Make a function's locally abstract types part of the function node - #8574

Merged
cristianoc merged 1 commit into
masterfrom
codex/nary-newtypes
Aug 21, 2026
Merged

Make a function's locally abstract types part of the function node#8574
cristianoc merged 1 commit into
masterfrom
codex/nary-newtypes

Conversation

@cristianoc

Copy link
Copy Markdown
Collaborator

Part of the n-ary functions series tracked in #8557 (item 8 of 10; items 1–7 are merged).

What

Replace the Pexp_newtype wrapper chains that the parser built for
(type t, x) => ... arrow syntax with a structural field on the function
node: Pexp_fun.newtypes carries each newtype name with its own
attributes, hoisted in front of the value parameters as before.
Pexp_newtype remains solely as the desugaring of [let f: type a. ...]
annotations and for PPX-authored trees.

Fidelity fixes visible in the formatter:

  • Attributes keep their association with their type parameter group:
    (@attr type t, x, @attr2 type s, y) round-trips as written instead of
    printing @attr @attr2 on the function.
  • Comments written next to a type parameter travel with it to the
    hoisted group instead of migrating onto the following value parameter.
  • Attributes written in front of the arrow now live on the function
    node, so built-in attribute processing (e.g. @this) sees them on
    type-first functions; previously they sat inert on the wrapper node.

Typing follows the upstream OCaml 5.x design: the newtype machinery is
extracted into a reusable type_newtype helper (mirroring OCaml's helper
of the same name) and the function case peels one newtype at a time,
mimicking the typing of the former wrapper chain; the typedtree output
is bit-identical to before.

The v0 PPX bridge expands the field back into a wrapper chain around
Function$: each wrapper carries its own newtype's attributes, and the
outermost wrapper separates function-node attributes from the first
newtype's attributes with an internal _res.newtype_attrs marker (no
marker means node attributes only, matching the historical wire).
Newtype-free programs are wire byte-identical; for functions with
newtypes the deltas are confined to wrapper-node locations and, for the
rare attributed groups, per-wrapper attribute placement. Identity-PPX
round-trips are AST-exact, verified against the previous compiler.

Also: jsx_v4 and bs_builtin_ppx now carry newtypes (and their
attributes) through their function rebuilds instead of dropping them,
the sexp AST debugger emits the field, and dead parser plumbing
(fundef param attrs/p_pos, arrow_start_pos, make_newtypes ~attrs) is
removed.

🤖 Generated with Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ea2e2cfe9c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread compiler/ml/typecore.ml Outdated
Comment thread compiler/ml/typecore.ml Outdated
@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.67347% with 24 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.85%. Comparing base (36b14d6) to head (1e39b9f).

Files with missing lines Patch % Lines
compiler/ml/ast_mapper_from0.ml 70.00% 6 Missing ⚠️
compiler/ml/printast.ml 0.00% 4 Missing ⚠️
compiler/frontend/bs_ast_mapper.ml 0.00% 3 Missing ⚠️
compiler/syntax/src/res_core.ml 88.46% 3 Missing ⚠️
compiler/ml/typecore.ml 92.59% 2 Missing ⚠️
compiler/syntax/src/res_comments_table.ml 75.00% 2 Missing ⚠️
compiler/syntax/src/res_parsetree_viewer.ml 83.33% 2 Missing ⚠️
compiler/frontend/bs_builtin_ppx.ml 75.00% 1 Missing ⚠️
tools/src/transforms.ml 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #8574      +/-   ##
==========================================
- Coverage   75.89%   75.85%   -0.04%     
==========================================
  Files         474      474              
  Lines       62772    62835      +63     
==========================================
+ Hits        47640    47665      +25     
- Misses      15132    15170      +38     
Files with missing lines Coverage Δ
compiler/ml/ast_helper.ml 78.73% <100.00%> (ø)
compiler/ml/ast_iterator.ml 92.78% <100.00%> (-0.28%) ⬇️
compiler/ml/ast_mapper.ml 75.46% <100.00%> (+0.11%) ⬆️
compiler/ml/ast_mapper_to0.ml 58.45% <100.00%> (+0.87%) ⬆️
compiler/ml/pprintast.ml 91.56% <100.00%> (-0.31%) ⬇️
compiler/syntax/src/jsx_v4.ml 86.70% <100.00%> (-0.03%) ⬇️
compiler/syntax/src/res_ast_debugger.ml 96.14% <100.00%> (+0.02%) ⬆️
compiler/syntax/src/res_printer.ml 93.18% <100.00%> (+<0.01%) ⬆️
compiler/frontend/bs_builtin_ppx.ml 89.18% <75.00%> (-1.44%) ⬇️
tools/src/transforms.ml 0.00% <0.00%> (ø)
... and 7 more

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pkg-pr-new

pkg-pr-new Bot commented Aug 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

rescript

npm i https://pkg.pr.new/rescript-lang/rescript@8574

@rescript/belt

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/belt@8574

@rescript/darwin-arm64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/darwin-arm64@8574

@rescript/darwin-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/darwin-x64@8574

@rescript/linux-arm64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/linux-arm64@8574

@rescript/linux-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/linux-x64@8574

@rescript/runtime

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/runtime@8574

@rescript/win32-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/win32-x64@8574

commit: 1e39b9f

@github-actions

Copy link
Copy Markdown

Replace the Pexp_newtype wrapper chains that the parser built for
(type t, x) => ... arrow syntax with a structural field on the function
node: Pexp_fun.newtypes carries each newtype name with its own
attributes, hoisted in front of the value parameters as before.
Pexp_newtype remains solely as the desugaring of [let f: type a. ...]
annotations and for PPX-authored trees.

Fidelity fixes visible in the formatter:
- Attributes keep their association with their type parameter group:
  (@attr type t, x, @attr2 type s, y) round-trips as written instead of
  printing @attr @attr2 on the function.
- Comments written next to a type parameter travel with it to the
  hoisted group instead of migrating onto the following value parameter.
- Attributes written in front of the arrow now live on the function
  node, so built-in attribute processing (e.g. @this) sees them on
  type-first functions; previously they sat inert on the wrapper node.

Typing follows the upstream OCaml 5.x design: the newtype machinery is
extracted into a reusable type_newtype helper (mirroring OCaml's helper
of the same name) and the function case peels one newtype at a time,
mimicking the typing of the former wrapper chain; the typedtree output
is bit-identical to before.

The v0 PPX bridge expands the field back into a wrapper chain around
Function$: each wrapper carries its own newtype's attributes, and the
outermost wrapper separates function-node attributes from the first
newtype's attributes with an internal _res.newtype_attrs marker (no
marker means node attributes only, matching the historical wire).
Newtype-free programs are wire byte-identical; for functions with
newtypes the deltas are confined to wrapper-node locations and, for the
rare attributed groups, per-wrapper attribute placement. Identity-PPX
round-trips are AST-exact, verified against the previous compiler.

Also: jsx_v4 and bs_builtin_ppx now carry newtypes (and their
attributes) through their function rebuilds instead of dropping them,
the sexp AST debugger emits the field, and dead parser plumbing
(fundef param attrs/p_pos, arrow_start_pos, make_newtypes ~attrs) is
removed.

Signed-Off-By: Cristiano Calcagno <cristianoc@users.noreply.github.com>

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cristianoc
cristianoc force-pushed the codex/nary-newtypes branch from 15936ab to 1e39b9f Compare August 20, 2026 15:54
@cristianoc
cristianoc requested a review from cknitt August 20, 2026 16:19
@cristianoc
cristianoc merged commit 403c9c0 into master Aug 21, 2026
53 of 54 checks passed
@cristianoc
cristianoc deleted the codex/nary-newtypes branch August 21, 2026 06:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants