Skip to content

Print types from applied functors in created interfaces - #9077

Open
cknitt wants to merge 3 commits into
masterfrom
fix-9065-create-interface-functor-types
Open

cknitt wants to merge 3 commits into
masterfrom
fix-9065-create-interface-functor-types

Conversation

@cknitt

@cknitt cknitt commented Oct 27, 2026

Copy link
Copy Markdown
Member

Fixes #9065.

Create interface copied each type declaration verbatim from the source file at the declaration's location. For a module created by applying a functor, or included from one, that location is inside the functor's body, possibly in another file. So the .resi got the unsubstituted body type or unrelated lines. Types declared outside the module being printed are now printed from the signature; local ones are still copied, keeping their attributes.

New analysis tests: CreateInterfaceFunctor (same file) and CreateInterfaceFunctorUse (functor from another file, module M = F(...) and include F(...)).

🤖 Generated with Claude Code

https://claude.ai/code/session_01Kbf3gLMawVgtmiKy3TMBc3

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Changelog

🐛 Bug fix

  • Editor "create interface" prints the types of applied functors and included modules instead of copying unrelated source lines.

Semantic Diff

3 commits · Full page

Print types from applied functors in created interfaces

a064592 · cknitt + Claude · Oct 27, 2026, 12:40 UTC

Why

Create interface copied each type declaration from the source file at the declaration's location. A type of an applied functor or of an included module is located in the functor's body, possibly in another file, so the interface got the unsubstituted body type or whatever lines of the current file happened to be there. Types declared elsewhere are now printed from the signature.

Diagnostic modified (create interface)

module StrSet = CreateInterfaceFunctor.MakeSet({
  type t = string
  let compare = (a: string, b) => a < b ? -1 : a > b ? 1 : 0
})

rescript · tests/analysis_tests/tests/src/CreateInterfaceFunctorUse.res

 module StrSet: {
-
+  type t = array<string>
   let add: (t, string) => array<string>
 }

Review

  • Are types declared in the module itself still copied verbatim? Yes. A type is copied when its location is in the source file and, inside a nested module, within that module's declaration, so attributes on local declarations are kept as before.
Copy same-file types outside functors verbatim in created interfaces

de88a9c · cknitt + Claude · Oct 27, 2026, 17:33 UTC

Codex review on #9077: a type of the same file reached through module type of or include was printed from the signature, which drops field attributes such as @as, so the interface no longer matched. Only types inside a functor body other than the module being printed, and types of other files, are printed from the signature now.

Print the runtime names of record fields from signatures

8a9ddb5 · cknitt + Claude · Oct 28, 2026, 07:39 UTC

Review on #9077: a type of an applied functor is printed from its signature, and the printed record dropped @as on its fields, so the created interface for module M = F({}) with type t = {@as("wire") field: int} in F's body didn't match. Record fields in the outcome tree now carry their runtime name, and the printer writes it as @as, which also shows it in hover and error messages.

Diagnostic modified (created interface of an applied functor)

module WithWire = (X: {}) => {
  type t = {@as("wire") field: int}
}

module Applied = WithWire({})

rescript

 module Applied: {
-  type t = {field: int}
+  type t = {@as("wire") field: int}
 }

@codecov

codecov Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.96970% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 81.46%. Comparing base (beb423d) to head (8a9ddb5).

Files with missing lines Patch % Lines
analysis/src/create_interface.ml 96.66% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master    #9077   +/-   ##
=======================================
  Coverage   81.45%   81.46%           
=======================================
  Files         460      460           
  Lines       64645    64664   +19     
=======================================
+ Hits        52657    52676   +19     
  Misses      11988    11988           
Files with missing lines Coverage Δ
analysis/src/cli.ml 80.30% <ø> (ø)
compiler/ml/printtyp.ml 71.99% <ø> (ø)
compiler/syntax/src/res_outcome_printer.ml 82.27% <100.00%> (+0.11%) ⬆️
analysis/src/create_interface.ml 88.00% <96.66%> (+1.20%) ⬆️
🚀 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 Oct 27, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

rescript

npm i https://pkg.pr.new/rescript@9077

@rescript/belt

npm i https://pkg.pr.new/@rescript/belt@9077

@rescript/darwin-arm64

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

@rescript/linux-arm64

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

@rescript/linux-x64

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

@rescript/runtime

npm i https://pkg.pr.new/@rescript/runtime@9077

@rescript/win32-x64

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

commit: 8a9ddb5

@github-actions

Copy link
Copy Markdown

@cknitt
cknitt marked this pull request as ready for review October 27, 2026 14:19
@cknitt

cknitt commented Oct 27, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-28T07:41:39.153785Z c6e8221 Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: 427fc4ecd5

ℹ️ 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 analysis/src/create_interface.ml
cknitt added a commit that referenced this pull request Oct 27, 2026
Codex review on #9077: a type of the same file reached through
`module type of` or `include` was printed from the signature, which drops
field attributes such as `@as`, so the interface no longer matched. Only
types inside a functor body other than the module being printed, and
types of other files, are printed from the signature now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kbf3gLMawVgtmiKy3TMBc3
Signed-off-by: Christoph Knittel <ck@cca.io>
@cknitt

