Skip to content

oparg_enum! to support custom display value#7654

Merged
youknowone merged 1 commit into
RustPython:mainfrom
ShaharNaveh:newtype-oparg-display-support
Apr 23, 2026
Merged

oparg_enum! to support custom display value#7654
youknowone merged 1 commit into
RustPython:mainfrom
ShaharNaveh:newtype-oparg-display-support

Conversation

@ShaharNaveh
Copy link
Copy Markdown
Contributor

@ShaharNaveh ShaharNaveh commented Apr 22, 2026

A reimplementation of #7489

Summary by CodeRabbit

  • Refactor
    • Instruction display now includes both numeric and descriptive operand values for clearer diagnostics.
    • Operator and constant labels consistently show human-friendly names or symbols in logs and debug output.
    • Redundant hand-written display logic replaced by generated, label-aware formatting to ensure consistency.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 22, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Refactors the oparg enum macro to accept labeled discriminants and auto-generate Display impls; converts several oparg enums to labeled tuple discriminants and removes manual Display impls. Also updates instruction formatting for Instruction::ConvertValue to print both numeric and typed operand forms.

Changes

Cohort / File(s) Summary
oparg macro & enums
crates/compiler-core/src/bytecode/oparg.rs
oparg_enum!/impl_oparg_enum! changed to accept token-tree discriminants ($value:tt) supporting Variant = N and Variant = (N, "label"); macro now derives numeric discriminants, generates as_u8/try_from_u8, and an auto core::fmt::Display that uses labels when present. Multiple enums (ConvertValueOparg, BinaryOperator, SpecialMethod, CommonConstant) updated to labeled tuple forms and their handwritten Display impls removed.
Instruction display update
crates/compiler-core/src/bytecode/instruction.rs
InstructionMetadata::fmt_dis for Instruction::ConvertValue { oparg } now decodes the typed operand into a local oparg and formats as CONVERT_VALUE <u8> (<typed_oparg>), including both raw numeric and typed representations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • youknowone

Poem

🐇 I hopped through macros late tonight,

I gave each variant a cozy, labeled light,
Numbers and names now dance in line,
I nibble bytes and make the enums fine,
A tiny rabbit cheering builds that shine.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: enhancing the oparg_enum! macro to support custom display values for variants.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/compiler-core/src/bytecode/instruction.rs`:
- Around line 1106-1109: The disassembly line for Self::ConvertValue { oparg }
is malformed because the format string writes the numeric operand immediately
after the opcode (producing "CONVERT_VALUE1 (str)"); update the write! call in
the Self::ConvertValue match arm (the write!(f, "...") inside that branch) to
put operands into the normal parenthesized form, e.g. change the format to
include a space and wrap the numeric operand in parentheses (use something like
"{:pad$} ({}) ({})" so the output becomes "CONVERT_VALUE (1) (str)").
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 52333198-e3d1-461b-8560-bbf8ceed29b4

📥 Commits

Reviewing files that changed from the base of the PR and between 5a45d41 and c51eac0.

📒 Files selected for processing (2)
  • crates/compiler-core/src/bytecode/instruction.rs
  • crates/compiler-core/src/bytecode/oparg.rs

Comment on lines +1106 to +1109
Self::ConvertValue { oparg } => {
let oparg = oparg.get(arg);
write!(f, "{:pad$}{} ({})", "CONVERT_VALUE", oparg.as_u8(), oparg)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix the malformed CONVERT_VALUE disassembly output.

Line 1108 currently concatenates the opcode and numeric operand, producing output like CONVERT_VALUE1 (str). Keep the operands inside the usual parenthesized format.

🐛 Proposed fix
             Self::ConvertValue { oparg } => {
                 let oparg = oparg.get(arg);
-                write!(f, "{:pad$}{} ({})", "CONVERT_VALUE", oparg.as_u8(), oparg)
+                write!(f, "{:pad$}({}, {})", "CONVERT_VALUE", oparg.as_u8(), oparg)
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Self::ConvertValue { oparg } => {
let oparg = oparg.get(arg);
write!(f, "{:pad$}{} ({})", "CONVERT_VALUE", oparg.as_u8(), oparg)
}
Self::ConvertValue { oparg } => {
let oparg = oparg.get(arg);
write!(f, "{:pad$}({}, {})", "CONVERT_VALUE", oparg.as_u8(), oparg)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/compiler-core/src/bytecode/instruction.rs` around lines 1106 - 1109,
The disassembly line for Self::ConvertValue { oparg } is malformed because the
format string writes the numeric operand immediately after the opcode (producing
"CONVERT_VALUE1 (str)"); update the write! call in the Self::ConvertValue match
arm (the write!(f, "...") inside that branch) to put operands into the normal
parenthesized form, e.g. change the format to include a space and wrap the
numeric operand in parentheses (use something like "{:pad$} ({}) ({})" so the
output becomes "CONVERT_VALUE (1) (str)").

