Repository navigation
Check variants with some @unboxed constructors like untagged ones - #9021
Conversation
Why:
The checks that keep the cases of an untagged variant apart ran only
when the type was `@unboxed`. A variant with `@unboxed` on some
constructors could have two number cases, an unknown payload beside
another, or an untagged object beside a tagged block, and its matches
then picked the wrong case (#9020). The `@as` of an untagged case was
meanwhile compared with tags, which it does not set.
The payload kinds are checked as soon as one case is untagged, tagged
blocks count as one object case, and only tagged cases' tags are compared
for duplicates.
Diagnostic added (two number cases in a mixed variant):
Example:
type t = | @unboxed A(int) | @unboxed B(int) | C
Before (diagnostic): none; `B(5)` matches `A`
After (diagnostic):
This untagged variant definition is invalid: At most one case can be a number type (int or float).
Diagnostic added (untagged object beside a tagged block):
Example:
type t = | @unboxed A({x: int}) | B({y: int}) | C
Before (diagnostic): none; `A({x: 1})` matches `B`
After (diagnostic):
This untagged variant definition is invalid: At most one case can be an object type.
Diagnostic removed (an untagged case's @as):
Example:
type t = | @unboxed @as("x") A(int) | @as("x") B({y: int}) | C
Before (diagnostic):
This untagged variant definition is invalid: Duplicate literal x.
After (diagnostic): none
Fixes #9020
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CMkrYaktctdKc4M41WF36t
Signed-off-by: Christoph Knittel <ck@cca.io>
Changelog🐛 Bug fix
Semantic Diff1 commit · Full page Check variants with some
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #9021 +/- ##
=======================================
Coverage 81.31% 81.31%
=======================================
Files 456 456
Lines 64003 64010 +7
=======================================
+ Hits 52044 52052 +8
+ Misses 11959 11958 -1
🚀 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-9021 |
|
@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 |
|
Codex Review: Didn't find any major issues. Delightful! 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:
The checks that keep the cases of an untagged variant apart ran only
when the type was `@unboxed`. A variant with `@unboxed` on some
constructors could have two number cases, an unknown payload beside
another, or an untagged object beside a tagged block, and its matches
then picked the wrong case (#9020). The `@as` of an untagged case was
meanwhile compared with tags, which it does not set.
The payload kinds are checked as soon as one case is untagged, tagged
blocks count as one object case, and only tagged cases' tags are compared
for duplicates.
Diagnostic added (two number cases in a mixed variant):
Example:
type t = | @unboxed A(int) | @unboxed B(int) | C
Before (diagnostic): none; `B(5)` matches `A`
After (diagnostic):
This untagged variant definition is invalid: At most one case can be a number type (int or float).
Diagnostic added (untagged object beside a tagged block):
Example:
type t = | @unboxed A({x: int}) | B({y: int}) | C
Before (diagnostic): none; `A({x: 1})` matches `B`
After (diagnostic):
This untagged variant definition is invalid: At most one case can be an object type.
Diagnostic removed (an untagged case's @as):
Example:
type t = | @unboxed @as("x") A(int) | @as("x") B({y: int}) | C
Before (diagnostic):
This untagged variant definition is invalid: Duplicate literal x.
After (diagnostic): none
The same fix as #9021 on master, for the stack's check_invariant; rule 6
says so.
Fixes #9020
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CMkrYaktctdKc4M41WF36t
Signed-off-by: Christoph Knittel <ck@cca.io>
cristianoc
left a comment
There was a problem hiding this comment.
I guess @unboxed on single cases should go.
Now seems redundant. It was needed when we did not have untagged variants.
#9021 checks a variant with some `@unboxed` constructors like an untagged one: tagged blocks count as one object case, and an untagged case's `@as` is not a tag. Rule 6 now says so and names its tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CMkrYaktctdKc4M41WF36t Signed-off-by: Christoph Knittel <ck@cca.io>
Fixes #9020.
A variant whose type isn't
@unboxed, but which has@unboxedon some of its constructors, skipped the checks that keep untagged cases apart.check_invariantran them only for@unboxedtypes. Three wrong declarations compiled, and their matches picked the wrong case:Meanwhile, the
@asof an untagged case was compared with the tags of tagged cases, although it doesn't set one.Now:
New tests:
untagged_mixed_two_numbers.res,untagged_mixed_unknown_payload.resanduntagged_mixed_object_and_tagged.res(each now an error);untagged_mixed_test.res: an untagged case's@asequal to a tagged case's tag compiles and matches correctly.Found by a review of the untagged variant work (#8950).
🤖 Generated with Claude Code
https://claude.ai/code/session_01CMkrYaktctdKc4M41WF36t