cknitt commented Oct 27, 2026

Copy link
Copy Markdown
Member Author

@codex review

@cknitt
cknitt requested a review from cristianoc October 27, 2026 20:11

@cristianoc cristianoc left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved, with one remaining interface-generation case worth addressing:

module F = (X: {}) => {
  type t = {@as("wire") field: int}
}
module M = F({})

For the applied module M, the synthetic printer drops @as("wire"), producing {field: int} and a signature mismatch. The path is analysis/src/create_interface.ml:288–290 → Printtyp.tree_of_label, which omits ld_runtime_name; Includecore.compare_records checks that runtime name. The latest fix preserves annotations for same-file types outside functors, but this applied-functor case remains.

This is based on source inspection; I have not run the repro locally.

cknitt added a commit that referenced this pull request Oct 28, 2026
Review on #9077: a type of an applied functor is printed from its
signature, and the printed record dropped `@as` on its fields, so the
created interface for `module M = F({})` with `type t = {@as("wire")
field: int}` in F's body didn't match. Record fields in the outcome tree
now carry their runtime name, and the printer writes it as `@as`, which
also shows it in hover and error messages.

Diagnostic modified (created interface of an applied functor):
Example:
    module WithWire = (X: {}) => {
      type t = {@as("wire") field: int}
    }

    module Applied = WithWire({})
Before (rescript):
    module Applied: {
      type t = {field: int}
    }
After (rescript):
    module Applied: {
      type t = {@as("wire") field: int}
    }

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kbf3gLMawVgtmiKy3TMBc3
Signed-off-by: Christoph Knittel <ck@cca.io>
@cknitt

cknitt commented Oct 28, 2026

Copy link
Copy Markdown
Member Author

Thanks, confirmed and fixed in c6e8221. Record fields in the outcome tree now carry their runtime name, and the outcome printer writes it as @as("…"), so module M = F({}) with type t = {@as("wire") field: int} in F's body gets type t = {@as("wire") field: int} in the created interface. CreateInterfaceFunctor.res has the case. The same printer is used by hover and error messages, which now show the runtime names too; the only other snapshot change is a JsxDOM.domProps hover listing its @as("aria-…") fields.

@cknitt

cknitt commented Oct 28, 2026

Copy link
Copy Markdown
Member Author

@codex review

@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: c6e822102e

ℹ️ 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 analysis/src/create_interface.ml
cknitt and others added 3 commits October 28, 2026 07:48
Why:
    Create interface copied each type declaration from the source file
    at the declaration's location. A type of an applied functor or of an
    included module is located in the functor's body, possibly in
    another file, so the interface got the unsubstituted body type or
    whatever lines of the current file happened to be there. Types
    declared elsewhere are now printed from the signature.

Diagnostic modified (create interface):
Example:
    module StrSet = CreateInterfaceFunctor.MakeSet({
      type t = string
      let compare = (a: string, b) => a < b ? -1 : a > b ? 1 : 0
    })
Before (rescript): tests/analysis_tests/tests/src/CreateInterfaceFunctorUse.res
    module StrSet: {

      let add: (t, string) => array<string>
    }
After (rescript): tests/analysis_tests/tests/src/CreateInterfaceFunctorUse.res
    module StrSet: {
      type t = array<string>
      let add: (t, string) => array<string>
    }

Review: Are types declared in the module itself still copied verbatim?
    Yes. A type is copied when its location is in the source file and,
    inside a nested module, within that module's declaration, so
    attributes on local declarations are kept as before.

Fixes: #9065
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kbf3gLMawVgtmiKy3TMBc3
Signed-off-by: Christoph Knittel <ck@cca.io>
Codex review on #9077: a type of the same file reached through
`module type of` or `include` was printed from the signature, which drops
field attributes such as `@as`, so the interface no longer matched. Only
types inside a functor body other than the module being printed, and
types of other files, are printed from the signature now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kbf3gLMawVgtmiKy3TMBc3
Signed-off-by: Christoph Knittel <ck@cca.io>
Review on #9077: a type of an applied functor is printed from its
signature, and the printed record dropped `@as` on its fields, so the
created interface for `module M = F({})` with `type t = {@as("wire")
field: int}` in F's body didn't match. Record fields in the outcome tree
now carry their runtime name, and the printer writes it as `@as`, which
also shows it in hover and error messages.

Diagnostic modified (created interface of an applied functor):
Example:
    module WithWire = (X: {}) => {
      type t = {@as("wire") field: int}
    }

    module Applied = WithWire({})
Before (rescript):
    module Applied: {
      type t = {field: int}
    }
After (rescript):
    module Applied: {
      type t = {@as("wire") field: int}
    }

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kbf3gLMawVgtmiKy3TMBc3
Signed-off-by: Christoph Knittel <ck@cca.io>
@cknitt
cknitt force-pushed the fix-9065-create-interface-functor-types branch from c6e8221 to 8a9ddb5 Compare October 28, 2026 08:10
@cknitt cknitt mentioned this pull request Oct 28, 2026
3 of 12 tasks
@cknitt
cknitt enabled auto-merge (squash) October 28, 2026 08:28

This branch has not been deployed

No deployments
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.

Create interface breaks types of applied functors and include F(...)

2 participants