@ShaharNaveh ShaharNaveh force-pushed the newtype-oparg-display-support branch from b5fa590 to 31078ac Compare April 22, 2026 09:41
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/compiler-core/src/bytecode/oparg.rs (1)

175-202: ⚠️ Potential issue | 🟠 Major

#[macro_export] on oparg_enum! will fail for external callers — helper macro is not exported.

oparg_enum! is marked #[macro_export] (line 175) but calls an un-exported helper macro impl_oparg_enum! on line 194 without a $crate:: path prefix. When invoked from another crate, name resolution for impl_oparg_enum! will fail at the expansion site.

This is not currently observable because the macro has no external users, but since it's part of the public API contract (via #[macro_export]), it must work cross-crate.

Apply one of these fixes:

  • Export the helper and route through $crate (recommended if this is intended as public API):
Fix: Export helper macro and use $crate path
 #[macro_export]
 macro_rules! oparg_enum {
     (
         $(#[$enum_meta:meta])*
         $vis:vis enum $name:ident {
             $(
                 $(#[$variant_meta:meta])*
                 $variant:ident = $value:tt
             ),* $(,)?
         }
     ) => {
         $(#[$enum_meta])*
         $vis enum $name {
             $(
                 $(#[$variant_meta:meta])*
                 $variant, // Do assign value to variant.
             )*
         }

-        impl_oparg_enum!(
+        $crate::impl_oparg_enum!(
             $vis enum $name {
                 $(
                     $variant = $value,
                 )*
             }
         );
     };
 }

+#[macro_export]
 macro_rules! impl_oparg_enum {
  • Remove #[macro_export] if this macro is only for internal use within this crate.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/compiler-core/src/bytecode/oparg.rs` around lines 175 - 202, The
oparg_enum! macro is #[macro_export] but calls the non-exported helper
impl_oparg_enum! which will break when used from other crates; fix it by
exporting the helper and invoking it through the crate-local path: add
#[macro_export] to impl_oparg_enum! (so it's available across crates) and change
the invocation inside oparg_enum! to call $crate::impl_oparg_enum!(...) instead
of impl_oparg_enum!(...) so macro name resolution works from external callers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@crates/compiler-core/src/bytecode/oparg.rs`:
- Around line 175-202: The oparg_enum! macro is #[macro_export] but calls the
non-exported helper impl_oparg_enum! which will break when used from other
crates; fix it by exporting the helper and invoking it through the crate-local
path: add #[macro_export] to impl_oparg_enum! (so it's available across crates)
and change the invocation inside oparg_enum! to call
$crate::impl_oparg_enum!(...) instead of impl_oparg_enum!(...) so macro name
resolution works from external callers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: bc3bbdc8-5692-41f3-a6b5-e8e6925ae05b

📥 Commits

Reviewing files that changed from the base of the PR and between c51eac0 and b5fa590.

📒 Files selected for processing (2)
  • crates/compiler-core/src/bytecode/instruction.rs
  • crates/compiler-core/src/bytecode/oparg.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/compiler-core/src/bytecode/instruction.rs

@ShaharNaveh ShaharNaveh force-pushed the newtype-oparg-display-support branch from 31078ac to 44a56f4 Compare April 22, 2026 09:58
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/compiler-core/src/bytecode/oparg.rs (1)

175-296: Macro extension LGTM — small indentation nit in the generated Display impl.

The labeled-variant approach ($value:tt + @discriminant / @display helpers) is clean and correctly handles both Variant = N and Variant = (N, "label"):

  • @discriminant yields an integer literal usable both as a match arm RHS in as_u8 and as a pattern in try_from_u8.
  • @display dispatches via ::core::fmt::Display::fmt, which preserves the formatter's format spec (width/alignment) — consistent with the docstring claim about format!("{:>10}", ...).

Minor nit: inside impl_oparg_enum!, the new impl ::core::fmt::Display for $name { ... } block (lines 275‑283) is indented with 4 spaces while the rest of the macro body uses 8 — cargo fmt will want this normalized. As per coding guidelines (**/*.rs: Follow the default rustfmt code style by running cargo fmt to format Rust code).

🔧 Proposed indentation fix
-    impl ::core::fmt::Display for $name {
-        fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
-            match self {
-                $(
-                    Self::$variant => impl_oparg_enum!(`@display` f, $value),
-                )*
-            }
-        }
-    }
-
+        impl ::core::fmt::Display for $name {
+            fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
+                match self {
+                    $(
+                        Self::$variant => impl_oparg_enum!(`@display` f, $value),
+                    )*
+                }
+            }
+        }
+
         impl OpArgType for $name {}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/compiler-core/src/bytecode/oparg.rs` around lines 175 - 296, The
Display impl inside the impl_oparg_enum! macro is indented inconsistently (4
spaces) compared to the surrounding macro body (8 spaces); update the
indentation of the block starting with impl ::core::fmt::Display for $name { ...
} so it matches the rest of the macro body (align with the other impl blocks
generated by impl_oparg_enum!), then run cargo fmt to normalize formatting;
ensure you adjust only spacing/indentation and keep the existing match arms that
call impl_oparg_enum!(`@display` ...) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/compiler-core/src/bytecode/oparg.rs`:
- Around line 175-296: The Display impl inside the impl_oparg_enum! macro is
indented inconsistently (4 spaces) compared to the surrounding macro body (8
spaces); update the indentation of the block starting with impl
::core::fmt::Display for $name { ... } so it matches the rest of the macro body
(align with the other impl blocks generated by impl_oparg_enum!), then run cargo
fmt to normalize formatting; ensure you adjust only spacing/indentation and keep
the existing match arms that call impl_oparg_enum!(`@display` ...) unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: a3f4fb88-05a6-4a37-ab38-db72a41e7511

📥 Commits

Reviewing files that changed from the base of the PR and between 31078ac and 44a56f4.

📒 Files selected for processing (2)
  • crates/compiler-core/src/bytecode/instruction.rs
  • crates/compiler-core/src/bytecode/oparg.rs

@ShaharNaveh ShaharNaveh force-pushed the newtype-oparg-display-support branch from 44a56f4 to ae2d1a4 Compare April 22, 2026 10:05
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
crates/compiler-core/src/bytecode/oparg.rs (3)

287-295: Macro arms look correct; minor robustness nit on numeric Display.

In @display $f:expr, $num:literal, the literal $num has no type annotation in this context, so &$num defaults to &i32. It happens to format identically for these small values, but if a future variant uses a non-i32-representable literal it will fail to compile here while @discriminant (used as u8) would succeed. Consider pinning the type so both arms agree:

Proposed tweak
-    (`@display` $f:expr, $num:literal) => {
-        ::core::fmt::Display::fmt(&$num, $f)
-    };
+    (`@display` $f:expr, $num:literal) => {
+        ::core::fmt::Display::fmt(&($num as u8), $f)
+    };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/compiler-core/src/bytecode/oparg.rs` around lines 287 - 295, The
`@display` macro arm uses &$num which defaults to &i32 and can mismatch
`@discriminant` (which is effectively u8); change the `@display` arm to pin the
literal to the same type as `@discriminant` (e.g., cast the literal to u8 before
formatting) so both arms agree on type; update the (`@display` $f:expr,
$num:literal) arm to format the literal as the same integer type used by
(`@discriminant`) to avoid future compile failures for non-i32-representable
literals.

312-314: Stale-ish NOTE: None still renders via the numeric branch as "0".

The comment says we should never reach Display for ConvertValueOparg::None, which is fine, but since the generated Display now silently prints "0" for it, any future misuse would produce a confusing disassembly rather than a visible error. Consider making the invariant explicit by labeling it (e.g. None = (0, "none")) or unreachable!()-ing in a dedicated Display override, so the assumption doesn't rot silently. Not blocking.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/compiler-core/src/bytecode/oparg.rs` around lines 312 - 314, The enum
variant ConvertValueOparg::None currently falls through to the numeric Display
branch and prints "0"; update the Display implementation for ConvertValueOparg
(the impl that formats opargs) to explicitly handle the None variant instead of
letting it hit the numeric fallback — either format it with an explicit label
like "none" or call unreachable!() (prefer unreachable!() if you want the
invariant to panic when violated); ensure you update the match arm for
ConvertValueOparg::None in the Display impl (and keep the note about
Instruction::FormatSimple handling FVC_NONE) so misuse surfaces immediately
rather than silently printing "0".

275-285: Consider future-proofing the nested macro call if oparg_enum! is ever exported.

The concern is valid: impl_oparg_enum! is a helper macro not meant for direct user calls, and it references $crate::marshal::MarshalError. If oparg_enum! were to become a #[macro_export]'d public macro, downstream crates would fail to resolve the nested impl_oparg_enum!(@discriminant ...) and similar calls (macro-by-example doesn't re-export helper macros automatically).

However, since both macros are currently internal to this crate and impl_oparg_enum! is not exposed as part of the public API, no immediate action is required. If these macros are planned for public export in the future, apply the suggested fix: mark impl_oparg_enum! with #[doc(hidden)] #[macro_export] and prefix the nested calls with $crate:: (e.g., $crate::impl_oparg_enum!(@discriminant $value)).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/compiler-core/src/bytecode/oparg.rs` around lines 275 - 285, The
nested helper macro impl_oparg_enum! used inside the impl for Display (and other
nested calls within oparg_enum!) should be made robust if oparg_enum! is ever
exported: mark impl_oparg_enum! with #[doc(hidden)] #[macro_export] and update
all internal invocations to use the $crate:: prefix (e.g., replace bare
impl_oparg_enum!(`@discriminant` ...) / impl_oparg_enum!(`@display` ...) calls with
$crate::impl_oparg_enum!(`@discriminant` ...) and
$crate::impl_oparg_enum!(`@display` ...)), so downstream crates can resolve the
helper when oparg_enum! is exported.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/compiler-core/src/bytecode/oparg.rs`:
- Around line 287-295: The `@display` macro arm uses &$num which defaults to &i32
and can mismatch `@discriminant` (which is effectively u8); change the `@display`
arm to pin the literal to the same type as `@discriminant` (e.g., cast the literal
to u8 before formatting) so both arms agree on type; update the (`@display`
$f:expr, $num:literal) arm to format the literal as the same integer type used
by (`@discriminant`) to avoid future compile failures for non-i32-representable
literals.
- Around line 312-314: The enum variant ConvertValueOparg::None currently falls
through to the numeric Display branch and prints "0"; update the Display
implementation for ConvertValueOparg (the impl that formats opargs) to
explicitly handle the None variant instead of letting it hit the numeric
fallback — either format it with an explicit label like "none" or call
unreachable!() (prefer unreachable!() if you want the invariant to panic when
violated); ensure you update the match arm for ConvertValueOparg::None in the
Display impl (and keep the note about Instruction::FormatSimple handling
FVC_NONE) so misuse surfaces immediately rather than silently printing "0".
- Around line 275-285: The nested helper macro impl_oparg_enum! used inside the
impl for Display (and other nested calls within oparg_enum!) should be made
robust if oparg_enum! is ever exported: mark impl_oparg_enum! with
#[doc(hidden)] #[macro_export] and update all internal invocations to use the
$crate:: prefix (e.g., replace bare impl_oparg_enum!(`@discriminant` ...) /
impl_oparg_enum!(`@display` ...) calls with $crate::impl_oparg_enum!(`@discriminant`
...) and $crate::impl_oparg_enum!(`@display` ...)), so downstream crates can
resolve the helper when oparg_enum! is exported.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 473014d9-b4c8-497b-b6cb-af9cfccb7ea0

📥 Commits

Reviewing files that changed from the base of the PR and between 44a56f4 and ae2d1a4.

📒 Files selected for processing (2)
  • crates/compiler-core/src/bytecode/instruction.rs
  • crates/compiler-core/src/bytecode/oparg.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/compiler-core/src/bytecode/instruction.rs

@ShaharNaveh ShaharNaveh requested a review from youknowone April 22, 2026 10:11
@youknowone youknowone merged commit f2f2017 into RustPython:main Apr 23, 2026
20 checks passed
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