Repository navigation
Conversation
Changelog💅 Polish
Semantic Diff3 commits · Full page Show existential types as $a and name their constructorbff79a6 · cknitt + Claude · Oct 27, 2026, 12:44 UTC
Diagnostic modified (existential escape) type rec any = Any('a): any
let get = (Any(x)) => x
-This has type: $Any_'a
+This has type: $a
But it's expected to have type: 'a
-The type constructor $Any_'a would escape its scope
+$a is an existential type bound by the constructor Any.
+It is only known in the scope of the pattern that matches Any.Review
Give distinct existential types distinct names2294674 · cknitt + Claude · Oct 27, 2026, 20:25 UTC Codex review on #9080: printing Diagnostic modified (existentials of two constructors) type rec any = First('a): any | Second('a): any
let same = (First(x), Second(y)) => x == y
-This has type: $a
+This has type: $a1
But it's being compared to something of type: $aKey existential constructors by identifierf56b61c · cknitt + Claude · Oct 27, 2026, 20:38 UTC Codex review on #9080: the constructor of each existential was recorded by its name, but the counter that makes names unique is reset for each binding, so a nested module's |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #9080 +/- ##
==========================================
+ Coverage 81.45% 81.52% +0.06%
==========================================
Files 460 460
Lines 64645 64659 +14
==========================================
+ Hits 52657 52713 +56
+ Misses 11988 11946 -42
🚀 New features to boost your workflow:
|
rescript
@rescript/belt
@rescript/darwin-arm64
@rescript/linux-arm64
@rescript/linux-x64
@rescript/runtime
@rescript/win32-x64
commit: |
|
Developer playground preview: https://rescript-lang.github.io/rescript/dev-playground/?version=pr-9080 |
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4bc31934fb
ℹ️ 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".
Codex review on #9080: printing `$C_'a` as `$a` made existentials of different constructors that bind the same variable print alike, so a mismatch between them read `$a` vs `$a`. Existentials are now named `$a` before the compiler makes the name unique, as OCaml 5 does, so the second one is `$a1`; the constructor binding each name is recorded for the escape explanation instead of being decoded from the name. Diagnostic modified (existentials of two constructors): Example: type rec any = First('a): any | Second('a): any let same = (First(x), Second(y)) => x == y Before (diagnostic): This has type: $a But it's being compared to something of type: $a After (diagnostic): This has type: $a1 But it's being compared to something of type: $a 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 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a757919c44
ℹ️ 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".
Codex review on #9080: the constructor of each existential was recorded by its name, but the counter that makes names unique is reset for each binding, so a nested module's `$a` could overwrite the constructor of an outer `$a`. It is recorded by the identifier's stamp 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>
|
@codex review |
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Why:
An existential type of a GADT constructor is an abstract type named
`$Any_'a` internally, and that name was printed as is in errors and
hover. It is now printed `$a`, as in OCaml 5, and the escape error
says which constructor binds it instead of calling it a type
constructor.
Diagnostic modified (existential escape):
Example:
type rec any = Any('a): any
let get = (Any(x)) => x
Before (diagnostic):
This has type: $Any_'a
But it's expected to have type: 'a
The type constructor $Any_'a would escape its scope
After (diagnostic):
This has type: $a
But it's expected to have type: 'a
$a is an existential type bound by the constructor Any.
It is only known in the scope of the pattern that matches Any.
Review: Why decode the name instead of recording the constructor?
The name already holds both parts, so printing needs no table that
would have to be reset between compilations in one process.
Fixes: #9068
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 #9080: printing `$C_'a` as `$a` made existentials of different constructors that bind the same variable print alike, so a mismatch between them read `$a` vs `$a`. Existentials are now named `$a` before the compiler makes the name unique, as OCaml 5 does, so the second one is `$a1`; the constructor binding each name is recorded for the escape explanation instead of being decoded from the name. Diagnostic modified (existentials of two constructors): Example: type rec any = First('a): any | Second('a): any let same = (First(x), Second(y)) => x == y Before (diagnostic): This has type: $a But it's being compared to something of type: $a After (diagnostic): This has type: $a1 But it's being compared to something of type: $a 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 #9080: the constructor of each existential was recorded by its name, but the counter that makes names unique is reset for each binding, so a nested module's `$a` could overwrite the constructor of an outer `$a`. It is recorded by the identifier's stamp 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>
9569e25 to
f56b61c
Compare
Fixes #9068.
Existential types of GADT constructors are printed
$ainstead of their internal name$Any_'a, in errors and in hover. An escaping one is explained by naming the constructor that binds it:Existentials are named
$abefore the compiler makes the name unique, as in OCaml 5, so two existentials binding the same variable print as$aand$a1. The constructor binding each name is recorded for the explanation.New fixtures
gadt_existential_escapeandgadt_existential_same_nameand analysis testHoverExistential.🤖 Generated with Claude Code
https://claude.ai/code/session_01Kbf3gLMawVgtmiKy3TMBc3