Adapt bitflagset to use enum (#7419)

This commit is contained in:
Jeong, YunWon authored and GitHub committed 2026-03-14 09:44:02 +09:00
1 parent 7e2154f382
commit 13a0623eb1
11 files changed
+193 -154

No files matched your search

+1
View File
@@ -5,6 +5,7 @@ biguint
bindgen
bitand
bitflags
bitflagset
bitor
bitvec
bitxor
Generated
+33
View File
@@ -349,6 +349,18 @@ version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
[[package]]
name = "bitflagset"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64b6ee310aa7af14142c8c9121775774ff601ae055ed98ba7fac96098bcde1b9"
dependencies = [
"num-integer",
"num-traits",
"radium",
"ref-cast",
]
[[package]]
name = "blake2"
version = "0.10.6"
@@ -2769,6 +2781,26 @@ dependencies = [
"thiserror 1.0.69",
]
[[package]]
name = "ref-cast"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "regalloc2"
version = "0.13.5"
@@ -3128,6 +3160,7 @@ name = "rustpython-compiler-core"
version = "0.4.0"
dependencies = [
"bitflags 2.11.0",
"bitflagset",
"itertools 0.14.0",
"lz4_flex",
"malachite-bigint",
+1
View File
@@ -167,6 +167,7 @@ phf = { version = "0.13.1", default-features = false, features = ["macros"]}
ahash = "0.8.12"
ascii = "1.1"
bitflags = "2.11.0"
bitflagset = "0.0.3"
bstr = "1"
bytes = "1.11.1"
cfg-if = "1.0"
+37 -38
View File
@@ -2509,7 +2509,7 @@ impl Compiler {
self.compile_expression(value)?;
emit!(self, Instruction::ReturnValue);
let value_code = self.exit_scope();
self.make_closure(value_code, bytecode::MakeFunctionFlags::empty())?;
self.make_closure(value_code, bytecode::MakeFunctionFlags::new())?;
// Stack: [type_params_tuple, value_closure]
// Swap so unpack_sequence reverse gives correct order
@@ -2522,7 +2522,7 @@ impl Compiler {
let code = self.exit_scope();
self.ctx = prev_ctx;
self.make_closure(code, bytecode::MakeFunctionFlags::empty())?;
self.make_closure(code, bytecode::MakeFunctionFlags::new())?;
emit!(self, Instruction::PushNull);
emit!(self, Instruction::Call { argc: 0 });
@@ -2561,7 +2561,7 @@ impl Compiler {
let code = self.exit_scope();
self.ctx = prev_ctx;
self.make_closure(code, bytecode::MakeFunctionFlags::empty())?;
self.make_closure(code, bytecode::MakeFunctionFlags::new())?;
// Stack: [name, None, closure]
}
@@ -2725,7 +2725,7 @@ impl Compiler {
self.ctx = prev_ctx;
// Create closure for lazy evaluation
self.make_closure(code, bytecode::MakeFunctionFlags::empty())?;
self.make_closure(code, bytecode::MakeFunctionFlags::new())?;
Ok(())
}
@@ -3649,7 +3649,7 @@ impl Compiler {
&mut self,
parameters: &ast::Parameters,
) -> CompileResult<bytecode::MakeFunctionFlags> {
let mut funcflags = bytecode::MakeFunctionFlags::empty();
let mut funcflags = bytecode::MakeFunctionFlags::new();
// Handle positional defaults
let defaults: Vec<_> = core::iter::empty()
@@ -3669,7 +3669,7 @@ impl Compiler {
count: defaults.len().to_u32()
}
);
funcflags |= bytecode::MakeFunctionFlags::DEFAULTS;
funcflags.insert(bytecode::MakeFunctionFlag::Defaults);
}
// Handle keyword-only defaults
@@ -3694,7 +3694,7 @@ impl Compiler {
count: kw_with_defaults.len().to_u32(),
}
);
funcflags |= bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS;
funcflags.insert(bytecode::MakeFunctionFlag::KwOnlyDefaults);
}
Ok(funcflags)
@@ -3844,7 +3844,7 @@ impl Compiler {
let annotate_code = self.exit_annotation_scope(saved_ctx);
// Make a closure from the code object
self.make_closure(annotate_code, bytecode::MakeFunctionFlags::empty())?;
self.make_closure(annotate_code, bytecode::MakeFunctionFlags::new())?;
Ok(true)
}
@@ -4054,7 +4054,7 @@ impl Compiler {
);
// Make a closure from the code object
self.make_closure(annotate_code, bytecode::MakeFunctionFlags::empty())?;
self.make_closure(annotate_code, bytecode::MakeFunctionFlags::new())?;
// Store as __annotate_func__ for classes, __annotate__ for modules
let name = if parent_scope_type == CompilerScope::Class {
@@ -4092,10 +4092,10 @@ impl Compiler {
if is_generic {
// Count args to pass to type params scope
if funcflags.contains(bytecode::MakeFunctionFlags::DEFAULTS) {
if funcflags.contains(&bytecode::MakeFunctionFlag::Defaults) {
num_typeparam_args += 1;
}
if funcflags.contains(bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS) {
if funcflags.contains(&bytecode::MakeFunctionFlag::KwOnlyDefaults) {
num_typeparam_args += 1;
}
@@ -4120,13 +4120,13 @@ impl Compiler {
// Add parameter names to varnames for the type params scope
// These will be passed as arguments when the closure is called
let current_info = self.current_code_info();
if funcflags.contains(bytecode::MakeFunctionFlags::DEFAULTS) {
if funcflags.contains(&bytecode::MakeFunctionFlag::Defaults) {
current_info
.metadata
.varnames
.insert(".defaults".to_owned());
}
if funcflags.contains(bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS) {
if funcflags.contains(&bytecode::MakeFunctionFlag::KwOnlyDefaults) {
current_info
.metadata
.varnames
@@ -4144,11 +4144,10 @@ impl Compiler {
}
// Compile annotations as closure (PEP 649)
let annotations_flag = if self.compile_annotations_closure(name, parameters, returns)? {
bytecode::MakeFunctionFlags::ANNOTATE
} else {
bytecode::MakeFunctionFlags::empty()
};
let mut annotations_flag = bytecode::MakeFunctionFlags::new();
if self.compile_annotations_closure(name, parameters, returns)? {
annotations_flag.insert(bytecode::MakeFunctionFlag::Annotate);
}
// Compile function body
let final_funcflags = funcflags | annotations_flag;
@@ -4179,7 +4178,7 @@ impl Compiler {
self.ctx = saved_ctx;
// Make closure for type params code
self.make_closure(type_params_code, bytecode::MakeFunctionFlags::empty())?;
self.make_closure(type_params_code, bytecode::MakeFunctionFlags::new())?;
// Call the type params closure with defaults/kwdefaults as arguments.
// Call protocol: [callable, self_or_null, arg1, ..., argN]
@@ -4347,57 +4346,57 @@ impl Compiler {
emit!(
self,
Instruction::SetFunctionAttribute {
flag: bytecode::MakeFunctionFlags::CLOSURE
flag: bytecode::MakeFunctionFlag::Closure
}
);
}
// Set annotations if present
if flags.contains(bytecode::MakeFunctionFlags::ANNOTATIONS) {
if flags.contains(&bytecode::MakeFunctionFlag::Annotations) {
emit!(
self,
Instruction::SetFunctionAttribute {
flag: bytecode::MakeFunctionFlags::ANNOTATIONS
flag: bytecode::MakeFunctionFlag::Annotations
}
);
}
// Set __annotate__ closure if present (PEP 649)
if flags.contains(bytecode::MakeFunctionFlags::ANNOTATE) {
if flags.contains(&bytecode::MakeFunctionFlag::Annotate) {
emit!(
self,
Instruction::SetFunctionAttribute {
flag: bytecode::MakeFunctionFlags::ANNOTATE
flag: bytecode::MakeFunctionFlag::Annotate
}
);
}
// Set kwdefaults if present
if flags.contains(bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS) {
if flags.contains(&bytecode::MakeFunctionFlag::KwOnlyDefaults) {
emit!(
self,
Instruction::SetFunctionAttribute {
flag: bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS
flag: bytecode::MakeFunctionFlag::KwOnlyDefaults
}
);
}
// Set defaults if present
if flags.contains(bytecode::MakeFunctionFlags::DEFAULTS) {
if flags.contains(&bytecode::MakeFunctionFlag::Defaults) {
emit!(
self,
Instruction::SetFunctionAttribute {
flag: bytecode::MakeFunctionFlags::DEFAULTS
flag: bytecode::MakeFunctionFlag::Defaults
}
);
}
// Set type_params if present
if flags.contains(bytecode::MakeFunctionFlags::TYPE_PARAMS) {
if flags.contains(&bytecode::MakeFunctionFlag::TypeParams) {
emit!(
self,
Instruction::SetFunctionAttribute {
flag: bytecode::MakeFunctionFlags::TYPE_PARAMS
flag: bytecode::MakeFunctionFlag::TypeParams
}
);
}
@@ -4689,14 +4688,14 @@ impl Compiler {
emit!(self, Instruction::PushNull);
// Set up the class function with type params
let mut func_flags = bytecode::MakeFunctionFlags::empty();
let mut func_flags = bytecode::MakeFunctionFlags::new();
emit!(
self,
Instruction::LoadName {
namei: dot_type_params
}
);
func_flags |= bytecode::MakeFunctionFlags::TYPE_PARAMS;
func_flags.insert(bytecode::MakeFunctionFlag::TypeParams);
// Create class function with closure
self.make_closure(class_code, func_flags)?;
@@ -4819,7 +4818,7 @@ impl Compiler {
self.ctx = saved_ctx;
// Execute the type params function
self.make_closure(type_params_code, bytecode::MakeFunctionFlags::empty())?;
self.make_closure(type_params_code, bytecode::MakeFunctionFlags::new())?;
emit!(self, Instruction::PushNull);
emit!(self, Instruction::Call { argc: 0 });
} else {
@@ -4828,7 +4827,7 @@ impl Compiler {
emit!(self, Instruction::PushNull);
// Create class function with closure
self.make_closure(class_code, bytecode::MakeFunctionFlags::empty())?;
self.make_closure(class_code, bytecode::MakeFunctionFlags::new())?;
self.emit_load_const(ConstantData::Str { value: name.into() });
if let Some(arguments) = arguments {
@@ -7096,12 +7095,12 @@ impl Compiler {
}
self.enter_function(&name, params)?;
let mut func_flags = bytecode::MakeFunctionFlags::empty();
let mut func_flags = bytecode::MakeFunctionFlags::new();
if have_defaults {
func_flags |= bytecode::MakeFunctionFlags::DEFAULTS;
func_flags.insert(bytecode::MakeFunctionFlag::Defaults);
}
if have_kwdefaults {
func_flags |= bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS;
func_flags.insert(bytecode::MakeFunctionFlag::KwOnlyDefaults);
}
// Set qualname for lambda
@@ -7785,7 +7784,7 @@ impl Compiler {
self.ctx = prev_ctx;
// Create comprehension function with closure
self.make_closure(code, bytecode::MakeFunctionFlags::empty())?;
self.make_closure(code, bytecode::MakeFunctionFlags::new())?;
emit!(self, Instruction::PushNull);
// Evaluate iterated item:
+1
View File
@@ -14,6 +14,7 @@ ruff_source_file = { workspace = true }
rustpython-wtf8 = { workspace = true }
bitflags = { workspace = true }
bitflagset = { workspace = true }
itertools = { workspace = true }
malachite-bigint = { workspace = true }
num-complex = { workspace = true }
+2 -2
View File
@@ -26,8 +26,8 @@ pub use crate::bytecode::{
oparg::{
BinaryOperator, BuildSliceArgCount, CommonConstant, ComparisonOperator, ConvertValueOparg,
IntrinsicFunction1, IntrinsicFunction2, Invert, Label, LoadAttr, LoadSuperAttr,
MakeFunctionFlags, NameIdx, OpArg, OpArgByte, OpArgState, OpArgType, RaiseKind, ResumeType,
SpecialMethod, UnpackExArgs,
MakeFunctionFlag, MakeFunctionFlags, NameIdx, OpArg, OpArgByte, OpArgState, OpArgType,
RaiseKind, ResumeType, SpecialMethod, UnpackExArgs,
},
};
@@ -6,7 +6,7 @@ use crate::{
oparg::{
self, BinaryOperator, BuildSliceArgCount, CommonConstant, ComparisonOperator,
ConvertValueOparg, IntrinsicFunction1, IntrinsicFunction2, Invert, Label, LoadAttr,
LoadSuperAttr, MakeFunctionFlags, NameIdx, OpArg, OpArgByte, OpArgType, RaiseKind,
LoadSuperAttr, MakeFunctionFlag, NameIdx, OpArg, OpArgByte, OpArgType, RaiseKind,
SpecialMethod, StoreFastLoadFast, UnpackExArgs,
},
},
@@ -264,7 +264,7 @@ pub enum Instruction {
i: Arg<u32>,
} = 107,
SetFunctionAttribute {
flag: Arg<MakeFunctionFlags>,
flag: Arg<MakeFunctionFlag>,
} = 108,
SetUpdate {
i: Arg<u32>,
+21 -17
View File
@@ -1,5 +1,3 @@
use bitflags::bitflags;
use core::fmt;
use crate::{
@@ -352,34 +350,40 @@ oparg_enum!(
}
);
bitflags! {
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct MakeFunctionFlags: u8 {
const CLOSURE = 0x01;
const ANNOTATIONS = 0x02;
const KW_ONLY_DEFAULTS = 0x04;
const DEFAULTS = 0x08;
const TYPE_PARAMS = 0x10;
bitflagset::bitflag! {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum MakeFunctionFlag {
Closure = 0,
Annotations = 1,
KwOnlyDefaults = 2,
Defaults = 3,
TypeParams = 4,
/// PEP 649: __annotate__ function closure (instead of __annotations__ dict)
const ANNOTATE = 0x20;
Annotate = 5,
}
}
impl TryFrom<u32> for MakeFunctionFlags {
bitflagset::bitflagset! {
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct MakeFunctionFlags(u8): MakeFunctionFlag
}
impl TryFrom<u32> for MakeFunctionFlag {
type Error = MarshalError;
fn try_from(value: u32) -> Result<Self, Self::Error> {
Self::from_bits(value as u8).ok_or(Self::Error::InvalidBytecode)
Self::try_from(value as u8).map_err(|_| MarshalError::InvalidBytecode)
}
}
impl From<MakeFunctionFlags> for u32 {
fn from(value: MakeFunctionFlags) -> Self {
value.bits().into()
impl From<MakeFunctionFlag> for u32 {
fn from(flag: MakeFunctionFlag) -> Self {
flag as u32
}
}
impl OpArgType for MakeFunctionFlags {}
impl OpArgType for MakeFunctionFlag {}
oparg_enum!(
/// The possible comparison operators.
+30 -32
View File
@@ -243,42 +243,40 @@ impl StackMachine {
};
let attr_value = self.stack.pop().expect("Expected attribute value on stack");
let flags = flag.get(arg);
let flag_value = flag.get(arg);
// Handle ANNOTATE flag (PEP 649 style - Python 3.14+)
// The attr_value is a function that returns annotations when called
if flags.contains(rustpython_compiler_core::bytecode::MakeFunctionFlags::ANNOTATE) {
if let StackValue::Function(annotate_func) = attr_value {
// Parse the annotate function's bytecode to extract annotations
// The pattern is: LOAD_CONST (key), LOAD_NAME (value), ... BUILD_MAP
let annotate_code = &annotate_func.code;
let annotations = extract_annotations_from_annotate_code(annotate_code);
match flag_value {
rustpython_compiler_core::bytecode::MakeFunctionFlag::Annotate => {
// Handle ANNOTATE flag (PEP 649 style - Python 3.14+)
if let StackValue::Function(annotate_func) = attr_value {
let annotate_code = &annotate_func.code;
let annotations = extract_annotations_from_annotate_code(annotate_code);
let updated_func = Function {
code: func.code,
annotations,
};
self.stack.push(StackValue::Function(updated_func));
} else {
panic!("Expected annotate function for ANNOTATE flag");
let updated_func = Function {
code: func.code,
annotations,
};
self.stack.push(StackValue::Function(updated_func));
} else {
panic!("Expected annotate function for ANNOTATE flag");
}
}
}
// Handle old ANNOTATIONS flag (Python 3.12 style)
else if flags
.contains(rustpython_compiler_core::bytecode::MakeFunctionFlags::ANNOTATIONS)
{
if let StackValue::Map(annotations) = attr_value {
let updated_func = Function {
code: func.code,
annotations,
};
self.stack.push(StackValue::Function(updated_func));
} else {
panic!("Expected annotations to be a map");
rustpython_compiler_core::bytecode::MakeFunctionFlag::Annotations => {
// Handle old ANNOTATIONS flag (Python 3.12 style)
if let StackValue::Map(annotations) = attr_value {
let updated_func = Function {
code: func.code,
annotations,
};
self.stack.push(StackValue::Function(updated_func));
} else {
panic!("Expected annotations to be a map");
}
}
_ => {
// For other attributes, just push the function back unchanged
self.stack.push(StackValue::Function(func));
}
} else {
// For other attributes, just push the function back unchanged
self.stack.push(StackValue::Function(func));
}
}
Instruction::ReturnValue => return ControlFlow::Break(()),
+64 -62
View File
@@ -454,75 +454,77 @@ impl PyFunction {
/// Set function attribute based on MakeFunctionFlags
pub(crate) fn set_function_attribute(
&mut self,
attr: bytecode::MakeFunctionFlags,
attr: bytecode::MakeFunctionFlag,
attr_value: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
use crate::builtins::PyDict;
if attr == bytecode::MakeFunctionFlags::DEFAULTS {
let defaults = match attr_value.downcast::<PyTuple>() {
Ok(tuple) => tuple,
Err(obj) => {
return Err(vm.new_type_error(format!(
"__defaults__ must be a tuple, not {}",
obj.class().name()
)));
}
};
self.defaults_and_kwdefaults.lock().0 = Some(defaults);
} else if attr == bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS {
let kwdefaults = match attr_value.downcast::<PyDict>() {
Ok(dict) => dict,
Err(obj) => {
return Err(vm.new_type_error(format!(
"__kwdefaults__ must be a dict, not {}",
obj.class().name()
)));
}
};
self.defaults_and_kwdefaults.lock().1 = Some(kwdefaults);
} else if attr == bytecode::MakeFunctionFlags::ANNOTATIONS {
let annotations = match attr_value.downcast::<PyDict>() {
Ok(dict) => dict,
Err(obj) => {
return Err(vm.new_type_error(format!(
"__annotations__ must be a dict, not {}",
obj.class().name()
)));
}
};
*self.annotations.lock() = Some(annotations);
} else if attr == bytecode::MakeFunctionFlags::CLOSURE {
// For closure, we need special handling
// The closure tuple contains cell objects
let closure_tuple = attr_value
.clone()
.downcast_exact::<PyTuple>(vm)
.map_err(|obj| {
match attr {
bytecode::MakeFunctionFlag::Defaults => {
let defaults = match attr_value.downcast::<PyTuple>() {
Ok(tuple) => tuple,
Err(obj) => {
return Err(vm.new_type_error(format!(
"__defaults__ must be a tuple, not {}",
obj.class().name()
)));
}
};
self.defaults_and_kwdefaults.lock().0 = Some(defaults);
}
bytecode::MakeFunctionFlag::KwOnlyDefaults => {
let kwdefaults = match attr_value.downcast::<PyDict>() {
Ok(dict) => dict,
Err(obj) => {
return Err(vm.new_type_error(format!(
"__kwdefaults__ must be a dict, not {}",
obj.class().name()
)));
}
};
self.defaults_and_kwdefaults.lock().1 = Some(kwdefaults);
}
bytecode::MakeFunctionFlag::Annotations => {
let annotations = match attr_value.downcast::<PyDict>() {
Ok(dict) => dict,
Err(obj) => {
return Err(vm.new_type_error(format!(
"__annotations__ must be a dict, not {}",
obj.class().name()
)));
}
};
*self.annotations.lock() = Some(annotations);
}
bytecode::MakeFunctionFlag::Closure => {
let closure_tuple = attr_value
.clone()
.downcast_exact::<PyTuple>(vm)
.map_err(|obj| {
vm.new_type_error(format!(
"closure must be a tuple, not {}",
obj.class().name()
))
})?
.into_pyref();
self.closure = Some(closure_tuple.try_into_typed::<PyCell>(vm)?);
}
bytecode::MakeFunctionFlag::TypeParams => {
let type_params = attr_value.clone().downcast::<PyTuple>().map_err(|_| {
vm.new_type_error(format!(
"closure must be a tuple, not {}",
obj.class().name()
"__type_params__ must be a tuple, not {}",
attr_value.class().name()
))
})?
.into_pyref();
self.closure = Some(closure_tuple.try_into_typed::<PyCell>(vm)?);
} else if attr == bytecode::MakeFunctionFlags::TYPE_PARAMS {
let type_params = attr_value.clone().downcast::<PyTuple>().map_err(|_| {
vm.new_type_error(format!(
"__type_params__ must be a tuple, not {}",
attr_value.class().name()
))
})?;
*self.type_params.lock() = type_params;
} else if attr == bytecode::MakeFunctionFlags::ANNOTATE {
// PEP 649: Store the __annotate__ function closure
if !attr_value.is_callable() {
return Err(vm.new_type_error("__annotate__ must be callable"));
})?;
*self.type_params.lock() = type_params;
}
bytecode::MakeFunctionFlag::Annotate => {
if !attr_value.is_callable() {
return Err(vm.new_type_error("__annotate__ must be callable"));
}
*self.annotate.lock() = Some(attr_value);
}
*self.annotate.lock() = Some(attr_value);
} else {
unreachable!("This is a compiler bug");
}
Ok(())
}
+1 -1
View File
@@ -6861,7 +6861,7 @@ impl ExecutingFrame<'_> {
fn execute_set_function_attribute(
&mut self,
vm: &VirtualMachine,
attr: bytecode::MakeFunctionFlags,
attr: bytecode::MakeFunctionFlag,
) -> FrameResult {
// SET_FUNCTION_ATTRIBUTE sets attributes on a function
// Stack: [..., attr_value, func] -> [..., func]