Repository navigation
Keep @tag and runtime annotations when printing a type declaration - #9136
Conversation
Changelog🐛 Bug fix
Semantic Diff3 commits · Full page Keep
|
d7ddc65 to
bef0fe8
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #9136 +/- ##
=======================================
Coverage 81.69% 81.70%
=======================================
Files 460 460
Lines 64855 64877 +22
=======================================
+ Hits 52984 53008 +24
+ Misses 11871 11869 -2
🚀 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-9136 |
|
@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. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bef0fe85a2
ℹ️ 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".
Why:
The printer of type declarations kept only @Immediate and @unboxed.
@tag, @notundefined, @instanceof and @typeof were dropped, so a
signature mismatch about them printed two declarations that looked the
same, hover hid them, and createInterface wrote an interface for an
applied functor that does not match its implementation (#9134).
Diagnostic modified (@tag mismatch):
Example:
// Foo.res
@tag("type")
type t =
| @as("a") A
| B
// Foo.resi
@tag("kind")
type t =
| @as("a") A
| B
Before (diagnostic):
Actual declaration (Foo.res:2:1-4:5):
type t = @as("a") A | B
Expected declaration (Foo.resi:2:1-4:5):
type t = @as("a") A | B
Their @tag annotations differ.
After (diagnostic):
Actual declaration (Foo.res:2:1-4:5):
@tag("type") type t = @as("a") A | B
Expected declaration (Foo.resi:2:1-4:5):
@tag("kind") type t = @as("a") A | B
Their @tag annotations differ.
Diagnostic modified (@notundefined functor parameter):
Example:
module Make = (
X: {
@notundefined type t
},
) => {
type u = X.t
}
module Applied = Make({
type t = option<int>
})
Before (diagnostic):
Actual declaration (not_undefined_functor_argument.res:10:3-22):
type t = option<int>
Expected declaration (not_undefined_functor_argument.res:3:19-24):
type t
Their runtime representations differ:
Actual declaration: can hold undefined
Expected declaration: @notundefined
After (diagnostic):
Actual declaration (not_undefined_functor_argument.res:10:3-22):
type t = option<int>
Expected declaration (not_undefined_functor_argument.res:3:19-24):
@notundefined type t
Their runtime representations differ:
Actual declaration: can hold undefined
Expected declaration: @notundefined
Format modified (createInterface for an applied functor):
Example:
module Tagged = (X: Type) => {
@tag("kind") type wrapped = Value({value: X.t}) | Empty({reason: string})
}
module IntTagged = Tagged({
type t = int
})
Before (rescript): the interface does not compile against the implementation
module IntTagged: {
type wrapped = Value({value: int}) | Empty({reason: string})
}
After (rescript):
module IntTagged: {
@tag("kind") type wrapped = Value({value: int}) | Empty({reason: string})
}
Representation modified (printed declaration annotations, Printtyp.tree_of_type_decl):
Before (representation):
otype_immediate: bool ↦ @Immediate
otype_unboxed: bool ↦ @unboxed
After (representation):
otype_attributes: string list ↦ @Immediate @unboxed @tag("…") @notundefined | @instanceof("…") | @typeof("…")
source: what the declaration itself states, not what it inherits from an abbreviated type
Review: Why read the attributes rather than the declaration's runtime shape? The shape of an abbreviation can come from the type it abbreviates; the printed declaration should show what it states itself, as the source does.
Review: Can printing raise for a malformed annotation? No. The annotations are parsed by the functions that typing uses, which raise on malformed payloads; those were reported when the declaration was typed, and the printer then leaves the annotation out.
Fixes: #9134
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kbf3gLpf7RN1MiRcubPgRn
Signed-off-by: Christoph Knittel <ck@cca.io>
Why:
With the annotations printed, two declarations can still read the same
and not match, when a type they mention differs between the two sides,
e.g. a base class that the interface leaves abstract. The error then
showed the same text twice, which reads as a bug in the compiler. The
reasons now start with a note saying so, which replaces the lead-in of a
difference in runtime representation.
Diagnostic modified (declarations that print the same):
Example:
// Classes.res
@instanceof("Animal") type animal
@instanceof("Dog") type dog = private animal
// Classes.resi
type animal
@instanceof("Dog") type dog = private animal
Before (diagnostic):
Actual declaration (Classes.res:2:20-44):
@instanceof("Dog") type dog = private animal
Expected declaration (Classes.resi:2:20-44):
@instanceof("Dog") type dog = private animal
Their runtime representations differ:
Actual declaration: instances of Dog, a subclass of Animal
Expected declaration: instances of Dog
After (diagnostic):
Actual declaration (Classes.res:2:20-44):
@instanceof("Dog") type dog = private animal
Expected declaration (Classes.resi:2:20-44):
@instanceof("Dog") type dog = private animal
The declarations read the same, but a type they mention differs:
Actual declaration: instances of Dog, a subclass of Animal
Expected declaration: instances of Dog
Review: Why compare the printed text? It is what the reader sees, and the case to catch is exactly two declarations that look the same.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kbf3gLpf7RN1MiRcubPgRn
Signed-off-by: Christoph Knittel <ck@cca.io>
db65f47 to
922b663
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. Breezy! 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". |
Codex review of #9136: the printed @tag put the decoded name between quotes as it is, so a tag with a quote printed as invalid source and a backslash changed its value when reparsed, also in interfaces written by createInterface. It is now encoded as a string literal, which keeps non-ASCII letters as they are. Diagnostic modified (@tag names with a quote, a backslash and a non-ASCII letter): Example: module M: { @tag("k\"ind") type t = A({x: int}) | B({y: int}) } = { @tag("typ\\é") type t = A({x: int}) | B({y: int}) } Before (diagnostic): Actual declaration (tag_name_escaped.res:6:18-51): @tag("typ\é") type t = A({x: int}) | B({y: int}) Expected declaration (tag_name_escaped.res:4:18-51): @tag("k"ind") type t = A({x: int}) | B({y: int}) After (diagnostic): Actual declaration (tag_name_escaped.res:6:18-51): @tag("typ\\é") type t = A({x: int}) | B({y: int}) Expected declaration (tag_name_escaped.res:4:18-51): @tag("k\"ind") type t = A({x: int}) | B({y: int}) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kbf3gLpf7RN1MiRcubPgRn Signed-off-by: Christoph Knittel <ck@cca.io>
|
@codex review |
|
Codex Review: Didn't find any major issues. Bravo. 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". |
Fixes #9134.
Printtyp.tree_of_type_declpassed on only@immediateand@unboxed. The other annotations of a declaration,@tag,@notUndefined,@instanceOfand@typeOf, were dropped wherever a declaration was printed:@tag, both sides looked the same next to "Their @tag annotations differ."type wrapped = …without@tag("kind")for a type of an applied functor, and the generated interface did not compile against its implementation.@notUndefined type Jsx.elementnow shows its annotation).The printed declaration now carries a list of annotations (
otype_attributes) in place of the two booleans, filled from what the declaration itself states, andRes_outcome_printerprints them beforetype.New test:
CreateInterfaceFunctor.res/CreateInterfaceFunctorUse.res(analysis tests) apply a functor with a@tagtype, and the generated interface keeps it. The changed error snapshots show the annotations on the expected and actual declarations.With the annotations printed, two declarations can still read the same and not match, when a type they mention differs between the two sides, e.g. a base class that the interface leaves abstract. The reasons then start with a note that replaces the lead-in of a difference in runtime representation:
This is the bottom of a stack with #9133 on top.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Kbf3gLpf7RN1MiRcubPgRn