From deefe91de2064114ba5e1264131ea19c228174e9 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 12:10:32 +0200 Subject: [PATCH 01/17] Generate optimized oparg enums --- crates/compiler-core/src/bytecode/oparg.rs | 676 ++++++++++----------- 1 file changed, 337 insertions(+), 339 deletions(-) diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index 7d2fca03988..6aaf8dca169 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -1,5 +1,4 @@ use bitflags::bitflags; -use num_enum::{IntoPrimitive, TryFromPrimitive}; use core::fmt; @@ -104,11 +103,75 @@ impl OpArgState { } } -macro_rules! impl_oparg_enum_traits { - ($name:ty) => { - impl From<$name> for u32 { - fn from(value: $name) -> Self { - Self::from(u8::from(value)) +/// Helper macro for defining oparg enums in an optimal way. +/// +/// Will generate the following: +/// +/// - Enum which variant's aren't assigned any value (for optimizations). +/// - impl [`TryFrom`] +/// - impl [`TryFrom`] +/// - impl [`Into`] +/// - impl [`Into`] +/// - impl [`OpArgType`] +/// +/// # Examples +/// +/// ```rust +/// oparg_enum!( +/// /// Oparg for the `X` opcode. +/// #[derive(Clone, Copy)] +/// pub enum MyOpArg { +/// /// Some doc. +/// Foo = 0, +/// Bar = 2, +/// Baz = 5, +/// } +/// ); +/// ``` +macro_rules! oparg_enum { + ( + $(#[$attr:meta])* + $vis:vis enum $name:ident { + $( + $(#[$var_attr:meta])* + $var:ident = $value:literal, + )* + } + ) => { + $(#[$attr])* + $vis enum $name { + $( + $(#[$var_attr])* + $var, // Do assign value to variant. + )* + } + + impl_oparg_enum!( + enum $name { + $( + $var = $value, + )* + } + ); + }; +} + +macro_rules! impl_oparg_enum { + ( + enum $name:ident { + $( + $var:ident = $value:literal, + )* + } + ) => { + impl TryFrom for $name { + type Error = $crate::marshal::MarshalError; + + fn try_from(value: u8) -> Result { + Ok(match value { + $($value => Self::$var,)* + _ => return Err(Self::Error::InvalidBytecode), + }) } } @@ -121,51 +184,64 @@ macro_rules! impl_oparg_enum_traits { .map(TryInto::try_into)? } } + + impl From<$name> for u8 { + fn from(value: $name) -> Self { + match value { + $($name::$var => $value,)* + } + } + } + + impl From<$name> for u32 { + fn from(value: $name) -> Self { + Self::from(u8::from(value)) + } + } + + impl OpArgType for $name {} }; } -/// Oparg values for [`Instruction::ConvertValue`]. -/// -/// ## See also -/// -/// - [CPython FVC_* flags](https://github.com/python/cpython/blob/8183fa5e3f78ca6ab862de7fb8b14f3d929421e0/Include/ceval.h#L129-L132) -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, Hash, IntoPrimitive, PartialEq, TryFromPrimitive)] -#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))] -pub enum ConvertValueOparg { - /// No conversion. +oparg_enum!( + /// Oparg values for [`Instruction::ConvertValue`]. /// - /// ```python - /// f"{x}" - /// f"{x:4}" - /// ``` - // Ruff `ConversionFlag::None` is `-1i8`, when its converted to `u8` its value is `u8::MAX`. - #[num_enum(alternatives = [255])] - None = 0, - /// Converts by calling `str()`. + /// ## See also /// - /// ```python - /// f"{x!s}" - /// f"{x!s:2}" - /// ``` - Str = 1, - /// Converts by calling `repr()`. - /// - /// ```python - /// f"{x!r}" - /// f"{x!r:2}" - /// ``` - Repr = 2, - /// Converts by calling `ascii()`. - /// - /// ```python - /// f"{x!a}" - /// f"{x!a:2}" - /// ``` - Ascii = 3, -} - -impl_oparg_enum_traits!(ConvertValueOparg); + /// - [CPython FVC_* flags](https://github.com/python/cpython/blob/8183fa5e3f78ca6ab862de7fb8b14f3d929421e0/Include/ceval.h#L129-L132) + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + pub enum ConvertValueOparg { + /// No conversion. + /// + /// ```python + /// f"{x}" + /// f"{x:4}" + /// ``` + // Ruff `ConversionFlag::None` is `-1i8`, when its converted to `u8` its value is `u8::MAX`. + None = 0, + /// Converts by calling `str()`. + /// + /// ```python + /// f"{x!s}" + /// f"{x!s:2}" + /// ``` + Str = 1, + /// Converts by calling `repr()`. + /// + /// ```python + /// f"{x!r}" + /// f"{x!r:2}" + /// ``` + Repr = 2, + /// Converts by calling `ascii()`. + /// + /// ```python + /// f"{x!a}" + /// f"{x!a:2}" + /// ``` + Ascii = 3, + } +); impl fmt::Display for ConvertValueOparg { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -181,23 +257,20 @@ impl fmt::Display for ConvertValueOparg { } } -impl OpArgType for ConvertValueOparg {} - -/// Resume type for the RESUME instruction -#[repr(u8)] -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, IntoPrimitive, TryFromPrimitive)] -#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))] -pub enum ResumeType { - AtFuncStart = 0, - AfterYield = 1, - AfterYieldFrom = 2, - AfterAwait = 3, -} +oparg_enum!( + /// Resume type for the RESUME instruction + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] + pub enum ResumeType { + AtFuncStart = 0, + AfterYield = 1, + AfterYieldFrom = 2, + AfterAwait = 3, + } +); pub type NameIdx = u32; impl OpArgType for u32 {} -//impl OpArgType for bool {} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] #[repr(transparent)] @@ -229,73 +302,64 @@ impl fmt::Display for Label { } } -/// The kind of Raise that occurred. -#[repr(u8)] -#[derive(Copy, Clone, Debug, PartialEq, TryFromPrimitive, IntoPrimitive, Eq)] -#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))] -pub enum RaiseKind { - /// Bare `raise` statement with no arguments. - /// Gets the current exception from VM state (topmost_exception). - /// Maps to RAISE_VARARGS with oparg=0. - BareRaise = 0, - /// `raise exc` - exception is on the stack. - /// Maps to RAISE_VARARGS with oparg=1. - Raise = 1, - /// `raise exc from cause` - exception and cause are on the stack. - /// Maps to RAISE_VARARGS with oparg=2. - RaiseCause = 2, - /// Reraise exception from the stack top. - /// Used in exception handler cleanup blocks (finally, except). - /// Gets exception from stack, not from VM state. - /// Maps to the RERAISE opcode. - ReraiseFromStack = 3, -} - -impl_oparg_enum_traits!(RaiseKind); -impl OpArgType for RaiseKind {} - -/// Intrinsic function for CALL_INTRINSIC_1 -#[repr(u8)] -#[derive(Copy, Clone, Debug, PartialEq, Eq, IntoPrimitive, TryFromPrimitive)] -#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))] -pub enum IntrinsicFunction1 { - // Invalid = 0, - Print = 1, - /// Import * operation - ImportStar = 2, - /// Convert StopIteration to RuntimeError in async context - StopIterationError = 3, - AsyncGenWrap = 4, - UnaryPositive = 5, - /// Convert list to tuple - ListToTuple = 6, - /// Type parameter related - TypeVar = 7, - ParamSpec = 8, - TypeVarTuple = 9, - /// Generic subscript for PEP 695 - SubscriptGeneric = 10, - TypeAlias = 11, -} - -impl_oparg_enum_traits!(IntrinsicFunction1); -impl OpArgType for IntrinsicFunction1 {} - -/// Intrinsic function for CALL_INTRINSIC_2 -#[repr(u8)] -#[derive(Copy, Clone, Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] -#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))] -pub enum IntrinsicFunction2 { - PrepReraiseStar = 1, - TypeVarWithBound = 2, - TypeVarWithConstraint = 3, - SetFunctionTypeParams = 4, - /// Set default value for type parameter (PEP 695) - SetTypeparamDefault = 5, -} - -impl_oparg_enum_traits!(IntrinsicFunction2); -impl OpArgType for IntrinsicFunction2 {} +oparg_enum!( + /// The kind of Raise that occurred. + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + pub enum RaiseKind { + /// Bare `raise` statement with no arguments. + /// Gets the current exception from VM state (topmost_exception). + /// Maps to RAISE_VARARGS with oparg=0. + BareRaise = 0, + /// `raise exc` - exception is on the stack. + /// Maps to RAISE_VARARGS with oparg=1. + Raise = 1, + /// `raise exc from cause` - exception and cause are on the stack. + /// Maps to RAISE_VARARGS with oparg=2. + RaiseCause = 2, + /// Reraise exception from the stack top. + /// Used in exception handler cleanup blocks (finally, except). + /// Gets exception from stack, not from VM state. + /// Maps to the RERAISE opcode. + ReraiseFromStack = 3, + } +); + +oparg_enum!( + /// Intrinsic function for CALL_INTRINSIC_1 + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + pub enum IntrinsicFunction1 { + // Invalid = 0, + Print = 1, + /// Import * operation + ImportStar = 2, + /// Convert StopIteration to RuntimeError in async context + StopIterationError = 3, + AsyncGenWrap = 4, + UnaryPositive = 5, + /// Convert list to tuple + ListToTuple = 6, + /// Type parameter related + TypeVar = 7, + ParamSpec = 8, + TypeVarTuple = 9, + /// Generic subscript for PEP 695 + SubscriptGeneric = 10, + TypeAlias = 11, + } +); + +oparg_enum!( + /// Intrinsic function for CALL_INTRINSIC_2 + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + pub enum IntrinsicFunction2 { + PrepReraiseStar = 1, + TypeVarWithBound = 2, + TypeVarWithConstraint = 3, + SetFunctionTypeParams = 4, + /// Set default value for type parameter (PEP 695) + SetTypeparamDefault = 5, + } +); bitflags! { #[derive(Copy, Clone, Debug, PartialEq)] @@ -326,95 +390,92 @@ impl From for u32 { impl OpArgType for MakeFunctionFlags {} -/// The possible comparison operators. -#[repr(u8)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] -#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))] -pub enum ComparisonOperator { - // be intentional with bits so that we can do eval_ord with just a bitwise and - // bits: | Equal | Greater | Less | - Less = 0b001, - Greater = 0b010, - NotEqual = 0b011, - Equal = 0b100, - LessOrEqual = 0b101, - GreaterOrEqual = 0b110, -} - -impl_oparg_enum_traits!(ComparisonOperator); -impl OpArgType for ComparisonOperator {} - -/// The possible Binary operators -/// -/// # Examples -/// -/// ```rust -/// use rustpython_compiler_core::bytecode::{Arg, BinaryOperator, Instruction}; -/// let (op, _) = Arg::new(BinaryOperator::Add); -/// let instruction = Instruction::BinaryOp { op }; -/// ``` -/// -/// See also: -/// - [_PyEval_BinaryOps](https://github.com/python/cpython/blob/8183fa5e3f78ca6ab862de7fb8b14f3d929421e0/Python/ceval.c#L316-L343) -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] -#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))] -pub enum BinaryOperator { - /// `+` - Add = 0, - /// `&` - And = 1, - /// `//` - FloorDivide = 2, - /// `<<` - Lshift = 3, - /// `@` - MatrixMultiply = 4, - /// `*` - Multiply = 5, - /// `%` - Remainder = 6, - /// `|` - Or = 7, - /// `**` - Power = 8, - /// `>>` - Rshift = 9, - /// `-` - Subtract = 10, - /// `/` - TrueDivide = 11, - /// `^` - Xor = 12, - /// `+=` - InplaceAdd = 13, - /// `&=` - InplaceAnd = 14, - /// `//=` - InplaceFloorDivide = 15, - /// `<<=` - InplaceLshift = 16, - /// `@=` - InplaceMatrixMultiply = 17, - /// `*=` - InplaceMultiply = 18, - /// `%=` - InplaceRemainder = 19, - /// `|=` - InplaceOr = 20, - /// `**=` - InplacePower = 21, - /// `>>=` - InplaceRshift = 22, - /// `-=` - InplaceSubtract = 23, - /// `/=` - InplaceTrueDivide = 24, - /// `^=` - InplaceXor = 25, - /// `[]` subscript - Subscr = 26, -} +oparg_enum!( + /// The possible comparison operators. + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + pub enum ComparisonOperator { + // be intentional with bits so that we can do eval_ord with just a bitwise and + // bits: | Equal | Greater | Less | + Less = 0b001, + Greater = 0b010, + NotEqual = 0b011, + Equal = 0b100, + LessOrEqual = 0b101, + GreaterOrEqual = 0b110, + } +); + +oparg_enum!( + /// The possible Binary operators + /// + /// # Examples + /// + /// ```rust + /// use rustpython_compiler_core::bytecode::{Arg, BinaryOperator, Instruction}; + /// let (op, _) = Arg::new(BinaryOperator::Add); + /// let instruction = Instruction::BinaryOp { op }; + /// ``` + /// + /// See also: + /// - [_PyEval_BinaryOps](https://github.com/python/cpython/blob/8183fa5e3f78ca6ab862de7fb8b14f3d929421e0/Python/ceval.c#L316-L343) + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub enum BinaryOperator { + /// `+` + Add = 0, + /// `&` + And = 1, + /// `//` + FloorDivide = 2, + /// `<<` + Lshift = 3, + /// `@` + MatrixMultiply = 4, + /// `*` + Multiply = 5, + /// `%` + Remainder = 6, + /// `|` + Or = 7, + /// `**` + Power = 8, + /// `>>` + Rshift = 9, + /// `-` + Subtract = 10, + /// `/` + TrueDivide = 11, + /// `^` + Xor = 12, + /// `+=` + InplaceAdd = 13, + /// `&=` + InplaceAnd = 14, + /// `//=` + InplaceFloorDivide = 15, + /// `<<=` + InplaceLshift = 16, + /// `@=` + InplaceMatrixMultiply = 17, + /// `*=` + InplaceMultiply = 18, + /// `%=` + InplaceRemainder = 19, + /// `|=` + InplaceOr = 20, + /// `**=` + InplacePower = 21, + /// `>>=` + InplaceRshift = 22, + /// `-=` + InplaceSubtract = 23, + /// `/=` + InplaceTrueDivide = 24, + /// `^=` + InplaceXor = 25, + /// `[]` subscript + Subscr = 26, + } +); impl BinaryOperator { /// Get the "inplace" version of the operator. @@ -449,9 +510,6 @@ impl BinaryOperator { } } -impl_oparg_enum_traits!(BinaryOperator); -impl OpArgType for BinaryOperator {} - impl fmt::Display for BinaryOperator { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let op = match self { @@ -487,43 +545,37 @@ impl fmt::Display for BinaryOperator { } } -/// Whether or not to invert the operation. -#[repr(u8)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] -#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))] -pub enum Invert { - /// ```py - /// foo is bar - /// x in lst - /// ``` - No = 0, - /// ```py - /// foo is not bar - /// x not in lst - /// ``` - Yes = 1, -} - -impl_oparg_enum_traits!(Invert); -impl OpArgType for Invert {} - -/// Special method for LOAD_SPECIAL opcode (context managers). -#[repr(u8)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] -#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))] -pub enum SpecialMethod { - /// `__enter__` for sync context manager - Enter = 0, - /// `__exit__` for sync context manager - Exit = 1, - /// `__aenter__` for async context manager - AEnter = 2, - /// `__aexit__` for async context manager - AExit = 3, -} - -impl_oparg_enum_traits!(SpecialMethod); -impl OpArgType for SpecialMethod {} +oparg_enum!( + /// Whether or not to invert the operation. + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + pub enum Invert { + /// ```py + /// foo is bar + /// x in lst + /// ``` + No = 0, + /// ```py + /// foo is not bar + /// x not in lst + /// ``` + Yes = 1, + } +); + +oparg_enum!( + /// Special method for LOAD_SPECIAL opcode (context managers). + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + pub enum SpecialMethod { + /// `__enter__` for sync context manager + Enter = 0, + /// `__exit__` for sync context manager + Exit = 1, + /// `__aenter__` for async context manager + AEnter = 2, + /// `__aexit__` for async context manager + AExit = 3, + } +); impl fmt::Display for SpecialMethod { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -537,26 +589,23 @@ impl fmt::Display for SpecialMethod { } } -/// Common constants for LOAD_COMMON_CONSTANT opcode. -/// pycore_opcode_utils.h CONSTANT_* -#[repr(u8)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] -#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))] -pub enum CommonConstant { - /// `AssertionError` exception type - AssertionError = 0, - /// `NotImplementedError` exception type - NotImplementedError = 1, - /// Built-in `tuple` type - BuiltinTuple = 2, - /// Built-in `all` function - BuiltinAll = 3, - /// Built-in `any` function - BuiltinAny = 4, -} - -impl_oparg_enum_traits!(CommonConstant); -impl OpArgType for CommonConstant {} +oparg_enum!( + /// Common constants for LOAD_COMMON_CONSTANT opcode. + /// pycore_opcode_utils.h CONSTANT_* + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + pub enum CommonConstant { + /// `AssertionError` exception type + AssertionError = 0, + /// `NotImplementedError` exception type + NotImplementedError = 1, + /// Built-in `tuple` type + BuiltinTuple = 2, + /// Built-in `all` function + BuiltinAll = 3, + /// Built-in `any` function + BuiltinAny = 4, + } +); impl fmt::Display for CommonConstant { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -571,51 +620,20 @@ impl fmt::Display for CommonConstant { } } -/// Specifies if a slice is built with either 2 or 3 arguments. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum BuildSliceArgCount { - /// ```py - /// x[5:10] - /// ``` - Two, - /// ```py - /// x[5:10:2] - /// ``` - Three, -} - -impl TryFrom for BuildSliceArgCount { - type Error = MarshalError; - - fn try_from(value: u8) -> Result { - Ok(match value { - 2 => Self::Two, - 3 => Self::Three, - _ => return Err(Self::Error::InvalidBytecode), - }) - } -} - -impl TryFrom for BuildSliceArgCount { - type Error = MarshalError; - - fn try_from(value: u32) -> Result { - u8::try_from(value) - .map_err(|_| Self::Error::InvalidBytecode) - .map(TryInto::try_into)? +oparg_enum!( + /// Specifies if a slice is built with either 2 or 3 arguments. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub enum BuildSliceArgCount { + /// ```py + /// x[5:10] + /// ``` + Two = 2, + /// ```py + /// x[5:10:2] + /// ``` + Three = 3, } -} - -impl From for u32 { - fn from(value: BuildSliceArgCount) -> Self { - match value { - BuildSliceArgCount::Two => 2, - BuildSliceArgCount::Three => 3, - } - } -} - -impl OpArgType for BuildSliceArgCount {} +); #[derive(Copy, Clone)] pub struct UnpackExArgs { @@ -727,23 +745,3 @@ impl From for LoadSuperAttr { builder.build() } } - -/// Helper function for `num_enum` derive macro. -/// -/// # Examples -/// -/// ```ignore -/// use num_enum::TryFromPrimitive; -/// -/// use rustpython_compiler_core::marshal::MarshalError; -/// -/// #[repr(u8)] -/// #[derive(TryFromPrimitive)] -/// #[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))] -/// enum Foo { -/// A = 1, -/// B = 2 -/// } -fn new_invalid_bytecode(_: T) -> MarshalError { - MarshalError::InvalidBytecode -} From b7794a534e21a3286d22cc2ee33737dd40522c56 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 12:15:05 +0200 Subject: [PATCH 02/17] No need to match on 255 --- crates/vm/src/stdlib/ast/other.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/vm/src/stdlib/ast/other.rs b/crates/vm/src/stdlib/ast/other.rs index 5c0803ac594..0e3942790a8 100644 --- a/crates/vm/src/stdlib/ast/other.rs +++ b/crates/vm/src/stdlib/ast/other.rs @@ -12,9 +12,8 @@ impl Node for ast::ConversionFlag { object: PyObjectRef, ) -> PyResult { // Python's AST uses ASCII codes: 's', 'r', 'a', -1=None - // Note: 255 is -1i8 as u8 (ruff's ConversionFlag::None) match i32::try_from_object(vm, object)? { - -1 | 255 => Ok(Self::None), + -1 => Ok(Self::None), x if x == b's' as i32 => Ok(Self::Str), x if x == b'r' as i32 => Ok(Self::Repr), x if x == b'a' as i32 => Ok(Self::Ascii), From ebabd58bb4c75c63180ce9976c7fdfdbb679a4cf Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 12:16:47 +0200 Subject: [PATCH 03/17] Remove `num_enum` crate from `compiler-core` --- crates/compiler-core/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/compiler-core/Cargo.toml b/crates/compiler-core/Cargo.toml index 6a03f02c24f..f4e619b95a4 100644 --- a/crates/compiler-core/Cargo.toml +++ b/crates/compiler-core/Cargo.toml @@ -17,7 +17,6 @@ bitflags = { workspace = true } itertools = { workspace = true } malachite-bigint = { workspace = true } num-complex = { workspace = true } -num_enum = { workspace = true } lz4_flex = "0.12" From a8b581c711a26ae924beeba99cfa2e1ef0134441 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 12:20:03 +0200 Subject: [PATCH 04/17] Update `Cargo.lock` --- Cargo.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 886b8294e17..58e16defe00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3110,7 +3110,6 @@ dependencies = [ "lz4_flex", "malachite-bigint", "num-complex", - "num_enum", "ruff_source_file", "rustpython-wtf8", ] From e48fdeb5e9121515411ec7d58dd76fc78bc1eaf7 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 12:20:19 +0200 Subject: [PATCH 05/17] macro fmt --- crates/compiler-core/src/bytecode/oparg.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index 6aaf8dca169..bd80bd88a31 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -169,7 +169,9 @@ macro_rules! impl_oparg_enum { fn try_from(value: u8) -> Result { Ok(match value { - $($value => Self::$var,)* + $( + $value => Self::$var, + )* _ => return Err(Self::Error::InvalidBytecode), }) } @@ -188,7 +190,9 @@ macro_rules! impl_oparg_enum { impl From<$name> for u8 { fn from(value: $name) -> Self { match value { - $($name::$var => $value,)* + $( + $name::$var => $value, + )* } } } From badcd5f5199ed7b1b06415e18324110da7250765 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 12:55:50 +0200 Subject: [PATCH 06/17] Rename macro vars --- crates/compiler-core/src/bytecode/oparg.rs | 20 ++++++++++---------- crates/vm/src/stdlib/ast/other.rs | 3 ++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index bd80bd88a31..70c3642d2fb 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -130,26 +130,26 @@ impl OpArgState { /// ``` macro_rules! oparg_enum { ( - $(#[$attr:meta])* + $(#[$enum_meta:meta])* $vis:vis enum $name:ident { $( - $(#[$var_attr:meta])* - $var:ident = $value:literal, + $(#[$variant_meta:meta])* + $variant:ident = $value:literal, )* } ) => { - $(#[$attr])* + $(#[$enum_meta])* $vis enum $name { $( - $(#[$var_attr])* - $var, // Do assign value to variant. + $(#[$variant_meta])* + $variant, // Do assign value to variant. )* } impl_oparg_enum!( enum $name { $( - $var = $value, + $variant = $value, )* } ); @@ -160,7 +160,7 @@ macro_rules! impl_oparg_enum { ( enum $name:ident { $( - $var:ident = $value:literal, + $variant:ident = $value:literal, )* } ) => { @@ -170,7 +170,7 @@ macro_rules! impl_oparg_enum { fn try_from(value: u8) -> Result { Ok(match value { $( - $value => Self::$var, + $value => Self::$variant, )* _ => return Err(Self::Error::InvalidBytecode), }) @@ -191,7 +191,7 @@ macro_rules! impl_oparg_enum { fn from(value: $name) -> Self { match value { $( - $name::$var => $value, + $name::$variant => $value, )* } } diff --git a/crates/vm/src/stdlib/ast/other.rs b/crates/vm/src/stdlib/ast/other.rs index 0e3942790a8..5c0803ac594 100644 --- a/crates/vm/src/stdlib/ast/other.rs +++ b/crates/vm/src/stdlib/ast/other.rs @@ -12,8 +12,9 @@ impl Node for ast::ConversionFlag { object: PyObjectRef, ) -> PyResult { // Python's AST uses ASCII codes: 's', 'r', 'a', -1=None + // Note: 255 is -1i8 as u8 (ruff's ConversionFlag::None) match i32::try_from_object(vm, object)? { - -1 => Ok(Self::None), + -1 | 255 => Ok(Self::None), x if x == b's' as i32 => Ok(Self::Str), x if x == b'r' as i32 => Ok(Self::Repr), x if x == b'a' as i32 => Ok(Self::Ascii), From 56e23eff60326e0f26999813ae77c9cbfde2646c Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 12:57:47 +0200 Subject: [PATCH 07/17] Match without `,` --- crates/compiler-core/src/bytecode/oparg.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index 70c3642d2fb..e3da5e7ed30 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -134,8 +134,8 @@ macro_rules! oparg_enum { $vis:vis enum $name:ident { $( $(#[$variant_meta:meta])* - $variant:ident = $value:literal, - )* + $variant:ident = $value:literal + ),* $(,)? } ) => { $(#[$enum_meta])* @@ -160,8 +160,8 @@ macro_rules! impl_oparg_enum { ( enum $name:ident { $( - $variant:ident = $value:literal, - )* + $variant:ident = $value:literal + ),* $(,)? } ) => { impl TryFrom for $name { From 5f3eb51fd7c934a31ed8ab5d7e5522f82c5dbd0b Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:08:44 +0200 Subject: [PATCH 08/17] Support alternative values --- crates/compiler-core/src/bytecode/oparg.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index e3da5e7ed30..83c616771d7 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -134,7 +134,7 @@ macro_rules! oparg_enum { $vis:vis enum $name:ident { $( $(#[$variant_meta:meta])* - $variant:ident = $value:literal + $variant:ident = $value:literal $(| $alternatives:expr)* ),* $(,)? } ) => { @@ -160,7 +160,7 @@ macro_rules! impl_oparg_enum { ( enum $name:ident { $( - $variant:ident = $value:literal + $variant:ident = $value:literal $(| $alternatives:expr)* ),* $(,)? } ) => { @@ -170,7 +170,7 @@ macro_rules! impl_oparg_enum { fn try_from(value: u8) -> Result { Ok(match value { $( - $value => Self::$variant, + $value $(| $alternatives)* => Self::$variant, )* _ => return Err(Self::Error::InvalidBytecode), }) @@ -222,7 +222,7 @@ oparg_enum!( /// f"{x:4}" /// ``` // Ruff `ConversionFlag::None` is `-1i8`, when its converted to `u8` its value is `u8::MAX`. - None = 0, + None = 0 | 255, /// Converts by calling `str()`. /// /// ```python From a371d16a13d148d79cb19a276732f65012ee1242 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:15:23 +0200 Subject: [PATCH 09/17] Fix alternatives --- crates/compiler-core/src/bytecode/oparg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index 83c616771d7..6f95bd82f99 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -149,7 +149,7 @@ macro_rules! oparg_enum { impl_oparg_enum!( enum $name { $( - $variant = $value, + $variant = $value $(| $alternatives)*, )* } ); From 1035006618ab019d89abb208f9b8c8445e06974f Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:19:17 +0200 Subject: [PATCH 10/17] Improve docs --- crates/compiler-core/src/bytecode/oparg.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index 6f95bd82f99..776aee744ef 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -114,6 +114,10 @@ impl OpArgState { /// - impl [`Into`] /// - impl [`OpArgType`] /// +/// # Note +/// If an enum variant has "alternative" values (i.e. `Foo = 0 | 1`), the first value will be the +/// result of converting to a number. +/// /// # Examples /// /// ```rust @@ -122,9 +126,10 @@ impl OpArgState { /// #[derive(Clone, Copy)] /// pub enum MyOpArg { /// /// Some doc. -/// Foo = 0, -/// Bar = 2, -/// Baz = 5, +/// Foo = 4, +/// Bar = 8, +/// Baz = 15 | 16, +/// Qux = 23 | 42 /// } /// ); /// ``` From 14f3030454bb1835c00c852b832fce1abd6468d6 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:33:27 +0200 Subject: [PATCH 11/17] Add const assert --- crates/compiler-core/src/bytecode/oparg.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index 776aee744ef..bc566b978bc 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -209,6 +209,8 @@ macro_rules! impl_oparg_enum { } impl OpArgType for $name {} + + const _: () = assert!(::core::mem::size_of::<$name>() == ::core::mem::size_of::()); }; } From d2c98f0991015ba54803dca32a883bf197c53d80 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:20:05 +0200 Subject: [PATCH 12/17] Don't use `as u32` --- crates/codegen/src/compile.rs | 12 ++++++------ crates/compiler-core/src/bytecode.rs | 4 ++-- crates/compiler-core/src/bytecode/oparg.rs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/codegen/src/compile.rs b/crates/codegen/src/compile.rs index 7058a258a44..6b0f596f70c 100644 --- a/crates/codegen/src/compile.rs +++ b/crates/codegen/src/compile.rs @@ -1175,7 +1175,7 @@ impl Compiler { arg: OpArgMarker::marker(), } .into(), - arg: OpArg(bytecode::ResumeType::AtFuncStart as u32), + arg: OpArg(u32::from(bytecode::ResumeType::AtFuncStart)), target: BlockIdx::NULL, location, end_location, @@ -6555,9 +6555,9 @@ impl Compiler { self, Instruction::Resume { arg: if is_await { - bytecode::ResumeType::AfterAwait as u32 + u32::from(bytecode::ResumeType::AfterAwait) } else { - bytecode::ResumeType::AfterYieldFrom as u32 + u32::from(bytecode::ResumeType::AfterYieldFrom) } } ); @@ -6710,7 +6710,7 @@ impl Compiler { emit!( self, Instruction::Resume { - arg: bytecode::ResumeType::AfterYield as u32 + arg: u32::from(bytecode::ResumeType::AfterYield) } ); } @@ -6932,7 +6932,7 @@ impl Compiler { emit!( compiler, Instruction::Resume { - arg: bytecode::ResumeType::AfterYield as u32 + arg: u32::from(bytecode::ResumeType::AfterYield) } ); emit!(compiler, Instruction::PopTop); @@ -8420,7 +8420,7 @@ impl Compiler { // Emit BUILD_INTERPOLATION // oparg encoding: (conversion << 2) | has_format_spec - let oparg = (conversion << 2) | (has_format_spec as u32); + let oparg = (conversion << 2) | u32::from(has_format_spec); emit!(self, Instruction::BuildInterpolation { oparg }); *interp_count += 1; diff --git a/crates/compiler-core/src/bytecode.rs b/crates/compiler-core/src/bytecode.rs index 3080b4e623e..a59b8f269e9 100644 --- a/crates/compiler-core/src/bytecode.rs +++ b/crates/compiler-core/src/bytecode.rs @@ -304,8 +304,8 @@ bitflags! { } } -#[derive(Copy, Clone)] #[repr(C)] +#[derive(Copy, Clone, Debug)] pub struct CodeUnit { pub op: Instruction, pub arg: OpArgByte, @@ -330,7 +330,7 @@ impl TryFrom<&[u8]> for CodeUnit { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct CodeUnits(Box<[CodeUnit]>); impl TryFrom<&[u8]> for CodeUnits { diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index bc566b978bc..784bb7eb9ce 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -210,7 +210,7 @@ macro_rules! impl_oparg_enum { impl OpArgType for $name {} - const _: () = assert!(::core::mem::size_of::<$name>() == ::core::mem::size_of::()); + // const _: () = assert!(::core::mem::size_of::<$name>() == ::core::mem::size_of::()); }; } From 4fcc241bd39d6b7e7ff9f677a267f044addf7017 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 21:52:07 +0200 Subject: [PATCH 13/17] Make only ComparisonOperator unoptimized --- crates/compiler-core/src/bytecode/oparg.rs | 31 +++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index 784bb7eb9ce..8df1fcb8313 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -161,6 +161,34 @@ macro_rules! oparg_enum { }; } +macro_rules! unoptimized_oparg_enum { + ( + $(#[$enum_meta:meta])* + $vis:vis enum $name:ident { + $( + $(#[$variant_meta:meta])* + $variant:ident = $value:literal $(| $alternatives:expr)* + ),* $(,)? + } + ) => { + $(#[$enum_meta])* + $vis enum $name { + $( + $(#[$variant_meta])* + $variant = $value, + )* + } + + impl_oparg_enum!( + enum $name { + $( + $variant = $value $(| $alternatives)*, + )* + } + ); + }; +} + macro_rules! impl_oparg_enum { ( enum $name:ident { @@ -401,7 +429,8 @@ impl From for u32 { impl OpArgType for MakeFunctionFlags {} -oparg_enum!( +// TODO: Make this optimized +unoptimized_oparg_enum!( /// The possible comparison operators. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ComparisonOperator { From 4a06d5280c1976c9e81f32a4976a7da725b47e90 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 22:44:02 +0200 Subject: [PATCH 14/17] Fix test --- crates/compiler-core/src/bytecode/oparg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index 8df1fcb8313..010ff7be169 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -120,7 +120,7 @@ impl OpArgState { /// /// # Examples /// -/// ```rust +/// ```ignore /// oparg_enum!( /// /// Oparg for the `X` opcode. /// #[derive(Clone, Copy)] From 2a9ef8291bef238cc2da6d019b18843bc1468059 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 6 Feb 2026 22:44:13 +0200 Subject: [PATCH 15/17] cleanup --- crates/codegen/src/compile.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/codegen/src/compile.rs b/crates/codegen/src/compile.rs index 6b0f596f70c..d89727c93b1 100644 --- a/crates/codegen/src/compile.rs +++ b/crates/codegen/src/compile.rs @@ -1277,8 +1277,6 @@ impl Compiler { /// Emit format parameter validation for annotation scope /// if format > VALUE_WITH_FAKE_GLOBALS (2): raise NotImplementedError fn emit_format_validation(&mut self) -> CompileResult<()> { - use bytecode::ComparisonOperator::Greater; - // Load format parameter (first local variable, index 0) emit!(self, Instruction::LoadFast(0)); @@ -1286,7 +1284,12 @@ impl Compiler { self.emit_load_const(ConstantData::Integer { value: 2.into() }); // Compare: format > 2 - emit!(self, Instruction::CompareOp { op: Greater }); + emit!( + self, + Instruction::CompareOp { + op: ComparisonOperator::Greater + } + ); // Jump to body if format <= 2 (comparison is false) let body_block = self.new_block(); From bb5677c8988d8e7b749113f754215709a14c3746 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 7 Feb 2026 08:41:17 +0200 Subject: [PATCH 16/17] All opargs are optimized --- crates/compiler-core/src/bytecode/oparg.rs | 31 +--------------------- crates/vm/src/types/slot.rs | 4 +-- 2 files changed, 3 insertions(+), 32 deletions(-) diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index 010ff7be169..b3a4d0b4f79 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -161,34 +161,6 @@ macro_rules! oparg_enum { }; } -macro_rules! unoptimized_oparg_enum { - ( - $(#[$enum_meta:meta])* - $vis:vis enum $name:ident { - $( - $(#[$variant_meta:meta])* - $variant:ident = $value:literal $(| $alternatives:expr)* - ),* $(,)? - } - ) => { - $(#[$enum_meta])* - $vis enum $name { - $( - $(#[$variant_meta])* - $variant = $value, - )* - } - - impl_oparg_enum!( - enum $name { - $( - $variant = $value $(| $alternatives)*, - )* - } - ); - }; -} - macro_rules! impl_oparg_enum { ( enum $name:ident { @@ -429,8 +401,7 @@ impl From for u32 { impl OpArgType for MakeFunctionFlags {} -// TODO: Make this optimized -unoptimized_oparg_enum!( +oparg_enum!( /// The possible comparison operators. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ComparisonOperator { diff --git a/crates/vm/src/types/slot.rs b/crates/vm/src/types/slot.rs index 2f45d9dcff1..53750610cae 100644 --- a/crates/vm/src/types/slot.rs +++ b/crates/vm/src/types/slot.rs @@ -1819,13 +1819,13 @@ impl PyComparisonOp { } } - pub const fn eval_ord(self, ord: Ordering) -> bool { + pub fn eval_ord(self, ord: Ordering) -> bool { let bit = match ord { Ordering::Less => Self::Lt, Ordering::Equal => Self::Eq, Ordering::Greater => Self::Gt, }; - self.0 as u8 & bit.0 as u8 != 0 + u8::from(self.0) & u8::from(bit.0) != 0 } pub const fn swapped(self) -> Self { From 9795123303ce429d075cb94afc559724616fb9a0 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 7 Feb 2026 08:46:32 +0200 Subject: [PATCH 17/17] Remove comment --- crates/compiler-core/src/bytecode/oparg.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index b3a4d0b4f79..a4eeb7ea1d9 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -209,8 +209,6 @@ macro_rules! impl_oparg_enum { } impl OpArgType for $name {} - - // const _: () = assert!(::core::mem::size_of::<$name>() == ::core::mem::size_of::()); }; }