Skip to content

Make locally abstract value constraints structural in the parsetree - #8575

Open
cristianoc wants to merge 1 commit into
codex/nary-newtypesfrom
codex/nary-value-constraints
Open

Make locally abstract value constraints structural in the parsetree#8575
cristianoc wants to merge 1 commit into
codex/nary-newtypesfrom
codex/nary-value-constraints

Conversation

@cristianoc

Copy link
Copy Markdown
Collaborator

Part of the n-ary functions series tracked in #8557 (item 9 of 10; stacked on #8574 via base branch; each PR merges independently).

What

Replace the desugared encoding of [let f: type a. t = e] - a Ptyp_poly
pattern constraint plus a Pexp_newtype chain over a Pexp_constraint,
with the type stored twice and no AST invariant ensuring that the copies
agree - with a structural field on the binding:

pvb_constraint: {pvc_newtypes: string loc list; pvc_type: core_type}

Only the [type a.] form uses the field; plain constraints and explicit
polymorphic annotations keep their existing representation. The type is
stored once, and [varify_constructors] now runs in exactly one place,
inside the type checker.

With functions already carrying their locally abstract type parameters in
Pexp_fun.newtypes, this removes the last place where the parser constructs
Pexp_newtype. Delete the constructor from the current parsetree, along with
the Texp_newtype exp_extra, which had no consumer beyond no-op iterators and
the debug printer. The CMT magic number is bumped to Caml1999T024; the CMI
format is unchanged.

Type checking follows the same design as the function case (and OCaml
5.x): type_let introduces the locally abstract types into scope via
type_newtype, types the body against the constraint, and unifies with the
pattern's polymorphic type. This preserves the semantics of the former
desugaring.

The frozen v0 PPX bridge expands the field back into the historical
wrapper-chain encoding and recognizes well-formed instances of that
encoding on the way in, verified by unit tests. A v0 Pexp_newtype chain
that cannot be represented - such as one that does not enclose ReScript's
Function$ encoding, or one whose structure was changed by a PPX - now
becomes a located ocaml.error extension with an explicit message. This is
the only intentional reduction in accepted v0 PPX output.

Formatter bug fix covered by syntax fixtures: a trailing comment between
the constraint type and [=] is no longer dropped. An end-to-end GADT test
checks that refinement still works with the new binding field.

🤖 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: f4726517aa

ℹ️ 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 CHANGELOG.md Outdated
Replace the desugared encoding of [let f: type a. t = e] - a Ptyp_poly
pattern constraint plus a Pexp_newtype chain over a Pexp_constraint,
with the type stored twice and no AST invariant ensuring that the copies
agree - with a structural field on the binding:

  pvb_constraint: {pvc_newtypes: string loc list; pvc_type: core_type}

Only the [type a.] form uses the field; plain constraints and explicit
polymorphic annotations keep their existing representation. The type is
stored once, and [varify_constructors] now runs in exactly one place,
inside the type checker.

With functions already carrying their locally abstract type parameters in
Pexp_fun.newtypes, this removes the last place where the parser constructs
Pexp_newtype. Delete the constructor from the current parsetree, along with
the Texp_newtype exp_extra, which had no consumer beyond no-op iterators and
the debug printer. The CMT magic number is bumped to Caml1999T024; the CMI
format is unchanged.

Type checking follows the same design as the function case (and OCaml
5.x): type_let introduces the locally abstract types into scope via
type_newtype, types the body against the constraint, and unifies with the
pattern's polymorphic type. This preserves the semantics of the former
desugaring.

The frozen v0 PPX bridge expands the field back into the historical
wrapper-chain encoding and recognizes well-formed instances of that
encoding on the way in, verified by unit tests. A v0 Pexp_newtype chain
that cannot be represented - such as one that does not enclose ReScript's
Function$ encoding, or one whose structure was changed by a PPX - now
becomes a located ocaml.error extension with an explicit message. This is
the only intentional reduction in accepted v0 PPX output.

Formatter bug fix covered by syntax fixtures: a trailing comment between
the constraint type and [=] is no longer dropped. An end-to-end GADT test
checks that refinement still works with the new binding field.

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-value-constraints branch from 1d06471 to 403b094 Compare August 20, 2026 15:54
@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.87938% with 44 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.93%. Comparing base (1e39b9f) to head (403b094).

Files with missing lines Patch % Lines
compiler/syntax/src/res_parens.ml 35.71% 9 Missing ⚠️
compiler/ml/pprintast.ml 72.00% 7 Missing ⚠️
compiler/ml/printast.ml 0.00% 6 Missing ⚠️
analysis/src/dump_ast.ml 28.57% 5 Missing ⚠️
tests/ounit_tests/ounit_ast_mapper0_tests.ml 78.26% 5 Missing ⚠️
compiler/frontend/bs_ast_mapper.ml 57.14% 3 Missing ⚠️
compiler/ml/ast_mapper_from0.ml 90.62% 3 Missing ⚠️
analysis/src/completion_front_end.ml 33.33% 2 Missing ⚠️
compiler/syntax/src/res_comments_table.ml 93.75% 2 Missing ⚠️
analysis/src/xform.ml 80.00% 1 Missing ⚠️
... and 1 more
Additional details and impacted files
@@                   Coverage Diff                   @@
##           codex/nary-newtypes    #8575      +/-   ##
=======================================================
+ Coverage                75.85%   75.93%   +0.07%     
=======================================================
  Files                      474      474              
  Lines                    62835    62902      +67     
=======================================================
+ Hits                     47665    47765     +100     
+ Misses                   15170    15137      -33     
Files with missing lines Coverage Δ
analysis/src/hint.ml 72.72% <ø> (ø)
analysis/src/utils.ml 54.21% <ø> (+0.32%) ⬆️
compiler/frontend/ast_tuple_pattern_flatten.ml 96.87% <100.00%> (+0.72%) ⬆️
compiler/frontend/ast_uncurry_gen.ml 95.23% <100.00%> (ø)
compiler/frontend/bs_builtin_ppx.ml 90.62% <100.00%> (+1.43%) ⬆️
compiler/ml/ast_async.ml 81.25% <ø> (-1.11%) ⬇️
compiler/ml/ast_helper.ml 78.18% <100.00%> (-0.56%) ⬇️
compiler/ml/ast_iterator.ml 93.17% <100.00%> (+0.39%) ⬆️
compiler/ml/ast_mapper.ml 76.38% <100.00%> (+0.92%) ⬆️
compiler/ml/ast_mapper_to0.ml 60.43% <100.00%> (+1.97%) ⬆️
... and 22 more

... and 4 files 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.

@cristianoc
cristianoc requested a review from cknitt August 20, 2026 16:20
@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@8575

@rescript/belt

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

@rescript/darwin-arm64

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

@rescript/darwin-x64

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

@rescript/linux-arm64

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

@rescript/linux-x64

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

@rescript/runtime

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

@rescript/win32-x64

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

commit: 403b094

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