From 3f93b22da4df1235d264160cacc63491c63bd440 Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" Date: Thu, 12 Mar 2026 23:36:39 +0900 Subject: [PATCH] Adapt bitflagset to use enum --- .cspell.dict/rust-more.txt | 1 + Cargo.lock | 33 +++++ Cargo.toml | 1 + crates/codegen/src/compile.rs | 75 +++++------ crates/compiler-core/Cargo.toml | 1 + crates/compiler-core/src/bytecode.rs | 4 +- .../compiler-core/src/bytecode/instruction.rs | 4 +- crates/compiler-core/src/bytecode/oparg.rs | 38 +++--- crates/jit/tests/common.rs | 62 +++++---- crates/vm/src/builtins/function.rs | 126 +++++++++--------- crates/vm/src/frame.rs | 2 +- 11 files changed, 193 insertions(+), 154 deletions(-) diff --git a/.cspell.dict/rust-more.txt b/.cspell.dict/rust-more.txt index af20aef568d..c4457723c6c 100644 --- a/.cspell.dict/rust-more.txt +++ b/.cspell.dict/rust-more.txt @@ -5,6 +5,7 @@ biguint bindgen bitand bitflags +bitflagset bitor bitvec bitxor diff --git a/Cargo.lock b/Cargo.lock index ba6899f1958..68adc9d682c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index 9c5b569f753..2f720de968a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/crates/codegen/src/compile.rs b/crates/codegen/src/compile.rs index 7c842286e87..94c6642aac2 100644 --- a/crates/codegen/src/compile.rs +++ b/crates/codegen/src/compile.rs @@ -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 { - 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: diff --git a/crates/compiler-core/Cargo.toml b/crates/compiler-core/Cargo.toml index f4e619b95a4..7be58432cdf 100644 --- a/crates/compiler-core/Cargo.toml +++ b/crates/compiler-core/Cargo.toml @@ -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 } diff --git a/crates/compiler-core/src/bytecode.rs b/crates/compiler-core/src/bytecode.rs index 169d4e8e53d..5120d371a39 100644 --- a/crates/compiler-core/src/bytecode.rs +++ b/crates/compiler-core/src/bytecode.rs @@ -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, }, }; diff --git a/crates/compiler-core/src/bytecode/instruction.rs b/crates/compiler-core/src/bytecode/instruction.rs index 16b9f1f960c..9eca2220977 100644 --- a/crates/compiler-core/src/bytecode/instruction.rs +++ b/crates/compiler-core/src/bytecode/instruction.rs @@ -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, } = 107, SetFunctionAttribute { - flag: Arg, + flag: Arg, } = 108, SetUpdate { i: Arg, diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index b73ea1e89eb..6de567048fe 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -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 for MakeFunctionFlags { +bitflagset::bitflagset! { + #[derive(Copy, Clone, PartialEq, Eq)] + pub struct MakeFunctionFlags(u8): MakeFunctionFlag +} + +impl TryFrom for MakeFunctionFlag { type Error = MarshalError; fn try_from(value: u32) -> Result { - Self::from_bits(value as u8).ok_or(Self::Error::InvalidBytecode) + Self::try_from(value as u8).map_err(|_| MarshalError::InvalidBytecode) } } -impl From for u32 { - fn from(value: MakeFunctionFlags) -> Self { - value.bits().into() +impl From for u32 { + fn from(flag: MakeFunctionFlag) -> Self { + flag as u32 } } -impl OpArgType for MakeFunctionFlags {} +impl OpArgType for MakeFunctionFlag {} oparg_enum!( /// The possible comparison operators. diff --git a/crates/jit/tests/common.rs b/crates/jit/tests/common.rs index 0bdfd77d856..629cdccc7fd 100644 --- a/crates/jit/tests/common.rs +++ b/crates/jit/tests/common.rs @@ -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(()), diff --git a/crates/vm/src/builtins/function.rs b/crates/vm/src/builtins/function.rs index 3b7d7bf14ea..7a6a3ef278f 100644 --- a/crates/vm/src/builtins/function.rs +++ b/crates/vm/src/builtins/function.rs @@ -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::() { - 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::() { - 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::() { - 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::(vm) - .map_err(|obj| { + match attr { + bytecode::MakeFunctionFlag::Defaults => { + let defaults = match attr_value.downcast::() { + 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::() { + 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::() { + 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::(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::(vm)?); + } + bytecode::MakeFunctionFlag::TypeParams => { + let type_params = attr_value.clone().downcast::().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::(vm)?); - } else if attr == bytecode::MakeFunctionFlags::TYPE_PARAMS { - let type_params = attr_value.clone().downcast::().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(()) } diff --git a/crates/vm/src/frame.rs b/crates/vm/src/frame.rs index d3c5ec2db53..071bd91da28 100644 --- a/crates/vm/src/frame.rs +++ b/crates/vm/src/frame.rs @@ -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]