From c8e1a5a5d44911dae1599ef1bac4b2cb163dcd72 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 20 Jun 2026 11:43:50 +0300 Subject: [PATCH 1/5] General nitpicks --- crates/codegen/src/compile.rs | 105 ++++++++++++++++------------------ crates/vm/src/py_io.rs | 20 +++++-- crates/vm/src/py_serde.rs | 5 +- crates/vm/src/readline.rs | 2 +- 4 files changed, 69 insertions(+), 63 deletions(-) diff --git a/crates/codegen/src/compile.rs b/crates/codegen/src/compile.rs index 476aa35e3ef..36f92092d67 100644 --- a/crates/codegen/src/compile.rs +++ b/crates/codegen/src/compile.rs @@ -24,13 +24,14 @@ use num_complex::Complex; use num_traits::{Num, ToPrimitive, Zero}; use ruff_python_ast as ast; use ruff_text_size::{Ranged, TextRange, TextSize}; + use rustpython_compiler_core::{ Mode, OneIndexed, PositionEncoding, SourceFile, SourceLocation, bytecode::{ self, AnyInstruction, AnyOpcode, Arg as OpArgMarker, BinaryOperator, BuildSliceArgCount, CodeObject, ComparisonOperator, ConstantData, ConvertValueOparg, Instruction, - IntrinsicFunction1, Invert, LoadAttr, LoadSuperAttr, OpArg, OpArgType, PseudoInstruction, - SpecialMethod, UnpackExArgs, oparg, + IntrinsicFunction1, Invert, LoadAttr, LoadSuperAttr, MakeFunctionFlag, MakeFunctionFlags, + OpArg, OpArgType, PseudoInstruction, SpecialMethod, UnpackExArgs, oparg, }, }; use rustpython_wtf8::Wtf8Buf; @@ -63,12 +64,9 @@ impl ExprExt for ast::Expr { fn is_constant_slice(&self) -> bool { match self { Self::Slice(s) => { - let lower_const = - s.lower.is_none() || s.lower.as_deref().is_some_and(|e| e.is_constant()); - let upper_const = - s.upper.is_none() || s.upper.as_deref().is_some_and(|e| e.is_constant()); - let step_const = - s.step.is_none() || s.step.as_deref().is_some_and(|e| e.is_constant()); + let lower_const = s.lower.as_deref().is_none_or(|e| e.is_constant()); + let upper_const = s.upper.as_deref().is_none_or(|e| e.is_constant()); + let step_const = s.step.as_deref().is_none_or(|e| e.is_constant()); lower_const && upper_const && step_const } _ => false, @@ -2485,11 +2483,13 @@ impl Compiler { let current_table = self.current_symbol_table(); if current_table.typ == CompilerScope::Class && !self.current_code_info().in_inlined_comp - && ((usage == NameUsage::Load - && (name == "__class__" - || name == "__classdict__" - || name == "__conditional_annotations__")) - || (name == "__conditional_annotations__" && usage == NameUsage::Store)) + && matches!( + (usage, name.as_ref()), + ( + NameUsage::Load, + "__class__" | "__classdict__" | "__conditional_annotations__" + ) | (NameUsage::Store, "__conditional_annotations__") + ) { Some(SymbolScope::Cell) } else { @@ -3150,7 +3150,7 @@ impl Compiler { let code = self.exit_scope(); self.ctx = prev_ctx; - self.make_closure(code, bytecode::MakeFunctionFlags::new())?; + self.make_closure(code, MakeFunctionFlags::new())?; emit!(self, Instruction::PushNull); emit!(self, Instruction::Call { argc: 0 }); } else { @@ -3333,10 +3333,7 @@ impl Compiler { self.ctx = prev_ctx; self.set_source_range(expr_range); - self.make_closure( - code, - bytecode::MakeFunctionFlags::from([bytecode::MakeFunctionFlag::Defaults]), - )?; + self.make_closure(code, MakeFunctionFlags::from([MakeFunctionFlag::Defaults]))?; Ok(()) } @@ -3376,10 +3373,7 @@ impl Compiler { let code = self.exit_scope(); self.ctx = prev_ctx; self.set_source_range(alias_range); - self.make_closure( - code, - bytecode::MakeFunctionFlags::from([bytecode::MakeFunctionFlag::Defaults]), - )?; + self.make_closure(code, MakeFunctionFlags::from([MakeFunctionFlag::Defaults]))?; Ok(()) } @@ -4206,7 +4200,7 @@ impl Compiler { parameters: &ast::Parameters, loc: TextRange, ) -> CompileResult { - let mut funcflags = bytecode::MakeFunctionFlags::new(); + let mut funcflags = MakeFunctionFlags::new(); // Handle positional defaults let defaults: Vec<_> = core::iter::empty() @@ -4227,7 +4221,7 @@ impl Compiler { count: defaults.len().to_u32() } ); - funcflags.insert(bytecode::MakeFunctionFlag::Defaults); + funcflags.insert(MakeFunctionFlag::Defaults); } // Handle keyword-only defaults @@ -4254,7 +4248,7 @@ impl Compiler { count: kw_with_defaults.len().to_u32(), } ); - funcflags.insert(bytecode::MakeFunctionFlag::KwOnlyDefaults); + funcflags.insert(MakeFunctionFlag::KwOnlyDefaults); } Ok(funcflags) @@ -4460,7 +4454,7 @@ impl Compiler { // Make a closure from the code object self.set_source_range(func_range); - self.make_closure(annotate_code, bytecode::MakeFunctionFlags::new())?; + self.make_closure(annotate_code, MakeFunctionFlags::new())?; Ok(true) } @@ -4684,7 +4678,7 @@ impl Compiler { // Make a closure from the code object self.set_source_range(loc); - self.make_closure(annotate_code, bytecode::MakeFunctionFlags::new())?; + self.make_closure(annotate_code, MakeFunctionFlags::new())?; // Store as __annotate_func__ for classes, __annotate__ for modules let name = if parent_scope_type == CompilerScope::Class { @@ -4737,10 +4731,10 @@ impl Compiler { if is_generic { // Count args to pass to type params scope - if funcflags.contains(&bytecode::MakeFunctionFlag::Defaults) { + if funcflags.contains(&MakeFunctionFlag::Defaults) { num_typeparam_args += 1; } - if funcflags.contains(&bytecode::MakeFunctionFlag::KwOnlyDefaults) { + if funcflags.contains(&MakeFunctionFlag::KwOnlyDefaults) { num_typeparam_args += 1; } if num_typeparam_args == 2 { @@ -4767,13 +4761,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::MakeFunctionFlag::Defaults) { + if funcflags.contains(&MakeFunctionFlag::Defaults) { current_info .metadata .varnames .insert(".defaults".to_owned()); } - if funcflags.contains(&bytecode::MakeFunctionFlag::KwOnlyDefaults) { + if funcflags.contains(&MakeFunctionFlag::KwOnlyDefaults) { current_info .metadata .varnames @@ -4791,9 +4785,9 @@ impl Compiler { } // Compile annotations as closure (PEP 649) - let mut annotations_flag = bytecode::MakeFunctionFlags::new(); + let mut annotations_flag = MakeFunctionFlags::new(); if self.compile_annotations_closure(name, parameters, returns, def_source_range)? { - annotations_flag.insert(bytecode::MakeFunctionFlag::Annotate); + annotations_flag.insert(MakeFunctionFlag::Annotate); } // Compile function body @@ -4834,7 +4828,7 @@ impl Compiler { self.ctx = saved_ctx; // Make closure for type params code - self.make_closure(type_params_code, bytecode::MakeFunctionFlags::new())?; + self.make_closure(type_params_code, MakeFunctionFlags::new())?; if num_typeparam_args > 0 { emit!( @@ -4879,9 +4873,10 @@ impl Compiler { // This should only apply when we're actually IN a class body, // not when we're in a method nested inside a class. if table.typ == CompilerScope::Class - && (name == "__class__" - || name == "__classdict__" - || name == "__conditional_annotations__") + && matches!( + name, + "__class__" | "__classdict__" | "__conditional_annotations__" + ) { return Ok(SymbolScope::Cell); } @@ -4990,57 +4985,57 @@ impl Compiler { emit!( self, Instruction::SetFunctionAttribute { - flag: bytecode::MakeFunctionFlag::Closure + flag: MakeFunctionFlag::Closure } ); } // Set annotations if present - if flags.contains(&bytecode::MakeFunctionFlag::Annotations) { + if flags.contains(&MakeFunctionFlag::Annotations) { emit!( self, Instruction::SetFunctionAttribute { - flag: bytecode::MakeFunctionFlag::Annotations + flag: MakeFunctionFlag::Annotations } ); } // Set __annotate__ closure if present (PEP 649) - if flags.contains(&bytecode::MakeFunctionFlag::Annotate) { + if flags.contains(&MakeFunctionFlag::Annotate) { emit!( self, Instruction::SetFunctionAttribute { - flag: bytecode::MakeFunctionFlag::Annotate + flag: MakeFunctionFlag::Annotate } ); } // Set kwdefaults if present - if flags.contains(&bytecode::MakeFunctionFlag::KwOnlyDefaults) { + if flags.contains(&MakeFunctionFlag::KwOnlyDefaults) { emit!( self, Instruction::SetFunctionAttribute { - flag: bytecode::MakeFunctionFlag::KwOnlyDefaults + flag: MakeFunctionFlag::KwOnlyDefaults } ); } // Set defaults if present - if flags.contains(&bytecode::MakeFunctionFlag::Defaults) { + if flags.contains(&MakeFunctionFlag::Defaults) { emit!( self, Instruction::SetFunctionAttribute { - flag: bytecode::MakeFunctionFlag::Defaults + flag: MakeFunctionFlag::Defaults } ); } // Set type_params if present - if flags.contains(&bytecode::MakeFunctionFlag::TypeParams) { + if flags.contains(&MakeFunctionFlag::TypeParams) { emit!( self, Instruction::SetFunctionAttribute { - flag: bytecode::MakeFunctionFlag::TypeParams + flag: MakeFunctionFlag::TypeParams } ); } @@ -5345,7 +5340,7 @@ impl Compiler { // Create the class body function with the .type_params closure // captured through the class code object's freevars. - self.make_closure(class_code, bytecode::MakeFunctionFlags::new())?; + self.make_closure(class_code, MakeFunctionFlags::new())?; self.emit_load_const(ConstantData::Str { value: name.into() }); // Create .generic_base after the class function and name are on the @@ -5496,7 +5491,7 @@ impl Compiler { // Execute the type params function self.set_source_range(class_source_range); - self.make_closure(type_params_code, bytecode::MakeFunctionFlags::new())?; + self.make_closure(type_params_code, MakeFunctionFlags::new())?; self.set_source_range(class_source_range); emit!(self, Instruction::PushNull); self.set_source_range(class_source_range); @@ -5507,7 +5502,7 @@ impl Compiler { emit!(self, Instruction::PushNull); // Create class function with closure - self.make_closure(class_code, bytecode::MakeFunctionFlags::new())?; + self.make_closure(class_code, MakeFunctionFlags::new())?; self.emit_load_const(ConstantData::Str { value: name.into() }); if let Some(arguments) = arguments { @@ -8225,12 +8220,12 @@ impl Compiler { } self.enter_function(&name, params)?; - let mut func_flags = bytecode::MakeFunctionFlags::new(); + let mut func_flags = MakeFunctionFlags::new(); if have_defaults { - func_flags.insert(bytecode::MakeFunctionFlag::Defaults); + func_flags.insert(MakeFunctionFlag::Defaults); } if have_kwdefaults { - func_flags.insert(bytecode::MakeFunctionFlag::KwOnlyDefaults); + func_flags.insert(MakeFunctionFlag::KwOnlyDefaults); } // Set qualname for lambda @@ -9593,7 +9588,7 @@ impl Compiler { // Create comprehension function with closure self.set_source_range(comprehension_range); - self.make_closure(code, bytecode::MakeFunctionFlags::new())?; + self.make_closure(code, MakeFunctionFlags::new())?; // Evaluate iterated item and get its iterator. self.compile_comprehension_iter(outermost)?; diff --git a/crates/vm/src/py_io.rs b/crates/vm/src/py_io.rs index 5649463b30e..aa3fea8e545 100644 --- a/crates/vm/src/py_io.rs +++ b/crates/vm/src/py_io.rs @@ -1,14 +1,15 @@ +use core::{fmt, ops}; +use std::io; + use crate::{ PyObject, PyObjectRef, PyResult, VirtualMachine, builtins::{PyBaseExceptionRef, PyBytes, PyStr}, common::ascii, }; -use alloc::fmt; -use core::ops; -use std::io; pub trait Write { type Error; + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), Self::Error>; } @@ -24,10 +25,12 @@ impl IoWriter { impl ops::Deref for IoWriter { type Target = T; + fn deref(&self) -> &T { &self.0 } } + impl ops::DerefMut for IoWriter { fn deref_mut(&mut self) -> &mut T { &mut self.0 @@ -39,6 +42,7 @@ where W: io::Write, { type Error = io::Error; + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { ::write_fmt(&mut self.0, args) } @@ -46,6 +50,7 @@ where impl Write for String { type Error = fmt::Error; + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result { ::write_fmt(self, args) } @@ -55,8 +60,10 @@ pub struct PyWriter<'vm>(pub PyObjectRef, pub &'vm VirtualMachine); impl Write for PyWriter<'_> { type Error = PyBaseExceptionRef; + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), Self::Error> { - let PyWriter(obj, vm) = self; + let Self(obj, vm) = self; + vm.call_method(obj, "write", (args.to_string(),)).map(drop) } } @@ -70,6 +77,7 @@ pub fn file_readline(obj: &PyObject, size: Option, vm: &VirtualMachine) - vec![vm.ctx.new_str(ascii!("EOF when reading a line")).into()], ) }; + let ret = match_class!(match ret { s @ PyStr => { // Use as_wtf8() to handle strings with surrogates (e.g., surrogateescape) @@ -77,6 +85,7 @@ pub fn file_readline(obj: &PyObject, size: Option, vm: &VirtualMachine) - if s_wtf8.is_empty() { return Err(eof_err()); } + // '\n' is ASCII, so we can check bytes directly if s_wtf8.as_bytes().last() == Some(&b'\n') { let no_nl = &s_wtf8[..s_wtf8.len() - 1]; @@ -90,13 +99,14 @@ pub fn file_readline(obj: &PyObject, size: Option, vm: &VirtualMachine) - if buf.is_empty() { return Err(eof_err()); } + if buf.last() == Some(&b'\n') { vm.ctx.new_bytes(buf[..buf.len() - 1].to_owned()).into() } else { b.into() } } - _ => return Err(vm.new_type_error("object.readline() returned non-string".to_owned())), + _ => return Err(vm.new_type_error("object.readline() returned non-string")), }); Ok(ret) } diff --git a/crates/vm/src/py_serde.rs b/crates/vm/src/py_serde.rs index 945068113f1..50ea4422b16 100644 --- a/crates/vm/src/py_serde.rs +++ b/crates/vm/src/py_serde.rs @@ -111,8 +111,9 @@ pub struct PyObjectDeserializer<'c> { } impl<'c> PyObjectDeserializer<'c> { - pub fn new(vm: &'c VirtualMachine) -> Self { - PyObjectDeserializer { vm } + #[must_use] + pub const fn new(vm: &'c VirtualMachine) -> Self { + Self { vm } } } diff --git a/crates/vm/src/readline.rs b/crates/vm/src/readline.rs index bd0ecd73912..53475358ce6 100644 --- a/crates/vm/src/readline.rs +++ b/crates/vm/src/readline.rs @@ -12,7 +12,7 @@ pub enum ReadlineResult { Line(String), Eof, Interrupt, - Io(std::io::Error), + Io(io::Error), #[cfg(unix)] OsError(String), Other(OtherError), From 04cc652c3da5de06488520ffc3091f727e07a8eb Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 20 Jun 2026 12:41:27 +0300 Subject: [PATCH 2/5] Move Compiler::constant_truthiness to a ConstantData method --- Cargo.lock | 1 + crates/codegen/src/compile.rs | 26 +++++--------------------- crates/compiler-core/Cargo.toml | 1 + crates/compiler-core/src/bytecode.rs | 25 +++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f916ef8cdb..706164e8411 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3552,6 +3552,7 @@ dependencies = [ "lz4_flex", "malachite-bigint", "num-complex", + "num-traits", "rustpython-ruff_source_file", "rustpython-wtf8", ] diff --git a/crates/codegen/src/compile.rs b/crates/codegen/src/compile.rs index 36f92092d67..8127fd53005 100644 --- a/crates/codegen/src/compile.rs +++ b/crates/codegen/src/compile.rs @@ -456,22 +456,6 @@ enum CollectionType { const STACK_USE_GUIDELINE: u32 = 30; impl Compiler { - fn constant_truthiness(constant: &ConstantData) -> bool { - match constant { - ConstantData::Tuple { elements } | ConstantData::Frozenset { elements } => { - !elements.is_empty() - } - ConstantData::Integer { value } => !value.is_zero(), - ConstantData::Float { value } => *value != 0.0, - ConstantData::Complex { value } => value.re != 0.0 || value.im != 0.0, - ConstantData::Boolean { value } => *value, - ConstantData::Str { value } => !value.is_empty(), - ConstantData::Bytes { value } => !value.is_empty(), - ConstantData::Code { .. } | ConstantData::Slice { .. } | ConstantData::Ellipsis => true, - ConstantData::None => false, - } - } - fn new(opts: CompileOpts, source_file: SourceFile, code_name: &str) -> Self { let module_code = ir::CodeInfo { // CPython convention: top-level module / interactive / @@ -10550,7 +10534,7 @@ impl Compiler { } (ast::UnaryOp::Not, ConstantData::Tuple { .. }) => return Ok(None), (ast::UnaryOp::Not, value) => ConstantData::Boolean { - value: !Self::constant_truthiness(&value), + value: !value.truthiness(), }, _ => return Ok(None), } @@ -10570,9 +10554,9 @@ impl Compiler { let mut selected = first; match op { ast::BoolOp::Or => { - if !Self::constant_truthiness(&selected) { + if !selected.truthiness() { for constant in iter { - let is_truthy = Self::constant_truthiness(&constant); + let is_truthy = constant.truthiness(); selected = constant; if is_truthy { break; @@ -10581,9 +10565,9 @@ impl Compiler { } } ast::BoolOp::And => { - if Self::constant_truthiness(&selected) { + if selected.truthiness() { for constant in iter { - let is_truthy = Self::constant_truthiness(&constant); + let is_truthy = constant.truthiness(); selected = constant; if !is_truthy { break; diff --git a/crates/compiler-core/Cargo.toml b/crates/compiler-core/Cargo.toml index 7d6d116f530..22201597d90 100644 --- a/crates/compiler-core/Cargo.toml +++ b/crates/compiler-core/Cargo.toml @@ -18,6 +18,7 @@ bitflagset = { workspace = true } itertools = { workspace = true } malachite-bigint = { workspace = true } num-complex = { workspace = true } +num-traits = { workspace = true } lz4_flex = { workspace = true } diff --git a/crates/compiler-core/src/bytecode.rs b/crates/compiler-core/src/bytecode.rs index e5ef24815a1..8994daadd4b 100644 --- a/crates/compiler-core/src/bytecode.rs +++ b/crates/compiler-core/src/bytecode.rs @@ -17,6 +17,7 @@ use core::{ use itertools::Itertools; use malachite_bigint::BigInt; use num_complex::Complex64; +use num_traits::Zero; use rustpython_wtf8::{Wtf8, Wtf8Buf}; pub use crate::bytecode::{ @@ -909,6 +910,30 @@ pub enum ConstantData { Ellipsis, } +impl ConstantData { + /// Whether or not python would return True/False for the given constant data. + /// + /// ```py + /// bool(0) # False + /// bool(1) # True + /// bool([]) # False + /// bool(...) # True + /// ``` + pub fn truthiness(&self) -> bool { + match self { + Self::Tuple { elements } | Self::Frozenset { elements } => !elements.is_empty(), + Self::Integer { value } => !value.is_zero(), + Self::Float { value } => *value != 0.0, + Self::Complex { value } => value.re != 0.0 || value.im != 0.0, + Self::Boolean { value } => *value, + Self::Str { value } => !value.is_empty(), + Self::Bytes { value } => !value.is_empty(), + Self::Code { .. } | Self::Slice { .. } | Self::Ellipsis => true, + Self::None => false, + } + } +} + impl PartialEq for ConstantData { fn eq(&self, other: &Self) -> bool { match (self, other) { From 76a60407b0c6157fa9786b8c1b8efca49432eb6c Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 20 Jun 2026 13:03:07 +0300 Subject: [PATCH 3/5] More code cleanup --- crates/codegen/src/compile.rs | 126 ++++++++++++++++------------------ 1 file changed, 59 insertions(+), 67 deletions(-) diff --git a/crates/codegen/src/compile.rs b/crates/codegen/src/compile.rs index 8127fd53005..571a1d85a42 100644 --- a/crates/codegen/src/compile.rs +++ b/crates/codegen/src/compile.rs @@ -31,7 +31,8 @@ use rustpython_compiler_core::{ self, AnyInstruction, AnyOpcode, Arg as OpArgMarker, BinaryOperator, BuildSliceArgCount, CodeObject, ComparisonOperator, ConstantData, ConvertValueOparg, Instruction, IntrinsicFunction1, Invert, LoadAttr, LoadSuperAttr, MakeFunctionFlag, MakeFunctionFlags, - OpArg, OpArgType, PseudoInstruction, SpecialMethod, UnpackExArgs, oparg, + OpArg, OpArgType, Opcode, PseudoInstruction, PseudoOpcode, SpecialMethod, UnpackExArgs, + oparg, }, }; use rustpython_wtf8::Wtf8Buf; @@ -1178,13 +1179,10 @@ impl Compiler { let source_path = self.source_file.name().to_owned(); // Lookup symbol table entry using key (_PySymtable_Lookup) - let ste = match self.symbol_table_stack.get(key) { - Some(v) => v, - None => { - return Err(self.error(CodegenErrorType::SyntaxError( - "unknown symbol table entry".to_owned(), - ))); - } + let Some(ste) = self.symbol_table_stack.get(key) else { + return Err(self.error(CodegenErrorType::SyntaxError( + "unknown symbol table entry".into(), + ))); }; // Use varnames from symbol table (already collected in definition order) @@ -1255,16 +1253,21 @@ impl Compiler { .collect() }) .unwrap_or_default(); - let mut free_names: Vec<_> = ste + + let mut free_names = ste .symbols .iter() .filter(|(_, s)| { - s.scope == SymbolScope::Free - || (scope_type != CompilerScope::Class - && s.flags.contains(SymbolFlags::FREE_CLASS)) - || (scope_type == CompilerScope::Class - && s.flags.contains(SymbolFlags::FREE_CLASS) - && self.has_enclosing_non_module_code_scope()) + if s.scope == SymbolScope::Free { + return true; + } + + let has_free_class = s.flags.contains(SymbolFlags::FREE_CLASS); + if scope_type == CompilerScope::Class { + has_free_class && self.has_enclosing_non_module_code_scope() + } else { + has_free_class + } }) .filter(|(name, symbol)| { if !matches!( @@ -1276,7 +1279,8 @@ impl Compiler { !(annotation_free_names.contains(*name) && symbol.flags.is_empty()) }) .map(|(name, _)| name.clone()) - .collect(); + .collect::>(); + free_names.sort(); for name in free_names { freevar_cache.insert(name); @@ -1418,10 +1422,7 @@ impl Compiler { let except_handler = None; self.cpython_cfg_builder_addop(ir::InstructionInfo { - instr: Instruction::Resume { - context: OpArgMarker::marker(), - } - .into(), + instr: Opcode::Resume.into(), arg: OpArg::new(oparg::ResumeLocation::AtFuncStart.into()), target: BlockIdx::NULL, location, @@ -4851,7 +4852,7 @@ impl Compiler { /// Determines if a variable should be CELL or FREE type // = get_ref_type fn get_ref_type(&self, name: &str) -> Result { - let table = self.symbol_table_stack.last().unwrap(); + let table = self.current_symbol_table(); // Special handling for __class__, __classdict__, and __conditional_annotations__ in class scope // This should only apply when we're actually IN a class body, @@ -4864,19 +4865,23 @@ impl Compiler { { return Ok(SymbolScope::Cell); } - match table.lookup(name) { - Some(symbol) => match symbol.scope { - SymbolScope::Cell => Ok(SymbolScope::Cell), - SymbolScope::Free => Ok(SymbolScope::Free), - _ if symbol.flags.contains(SymbolFlags::FREE_CLASS) => Ok(SymbolScope::Free), - _ => Err(CodegenErrorType::SyntaxError(format!( - "get_ref_type: invalid scope for '{name}'" - ))), - }, - None => Err(CodegenErrorType::SyntaxError(format!( + + let Some(symbol) = table.lookup(name) else { + return Err(CodegenErrorType::SyntaxError(format!( "get_ref_type: cannot find symbol '{name}'" - ))), - } + ))); + }; + + Ok(match symbol.scope { + SymbolScope::Cell => SymbolScope::Cell, + SymbolScope::Free => SymbolScope::Free, + _ if symbol.flags.contains(SymbolFlags::FREE_CLASS) => SymbolScope::Free, + _ => { + return Err(CodegenErrorType::SyntaxError(format!( + "get_ref_type: invalid scope for '{name}'" + ))); + } + }) } /// Loads closure variables if needed and creates a function object @@ -8249,12 +8254,7 @@ impl Compiler { }) => { self.compile_comprehension( "", - Some( - Instruction::BuildList { - count: OpArgMarker::marker(), - } - .into(), - ), + Some(Opcode::BuildList.into()), generators, &|compiler, collection_add_i| { compiler.compile_comprehension_element(elt)?; @@ -8282,12 +8282,7 @@ impl Compiler { }) => { self.compile_comprehension( "", - Some( - Instruction::BuildSet { - count: OpArgMarker::marker(), - } - .into(), - ), + Some(Opcode::BuildSet.into()), generators, &|compiler, collection_add_i| { compiler.compile_comprehension_element(elt)?; @@ -8316,12 +8311,7 @@ impl Compiler { }) => { self.compile_comprehension( "", - Some( - Instruction::BuildMap { - count: OpArgMarker::marker(), - } - .into(), - ), + Some(Opcode::BuildMap.into()), generators, &|compiler, collection_add_i| { // changed evaluation order for Py38 named expression PEP 572 @@ -10071,18 +10061,22 @@ impl Compiler { } let instr = instr.into(); let opcode = AnyOpcode::from(instr); + debug_assert!( !instr.is_assembler(), "CPython codegen_addop_* must not emit assembler-only opcodes" ); + debug_assert!( opcode.has_arg() || instr.has_target() || u32::from(arg) == 0, "CPython _PyInstructionSequence_Addop requires either OPCODE_HAS_ARG, HAS_TARGET, or oparg == 0" ); + debug_assert!( target == BlockIdx::NULL || instr.has_target(), "CPython codegen_addop_j only accepts HAS_TARGET opcodes" ); + let range = self.current_source_range; let source = self.source_file.to_source_code(); let location = source.source_location(range.start(), PositionEncoding::Utf8); @@ -10166,6 +10160,7 @@ impl Compiler { .blocks .first_mut() .expect("code unit must have an entry block"); + debug_assert!( entry .used_instructions() @@ -10179,14 +10174,11 @@ impl Compiler { }), "scope entry must start with a function-start RESUME" ); + debug_assert!( !entry.used_instructions().iter().any(|info| matches!( - info.instr.real(), - Some( - Instruction::ReturnGenerator - | Instruction::MakeCell { .. } - | Instruction::CopyFreeVars { .. } - ) + info.instr.real_opcode(), + Some(Opcode::ReturnGenerator | Opcode::MakeCell | Opcode::CopyFreeVars) )), "CPython inserts StopIteration cleanup before CFG prefix instructions" ); @@ -10893,12 +10885,17 @@ impl Compiler { _ => {} } } + if !found_loop { - if is_break { - return Err(self.error_ranged(CodegenErrorType::InvalidBreak, range)); - } - return Err(self.error_ranged(CodegenErrorType::InvalidContinue, range)); + let err_type = if is_break { + CodegenErrorType::InvalidBreak + } else { + CodegenErrorType::InvalidContinue + }; + + return Err(self.error_ranged(err_type, range)); } + return Ok(()); } @@ -10935,12 +10932,7 @@ impl Compiler { } else { self.set_source_range(range); }; - self.emit_jump_label( - PseudoInstruction::Jump { - delta: OpArgMarker::marker(), - }, - target_label, - ); + self.emit_jump_label(PseudoOpcode::Jump, target_label); if unwind_loc.is_none() { self.set_no_location(); } From 93bb0e7c6675b53819030f373e9fd96ee13af19c Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 20 Jun 2026 13:30:53 +0300 Subject: [PATCH 4/5] bytecode::CodeFlags -> CodeFlags --- crates/codegen/src/compile.rs | 139 +++++++++++++--------------------- 1 file changed, 52 insertions(+), 87 deletions(-) diff --git a/crates/codegen/src/compile.rs b/crates/codegen/src/compile.rs index 571a1d85a42..4f12a729eb7 100644 --- a/crates/codegen/src/compile.rs +++ b/crates/codegen/src/compile.rs @@ -29,7 +29,7 @@ use rustpython_compiler_core::{ Mode, OneIndexed, PositionEncoding, SourceFile, SourceLocation, bytecode::{ self, AnyInstruction, AnyOpcode, Arg as OpArgMarker, BinaryOperator, BuildSliceArgCount, - CodeObject, ComparisonOperator, ConstantData, ConvertValueOparg, Instruction, + CodeFlags, CodeObject, ComparisonOperator, ConstantData, ConvertValueOparg, Instruction, IntrinsicFunction1, Invert, LoadAttr, LoadSuperAttr, MakeFunctionFlag, MakeFunctionFlags, OpArg, OpArgType, Opcode, PseudoInstruction, PseudoOpcode, SpecialMethod, UnpackExArgs, oparg, @@ -467,7 +467,7 @@ impl Compiler { // empty flags. frame.rs:725-731 then binds locals to globals // for module/REPL frames whose `scope.locals` is None - the // correct semantics for `exec(code, globals)` and module init. - flags: bytecode::CodeFlags::empty(), + flags: CodeFlags::empty(), source_path: source_file.name().to_owned(), private: None, blocks: vec![ir::Block::default()], @@ -1288,28 +1288,23 @@ impl Compiler { // Initialize u_metadata fields let (mut flags, posonlyarg_count, arg_count, kwonlyarg_count) = match scope_type { - CompilerScope::Module => (bytecode::CodeFlags::empty(), 0, 0, 0), - CompilerScope::Class => (bytecode::CodeFlags::empty(), 0, 0, 0), + CompilerScope::Module => (CodeFlags::empty(), 0, 0, 0), + CompilerScope::Class => (CodeFlags::empty(), 0, 0, 0), CompilerScope::Function | CompilerScope::AsyncFunction | CompilerScope::Lambda => ( - bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED, + CodeFlags::NEWLOCALS | CodeFlags::OPTIMIZED, 0, // Will be set later in enter_function 0, // Will be set later in enter_function 0, // Will be set later in enter_function ), CompilerScope::Comprehension => ( - bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED, + CodeFlags::NEWLOCALS | CodeFlags::OPTIMIZED, 0, 1, // comprehensions take one argument (.0) 0, ), - CompilerScope::TypeParams => ( - bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED, - 0, - 0, - 0, - ), + CompilerScope::TypeParams => (CodeFlags::NEWLOCALS | CodeFlags::OPTIMIZED, 0, 0, 0), CompilerScope::Annotation => ( - bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED, + CodeFlags::NEWLOCALS | CodeFlags::OPTIMIZED, 1, // format is positional-only 1, // annotation scope takes one argument (format) 0, @@ -1317,7 +1312,7 @@ impl Compiler { }; if ste.is_method { - flags |= bytecode::CodeFlags::METHOD; + flags |= CodeFlags::METHOD; } // CPython sets CO_NESTED from symtable's ste_nested, not merely @@ -1333,12 +1328,12 @@ impl Compiler { | CompilerScope::Annotation | CompilerScope::TypeParams ) { - flags | bytecode::CodeFlags::NESTED + flags | CodeFlags::NESTED } else { flags }; if self.future_annotations { - flags |= bytecode::CodeFlags::FUTURE_ANNOTATIONS; + flags |= CodeFlags::FUTURE_ANNOTATIONS; } // Get private name from parent scope @@ -1460,9 +1455,7 @@ impl Compiler { // Preserve flags computed from the symbol-table context. info.flags = flags | (info.flags - & (bytecode::CodeFlags::NESTED - | bytecode::CodeFlags::METHOD - | bytecode::CodeFlags::FUTURE_ANNOTATIONS)); + & (CodeFlags::NESTED | CodeFlags::METHOD | CodeFlags::FUTURE_ANNOTATIONS)); info.metadata.argcount = arg_count; info.metadata.posonlyargcount = posonlyarg_count; info.metadata.kwonlyargcount = kwonlyarg_count; @@ -2057,7 +2050,7 @@ impl Compiler { if self.future_annotations { self.current_code_info() .flags - .insert(bytecode::CodeFlags::FUTURE_ANNOTATIONS); + .insert(CodeFlags::FUTURE_ANNOTATIONS); } // Module-level __conditional_annotations__ cell @@ -2128,7 +2121,7 @@ impl Compiler { if self.future_annotations { self.current_code_info() .flags - .insert(bytecode::CodeFlags::FUTURE_ANNOTATIONS); + .insert(CodeFlags::FUTURE_ANNOTATIONS); } self.symbol_table_stack.push(symbol_table); let module_start_loc = self.module_start_location(body); @@ -3213,7 +3206,7 @@ impl Compiler { } self.push_output( - bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED, + CodeFlags::NEWLOCALS | CodeFlags::OPTIMIZED, parameters.posonlyargs.len().to_u32(), (parameters.posonlyargs.len() + parameters.args.len()).to_u32(), parameters.kwonlyargs.len().to_u32(), @@ -3231,11 +3224,11 @@ impl Compiler { } if let Some(name) = parameters.vararg.as_deref() { - self.current_code_info().flags |= bytecode::CodeFlags::VARARGS; + self.current_code_info().flags |= CodeFlags::VARARGS; self.varname(name.name.as_str()); } if let Some(name) = parameters.kwarg.as_deref() { - self.current_code_info().flags |= bytecode::CodeFlags::VARKEYWORDS; + self.current_code_info().flags |= CodeFlags::VARKEYWORDS; self.varname(name.name.as_str()); } @@ -4254,7 +4247,7 @@ impl Compiler { self.enter_function(name, parameters)?; self.current_code_info() .flags - .set(bytecode::CodeFlags::COROUTINE, is_async); + .set(CodeFlags::COROUTINE, is_async); // Set up context let prev_ctx = self.ctx; @@ -4283,7 +4276,7 @@ impl Compiler { .insert_full(ConstantData::Str { value: (*doc).to_string().into(), }); - self.current_code_info().flags |= bytecode::CodeFlags::HAS_DOCSTRING; + self.current_code_info().flags |= CodeFlags::HAS_DOCSTRING; } let start_label = self.use_cpython_function_start_label(); @@ -4729,7 +4722,7 @@ impl Compiler { // Enter type params scope let type_params_name = format!(""); self.push_output( - bytecode::CodeFlags::OPTIMIZED | bytecode::CodeFlags::NEWLOCALS, + CodeFlags::OPTIMIZED | CodeFlags::NEWLOCALS, 0, num_typeparam_args, 0, @@ -5286,7 +5279,7 @@ impl Compiler { if is_generic { let type_params_name = format!(""); self.push_output( - bytecode::CodeFlags::OPTIMIZED | bytecode::CodeFlags::NEWLOCALS, + CodeFlags::OPTIMIZED | CodeFlags::NEWLOCALS, 0, 0, 0, @@ -9278,9 +9271,7 @@ impl Compiler { if let Some(info) = self.code_stack.last_mut() { info.flags = flags | (info.flags - & (bytecode::CodeFlags::NESTED - | bytecode::CodeFlags::METHOD - | bytecode::CodeFlags::FUTURE_ANNOTATIONS)); + & (CodeFlags::NESTED | CodeFlags::METHOD | CodeFlags::FUTURE_ANNOTATIONS)); info.metadata.argcount = arg_count; info.metadata.posonlyargcount = posonlyarg_count; info.metadata.kwonlyargcount = kwonlyarg_count; @@ -9364,9 +9355,9 @@ impl Compiler { in_async_scope: prev_ctx.in_async_scope || is_async, }; - let flags = bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED; + let flags = CodeFlags::NEWLOCALS | CodeFlags::OPTIMIZED; let flags = if is_async { - flags | bytecode::CodeFlags::COROUTINE + flags | CodeFlags::COROUTINE } else { flags }; @@ -11162,10 +11153,10 @@ impl Compiler { let is_async = self.ctx.func == FunctionContext::AsyncFunction; let flags = &mut self.current_code_info().flags; if is_async { - flags.remove(bytecode::CodeFlags::COROUTINE); - flags.insert(bytecode::CodeFlags::ASYNC_GENERATOR); + flags.remove(CodeFlags::COROUTINE); + flags.insert(CodeFlags::ASYNC_GENERATOR); } else { - flags.insert(bytecode::CodeFlags::GENERATOR); + flags.insert(CodeFlags::GENERATOR); } } @@ -12209,10 +12200,8 @@ mod tests { fn assert_scope_exit_locations(code: &CodeObject) { for (instr, (location, _)) in code.instructions.iter().zip(code.locations.iter()) { if matches!( - instr.op, - Instruction::ReturnValue - | Instruction::RaiseVarargs { .. } - | Instruction::Reraise { .. } + instr.op.into(), + Opcode::ReturnValue | Opcode::RaiseVarargs | Opcode::Reraise ) { assert!( location.line.get() > 0, @@ -12410,7 +12399,7 @@ def f(x, y, z): compiler .current_code_info() .flags - .set(bytecode::CodeFlags::COROUTINE, is_async); + .set(CodeFlags::COROUTINE, is_async); let prev_ctx = compiler.ctx; compiler.ctx = CompileContext { @@ -14728,13 +14717,13 @@ def f(): for code in [method, async_method, lambda, genexpr] { assert!( - code.flags.contains(bytecode::CodeFlags::METHOD), + code.flags.contains(CodeFlags::METHOD), "class-scope function-like code should carry CO_METHOD like CPython 3.14, got {:?}", code.flags ); } assert!( - !module_function.flags.contains(bytecode::CodeFlags::METHOD), + !module_function.flags.contains(CodeFlags::METHOD), "module-scope function must not carry CO_METHOD" ); } @@ -14753,11 +14742,11 @@ class C: let class_code = find_code(&code, "C").expect("missing class code"); let lambda = find_code(class_code, "").expect("missing lambda code"); assert!( - lambda.flags.contains(bytecode::CodeFlags::NESTED), + lambda.flags.contains(CodeFlags::NESTED), "lambda under inlined class comprehension should stay nested" ); assert!( - !lambda.flags.contains(bytecode::CodeFlags::METHOD), + !lambda.flags.contains(CodeFlags::METHOD), "CPython creates this lambda while the current symtable block is the comprehension, not the class" ); } @@ -14793,37 +14782,17 @@ async def ag(): let coroutine = find_code(&code, "c").expect("missing coroutine code"); let async_generator = find_code(&code, "ag").expect("missing async generator code"); - assert!(generator.flags.contains(bytecode::CodeFlags::GENERATOR)); - assert!(!generator.flags.contains(bytecode::CodeFlags::COROUTINE)); - assert!( - !generator - .flags - .contains(bytecode::CodeFlags::ASYNC_GENERATOR) - ); + assert!(generator.flags.contains(CodeFlags::GENERATOR)); + assert!(!generator.flags.contains(CodeFlags::COROUTINE)); + assert!(!generator.flags.contains(CodeFlags::ASYNC_GENERATOR)); - assert!(coroutine.flags.contains(bytecode::CodeFlags::COROUTINE)); - assert!(!coroutine.flags.contains(bytecode::CodeFlags::GENERATOR)); - assert!( - !coroutine - .flags - .contains(bytecode::CodeFlags::ASYNC_GENERATOR) - ); + assert!(coroutine.flags.contains(CodeFlags::COROUTINE)); + assert!(!coroutine.flags.contains(CodeFlags::GENERATOR)); + assert!(!coroutine.flags.contains(CodeFlags::ASYNC_GENERATOR)); - assert!( - async_generator - .flags - .contains(bytecode::CodeFlags::ASYNC_GENERATOR) - ); - assert!( - !async_generator - .flags - .contains(bytecode::CodeFlags::GENERATOR) - ); - assert!( - !async_generator - .flags - .contains(bytecode::CodeFlags::COROUTINE) - ); + assert!(async_generator.flags.contains(CodeFlags::ASYNC_GENERATOR)); + assert!(!async_generator.flags.contains(CodeFlags::GENERATOR)); + assert!(!async_generator.flags.contains(CodeFlags::COROUTINE)); } #[test] @@ -24064,15 +24033,11 @@ def f(): return C ", ); - assert!(code.flags.contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS)); + assert!(code.flags.contains(CodeFlags::FUTURE_ANNOTATIONS)); let f = find_code(&code, "f").expect("missing f code"); - assert!(f.flags.contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS)); + assert!(f.flags.contains(CodeFlags::FUTURE_ANNOTATIONS)); let class_code = find_code(f, "C").expect("missing C code"); - assert!( - class_code - .flags - .contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS) - ); + assert!(class_code.flags.contains(CodeFlags::FUTURE_ANNOTATIONS)); } #[test] @@ -24091,7 +24056,7 @@ def outer(): let class_annotate = find_code(class_code, "__annotate__").expect("missing class annotation code"); assert!( - !class_annotate.flags.contains(bytecode::CodeFlags::NESTED), + !class_annotate.flags.contains(CodeFlags::NESTED), "module-level class annotation scope should not be nested" ); @@ -24100,7 +24065,7 @@ def outer(): let nested_annotate = find_code(nested_class, "__annotate__").expect("missing nested annotation code"); assert!( - nested_annotate.flags.contains(bytecode::CodeFlags::NESTED), + nested_annotate.flags.contains(CodeFlags::NESTED), "annotation scope under a nested class should be nested" ); } @@ -24115,25 +24080,25 @@ type A[T] = T ); let outer_lambda = find_code(&code, "").expect("missing outer lambda code"); assert!( - !outer_lambda.flags.contains(bytecode::CodeFlags::NESTED), + !outer_lambda.flags.contains(CodeFlags::NESTED), "module-level lambda should not be nested" ); let inner_lambda = find_direct_child_code(outer_lambda, "").expect("missing inner lambda code"); assert!( - inner_lambda.flags.contains(bytecode::CodeFlags::NESTED), + inner_lambda.flags.contains(CodeFlags::NESTED), "lambda inside lambda should be nested" ); let type_params = find_code(&code, "").expect("missing type params code"); assert!( - !type_params.flags.contains(bytecode::CodeFlags::NESTED), + !type_params.flags.contains(CodeFlags::NESTED), "module-level type-parameter scope should not be nested" ); let type_alias = find_direct_child_code(type_params, "A").expect("missing type alias code"); assert!( - type_alias.flags.contains(bytecode::CodeFlags::NESTED), + type_alias.flags.contains(CodeFlags::NESTED), "type alias body inside type-parameter scope should be nested" ); } From eef595059447c55dea04043c4ced95fd5960ba41 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 20 Jun 2026 13:56:34 +0300 Subject: [PATCH 5/5] More code clenaups --- crates/codegen/src/ir.rs | 345 +++++++++------------------ crates/codegen/src/string_parser.rs | 1 + crates/compiler-core/src/bytecode.rs | 1 + crates/vm/src/function/buffer.rs | 23 +- crates/vm/src/function/builtin.rs | 7 +- crates/vm/src/function/either.rs | 24 +- crates/vm/src/function/getset.rs | 4 +- crates/vm/src/function/method.rs | 1 + 8 files changed, 153 insertions(+), 253 deletions(-) diff --git a/crates/codegen/src/ir.rs b/crates/codegen/src/ir.rs index f22efe8e52d..89b6896c69f 100644 --- a/crates/codegen/src/ir.rs +++ b/crates/codegen/src/ir.rs @@ -9,10 +9,10 @@ use rustpython_wtf8::Wtf8Buf; use rustpython_compiler_core::{ OneIndexed, SourceLocation, bytecode::{ - AnyInstruction, AnyOpcode, Arg, CO_FAST_ARG_KW, CO_FAST_ARG_POS, CO_FAST_ARG_VAR, - CO_FAST_CELL, CO_FAST_FREE, CO_FAST_HIDDEN, CO_FAST_LOCAL, CodeFlags, CodeObject, CodeUnit, - CodeUnits, ConstantData, InstrDisplayContext, Instruction, IntrinsicFunction1, OpArg, - OpArgByte, Opcode, PseudoInstruction, PseudoOpcode, PyCodeLocationInfoKind, oparg, + AnyInstruction, AnyOpcode, CO_FAST_ARG_KW, CO_FAST_ARG_POS, CO_FAST_ARG_VAR, CO_FAST_CELL, + CO_FAST_FREE, CO_FAST_HIDDEN, CO_FAST_LOCAL, CodeFlags, CodeObject, CodeUnit, CodeUnits, + ConstantData, InstrDisplayContext, Instruction, IntrinsicFunction1, OpArg, OpArgByte, + Opcode, PseudoInstruction, PseudoOpcode, PyCodeLocationInfoKind, oparg, }, varint::{write_signed_varint, write_varint}, }; @@ -832,7 +832,7 @@ fn instr_size(instr: &InstructionInfo) -> usize { } /// pycore_opcode_metadata.h is_pseudo_target -fn is_pseudo_target(pseudo: PseudoOpcode, target: Opcode) -> bool { +const fn is_pseudo_target(pseudo: PseudoOpcode, target: Opcode) -> bool { match pseudo { PseudoOpcode::LoadClosure => matches!(target, Opcode::LoadFast), PseudoOpcode::StoreFastMaybeNull => matches!(target, Opcode::StoreFast), @@ -874,16 +874,11 @@ fn resolve_unconditional_jumps( AnyInstruction::Pseudo(PseudoInstruction::Jump { .. }) => { debug_assert!(is_pseudo_target(PseudoOpcode::Jump, Opcode::JumpForward)); debug_assert!(is_pseudo_target(PseudoOpcode::Jump, Opcode::JumpBackward)); + if is_forward { - instr.instr = Instruction::JumpForward { - delta: Arg::marker(), - } - .into(); + instr.instr = Opcode::JumpForward.into(); } else { - instr.instr = Instruction::JumpBackward { - delta: Arg::marker(), - } - .into(); + instr.instr = Opcode::JumpBackward.into(); } } AnyInstruction::Pseudo(PseudoInstruction::JumpNoInterrupt { .. }) => { @@ -896,15 +891,9 @@ fn resolve_unconditional_jumps( Opcode::JumpBackwardNoInterrupt )); if is_forward { - instr.instr = Instruction::JumpForward { - delta: Arg::marker(), - } - .into(); + instr.instr = Opcode::JumpForward.into(); } else { - instr.instr = Instruction::JumpBackwardNoInterrupt { - delta: Arg::marker(), - } - .into(); + instr.instr = Opcode::JumpBackwardNoInterrupt.into(); } } _ => { @@ -1319,7 +1308,8 @@ impl Block { &self.instructions[..self.instruction_used] } - pub(crate) fn is_empty(&self) -> bool { + #[must_use] + pub(crate) const fn is_empty(&self) -> bool { self.instruction_used == 0 } } @@ -1717,10 +1707,7 @@ impl CodeInfo { &mut self.instr_sequence, 0, InstructionInfo { - instr: PseudoInstruction::SetupCleanup { - delta: Arg::marker(), - } - .into(), + instr: PseudoOpcode::SetupCleanup.into(), arg: instruction_sequence_label_oparg(handler_label), target: BlockIdx::NULL, location: SourceLocation::default(), @@ -1851,7 +1838,6 @@ fn optimized_cfg_to_instruction_sequence( } impl CodeInfo { - #[allow(clippy::needless_range_loop)] pub fn finalize_code( mut self, opts: &crate::compile::CompileOpts, @@ -2016,7 +2002,7 @@ fn insert_prefix_instructions( entry, ncellsused, InstructionInfo { - instr: Instruction::MakeCell { i: Arg::marker() }.into(), + instr: Opcode::MakeCell.into(), arg: OpArg::new(oldindex as u32), target: BlockIdx::NULL, location: SourceLocation::default(), @@ -2034,7 +2020,7 @@ fn insert_prefix_instructions( entry, 0, InstructionInfo { - instr: Instruction::CopyFreeVars { n: Arg::marker() }.into(), + instr: Opcode::CopyFreeVars.into(), arg: OpArg::new(nfreevars as u32), target: BlockIdx::NULL, location: SourceLocation::default(), @@ -2153,7 +2139,7 @@ fn eval_const_unaryop( } (ConstantData::Boolean { .. }, Instruction::UnaryInvert, None) => None, (_, Instruction::UnaryNot, None) => Some(ConstantData::Boolean { - value: !constant_truthiness(operand), + value: !operand.truthiness(), }), ( ConstantData::Integer { value }, @@ -2183,22 +2169,6 @@ fn eval_const_unaryop( } } -fn constant_truthiness(constant: &ConstantData) -> bool { - match constant { - ConstantData::Tuple { elements } | ConstantData::Frozenset { elements } => { - !elements.is_empty() - } - ConstantData::Integer { value } => !value.is_zero(), - ConstantData::Float { value } => *value != 0.0, - ConstantData::Complex { value } => value.re != 0.0 || value.im != 0.0, - ConstantData::Boolean { value } => *value, - ConstantData::Str { value } => !value.is_empty(), - ConstantData::Bytes { value } => !value.is_empty(), - ConstantData::Code { .. } | ConstantData::Slice { .. } | ConstantData::Ellipsis => true, - ConstantData::None => false, - } -} - fn load_const_truthiness( instr: Instruction, arg: OpArg, @@ -2207,7 +2177,7 @@ fn load_const_truthiness( match instr { Instruction::LoadConst { consti } => { let constant = &metadata.consts[consti.get(arg).as_usize()]; - Some(constant_truthiness(constant)) + Some(constant.truthiness()) } Instruction::LoadSmallInt { i } => Some(i.get(arg) != 0), _ => None, @@ -2234,10 +2204,7 @@ fn instr_make_load_const( let const_idx = add_const(metadata, constant)?; instr_set_op1( instr, - Instruction::LoadConst { - consti: Arg::marker(), - } - .into(), + Opcode::LoadConst.into(), OpArg::new(const_idx as u32), ); Ok(()) @@ -2260,12 +2227,7 @@ fn fold_const_unaryop( oparg::IntrinsicFunction1::UnaryPositive ) => { - ( - Instruction::CallIntrinsic1 { - func: Arg::marker(), - }, - Some(func.get(instr.arg)), - ) + (Opcode::CallIntrinsic1.into(), Some(func.get(instr.arg))) } _ => return Ok(false), }; @@ -2337,9 +2299,10 @@ fn fold_const_binop( ) -> crate::InternalResult { use oparg::BinaryOperator as BinOp; - let Some(Instruction::BinaryOp { .. }) = block.instructions[i].instr.real() else { + let Some(Opcode::BinaryOp) = block.instructions[i].instr.real_opcode() else { return Ok(false); }; + let Some(operand_indices) = (if let Some(start) = i.checked_sub(1) { get_const_loading_instrs(block, start, 2)? } else { @@ -2347,18 +2310,22 @@ fn fold_const_binop( }) else { return Ok(false); }; + let op_raw = u32::from(block.instructions[i].arg); let Ok(op) = BinOp::try_from(op_raw) else { return Ok(false); }; + let left = get_const_value(metadata, &block.instructions[operand_indices[0]]); let right = get_const_value(metadata, &block.instructions[operand_indices[1]]); let (Some(left_val), Some(right_val)) = (left, right) else { return Ok(false); }; + let Some(result_const) = eval_const_binop(&left_val, &right_val, op) else { return Ok(false); }; + nop_out(block, &operand_indices); instr_make_load_const(metadata, &mut block.instructions[i], result_const)?; Ok(true) @@ -2366,13 +2333,13 @@ fn fold_const_binop( /// flowgraph.c loads_const fn loads_const(info: &InstructionInfo) -> bool { - info.instr.has_const() || matches!(info.instr.real(), Some(Instruction::LoadSmallInt { .. })) + info.instr.has_const() || matches!(info.instr.real_opcode(), Some(Opcode::LoadSmallInt)) } /// flowgraph.c get_const_value fn get_const_value(metadata: &CodeUnitMetadata, info: &InstructionInfo) -> Option { - match info.instr.real() { - Some(Instruction::LoadSmallInt { .. }) => { + match info.instr.real_opcode() { + Some(Opcode::LoadSmallInt) => { let v = u32::from(info.arg) as i32; Some(ConstantData::Integer { value: BigInt::from(v), @@ -3059,7 +3026,7 @@ fn fold_tuple_of_constants( block: &mut Block, i: usize, ) -> crate::InternalResult { - let Some(Instruction::BuildTuple { .. }) = block.instructions[i].instr.real() else { + let Some(Opcode::BuildTuple) = block.instructions[i].instr.real_opcode() else { return Ok(false); }; @@ -3237,16 +3204,11 @@ fn optimize_lists_and_sets( nop_out(block, &operand_indices); let build_instr = if is_list { - Instruction::BuildList { - count: Arg::marker(), - } - .into() + Opcode::BuildList } else { - Instruction::BuildSet { - count: Arg::marker(), - } - .into() - }; + Opcode::BuildSet + } + .into(); instr_set_op1(&mut block.instructions[i - 2], build_instr, OpArg::new(0)); block.instructions[i - 2].location = folded_loc; block.instructions[i - 2].end_location = end_loc; @@ -3254,10 +3216,7 @@ fn optimize_lists_and_sets( instr_set_op1( &mut block.instructions[i - 1], - Instruction::LoadConst { - consti: Arg::marker(), - } - .into(), + Opcode::LoadConst.into(), OpArg::new(const_idx as u32), ); @@ -3278,10 +3237,7 @@ fn optimize_lists_and_sets( instr_set_op1( &mut block.instructions[i], - Instruction::LoadConst { - consti: Arg::marker(), - } - .into(), + Opcode::LoadConst.into(), OpArg::new(const_idx as u32), ); Ok(true) @@ -3333,21 +3289,21 @@ fn next_swappable_instruction(block: &Block, mut i: usize, lineno: i32) -> Optio /// flowgraph.c swaptimize fn swaptimize(block: &mut Block, ix: &mut usize) -> crate::InternalResult<()> { debug_assert!(matches!( - block.instructions[*ix].instr.real(), - Some(Instruction::Swap { .. }) + block.instructions[*ix].instr.real_opcode(), + Some(Opcode::Swap) )); let mut depth = u32::from(block.instructions[*ix].arg) as usize; let mut len = 1usize; let mut more = false; let limit = block.instruction_used - *ix; while len < limit { - match block.instructions[*ix + len].instr.real() { - Some(Instruction::Swap { .. }) => { + match block.instructions[*ix + len].instr.real_opcode() { + Some(Opcode::Swap) => { depth = depth.max(u32::from(block.instructions[*ix + len].arg) as usize); more = true; len += 1; } - Some(Instruction::Nop) => { + Some(Opcode::Nop) => { len += 1; } _ => break, @@ -3372,7 +3328,7 @@ fn swaptimize(block: &mut Block, ix: &mut usize) -> crate::InternalResult<()> { i = 0; while i < len { let info = &block.instructions[*ix + i]; - if matches!(info.instr.real(), Some(Instruction::Swap { .. })) { + if matches!(info.instr.real_opcode(), Some(Opcode::Swap)) { let oparg = u32::from(info.arg) as usize; stack.swap(0, oparg - 1); } @@ -3416,15 +3372,15 @@ fn apply_static_swaps(block: &mut Block, mut i: isize) { while i >= 0 { let idx = i as usize; debug_assert!(idx < block.instruction_used); - let swap_arg = match block.instructions[idx].instr.real() { - Some(Instruction::Swap { .. }) => u32::from(block.instructions[idx].arg), - Some(Instruction::Nop | Instruction::PopTop | Instruction::StoreFast { .. }) => { + let swap_arg = match block.instructions[idx].instr.real_opcode() { + Some(Opcode::Swap) => u32::from(block.instructions[idx].arg), + Some(Opcode::Nop | Opcode::PopTop | Opcode::StoreFast) => { i -= 1; continue; } _ if matches!( - block.instructions[idx].instr.pseudo(), - Some(PseudoInstruction::StoreFastMaybeNull { .. }) + block.instructions[idx].instr.pseudo_opcode(), + Some(PseudoOpcode::StoreFastMaybeNull) ) => { i -= 1; @@ -3472,8 +3428,8 @@ fn apply_static_swaps_block(block: &mut Block) -> crate::InternalResult<()> { let mut i = 0; while i < block.instruction_used { if matches!( - block.instructions[i].instr.real(), - Some(Instruction::Swap { .. }) + block.instructions[i].instr.real_opcode(), + Some(Opcode::Swap) ) { swaptimize(block, &mut i)?; apply_static_swaps(block, i as isize); @@ -3543,11 +3499,11 @@ fn basicblock_optimize_load_const( let next_arg = next.arg; if let Some(is_true) = load_const_truthiness(const_instr, const_arg, metadata) { - let const_jump = match (next.instr.real(), next.instr.pseudo()) { - (_, Some(PseudoInstruction::JumpIfTrue { .. })) => Some((true, false)), - (_, Some(PseudoInstruction::JumpIfFalse { .. })) => Some((false, false)), - (Some(Instruction::PopJumpIfTrue { .. }), _) => Some((true, true)), - (Some(Instruction::PopJumpIfFalse { .. }), _) => Some((false, true)), + let const_jump = match (next.instr.real_opcode(), next.instr.pseudo_opcode()) { + (_, Some(PseudoOpcode::JumpIfTrue)) => Some((true, false)), + (_, Some(PseudoOpcode::JumpIfFalse)) => Some((false, false)), + (Some(Opcode::PopJumpIfTrue), _) => Some((true, true)), + (Some(Opcode::PopJumpIfFalse), _) => Some((false, true)), _ => None, }; if let Some((jump_if_true, pops_condition)) = const_jump { @@ -3555,10 +3511,7 @@ fn basicblock_optimize_load_const( set_to_nop(&mut block.instructions[i]); } if is_true == jump_if_true { - block.instructions[i + 1].instr = PseudoInstruction::Jump { - delta: Arg::marker(), - } - .into(); + block.instructions[i + 1].instr = PseudoOpcode::Jump.into(); } else { set_to_nop(&mut block.instructions[i + 1]); } @@ -3619,13 +3572,9 @@ fn basicblock_optimize_load_const( set_to_nop(&mut block.instructions[i]); set_to_nop(&mut block.instructions[i + 1]); block.instructions[jump_idx].instr = if invert { - Instruction::PopJumpIfNotNone { - delta: Arg::marker(), - } + Opcode::PopJumpIfNotNone } else { - Instruction::PopJumpIfNone { - delta: Arg::marker(), - } + Opcode::PopJumpIfNone } .into(); i = jump_idx; @@ -3643,10 +3592,7 @@ fn basicblock_optimize_load_const( set_to_nop(&mut block.instructions[i]); instr_set_op1( &mut block.instructions[i + 1], - Instruction::LoadConst { - consti: Arg::marker(), - } - .into(), + Opcode::LoadConst.into(), OpArg::new(const_idx as u32), ); i += 1; @@ -3724,8 +3670,7 @@ fn optimize_basic_block( } 2 | 3 => { set_to_nop(&mut blocks[bi].instructions[i]); - blocks[bi].instructions[i + 1].instr = - Instruction::Swap { i: Arg::marker() }.into(); + blocks[bi].instructions[i + 1].instr = Opcode::Swap.into(); i += 1; continue; } @@ -3920,7 +3865,6 @@ fn optimize_basic_block( } /// flowgraph.c remove_redundant_nops_and_pairs -#[allow(clippy::if_same_then_else, clippy::useless_let_if_seq)] #[allow(clippy::unnecessary_wraps)] fn remove_redundant_nops_and_pairs(blocks: &mut [Block]) -> crate::InternalResult<()> { let mut done = false; @@ -3942,29 +3886,21 @@ fn remove_redundant_nops_and_pairs(blocks: &mut [Block]) -> crate::InternalResul instr = Some((block_idx, instr_idx)); let instr_info = blocks[block_idx.idx()].instructions[instr_idx]; let mut prev_opcode = None; - let mut prev_oparg = 0; - if let Some((prev_block, prev_instr_idx)) = prev_instr { + let prev_oparg = if let Some((prev_block, prev_instr_idx)) = prev_instr { let prev_info = blocks[prev_block.idx()].instructions[prev_instr_idx]; - prev_opcode = prev_info.instr.real(); - prev_oparg = match prev_info.instr.real() { + prev_opcode = prev_info.instr.real_opcode(); + match prev_info.instr.real() { Some(Instruction::Copy { i }) => i.get(prev_info.arg), _ => u32::from(prev_info.arg), - }; - } - let opcode = instr_info.instr.real(); - let mut is_redundant_pair = false; - if matches!(opcode, Some(Instruction::PopTop)) { - if matches!( - prev_opcode, - Some(Instruction::LoadConst { .. } | Instruction::LoadSmallInt { .. }) - ) { - is_redundant_pair = true; - } else if matches!(prev_opcode, Some(Instruction::Copy { .. })) - && prev_oparg == 1 - { - is_redundant_pair = true; } - } + } else { + 0 + }; + + let opcode = instr_info.instr.real_opcode(); + let is_redundant_pair = matches!(opcode, Some(Opcode::PopTop)) + && (matches!(prev_opcode, Some(Opcode::LoadConst | Opcode::LoadSmallInt)) + || (prev_oparg == 1 && matches!(prev_opcode, Some(Opcode::Copy)))); if is_redundant_pair { let (prev_block, prev_instr_idx) = @@ -3975,10 +3911,10 @@ fn remove_redundant_nops_and_pairs(blocks: &mut [Block]) -> crate::InternalResul } } - let mut instr_is_jump = false; - if let Some((instr_block, instr_idx)) = instr { - instr_is_jump = is_jump(&blocks[instr_block.idx()].instructions[instr_idx]); - } + let instr_is_jump = instr.is_some_and(|(instr_block, instr_idx)| { + is_jump(&blocks[instr_block.idx()].instructions[instr_idx]) + }); + let block = &blocks[block_idx.idx()]; if instr_is_jump || !bb_has_fallthrough(block) { instr = None; @@ -4322,18 +4258,13 @@ fn optimize_load_fast(blocks: &mut [Block]) -> crate::InternalResult<()> { i += 1; continue; } - match info.instr.real() { - Some(Instruction::LoadFast { .. }) => { - info.instr = Instruction::LoadFastBorrow { - var_num: Arg::marker(), - } - .into(); + + match info.instr.real_opcode() { + Some(Opcode::LoadFast) => { + info.instr = Opcode::LoadFastBorrow.into(); } - Some(Instruction::LoadFastLoadFast { .. }) => { - info.instr = Instruction::LoadFastBorrowLoadFastBorrow { - var_nums: Arg::marker(), - } - .into(); + Some(Opcode::LoadFastLoadFast) => { + info.instr = Opcode::LoadFastBorrowLoadFastBorrow.into(); } _ => {} } @@ -4616,10 +4547,7 @@ fn insert_superinstructions(blocks: &mut [Block]) -> crate::InternalResult crate::InternalResult { @@ -4640,10 +4565,7 @@ fn insert_superinstructions(blocks: &mut [Block]) -> crate::InternalResult {} @@ -4660,6 +4582,7 @@ fn insert_superinstructions(blocks: &mut [Block]) -> crate::InternalResult crate::InternalResu let instr = block.instructions[i]; let opcode = instr.instr; if matches!( - opcode.pseudo(), - Some(PseudoInstruction::JumpIfFalse { .. } | PseudoInstruction::JumpIfTrue { .. }) + opcode.pseudo_opcode(), + Some(PseudoOpcode::JumpIfFalse | PseudoOpcode::JumpIfTrue) ) { debug_assert_eq!(i, block.instruction_used - 1); block.instructions[i].instr = - if matches!(opcode.pseudo(), Some(PseudoInstruction::JumpIfFalse { .. })) { - Instruction::PopJumpIfFalse { - delta: Arg::marker(), - } - .into() + if matches!(opcode.pseudo_opcode(), Some(PseudoOpcode::JumpIfFalse)) { + Opcode::PopJumpIfFalse } else { - Instruction::PopJumpIfTrue { - delta: Arg::marker(), - } - .into() - }; + Opcode::PopJumpIfTrue + } + .into(); let location = instr.location; let end_location = instr.end_location; let except_handler = instr.except_handler; let lineno_override = instr.lineno_override; let copy = InstructionInfo { - instr: Instruction::Copy { i: Arg::marker() }.into(), + instr: Opcode::Copy.into(), arg: OpArg::new(1), target: BlockIdx::NULL, location, @@ -5497,7 +5416,7 @@ fn convert_pseudo_conditional_jumps(blocks: &mut [Block]) -> crate::InternalResu i += 1; let to_bool = InstructionInfo { - instr: Instruction::ToBool.into(), + instr: Opcode::ToBool.into(), arg: OpArg::new(0), target: BlockIdx::NULL, location, @@ -5547,7 +5466,7 @@ fn normalize_jumps_in_block( return Ok(()); } - let reversed_opcode = match AnyOpcode::from(last_ins.instr).real() { + let reversed_opcode = match last_ins.instr.real_opcode() { Some(Opcode::PopJumpIfNotNone) => Opcode::PopJumpIfNone.into(), Some(Opcode::PopJumpIfNone) => Opcode::PopJumpIfNotNone.into(), Some(Opcode::PopJumpIfFalse) => Opcode::PopJumpIfTrue.into(), @@ -5765,10 +5684,7 @@ fn remove_redundant_nops(blocks: &mut [Block]) -> crate::InternalResult { /// flowgraph.c no_redundant_nops #[cfg(debug_assertions)] fn no_redundant_nops(blocks: &mut [Block]) -> bool { - match remove_redundant_nops(blocks) { - Ok(0) => true, - Ok(_) | Err(_) => false, - } + matches!(remove_redundant_nops(blocks), Ok(0)) } /// flowgraph.c remove_redundant_jumps @@ -6740,10 +6656,7 @@ pub(crate) fn convert_pseudo_ops(blocks: &mut [Block]) -> crate::InternalResult< PseudoOpcode::StoreFastMaybeNull, Opcode::StoreFast )); - info.instr = Instruction::StoreFast { - var_num: Arg::marker(), - } - .into(); + info.instr = Opcode::StoreFast.into(); } } block_idx = next; @@ -6967,10 +6880,7 @@ mod tests { assert!(except_stack_top(&stack, &blocks).is_none()); let setup = InstructionInfo { - instr: PseudoInstruction::SetupWith { - delta: Arg::marker(), - } - .into(), + instr: PseudoOpcode::SetupWith.into(), arg: OpArg::new(0), target: BlockIdx::new(1), location: SourceLocation::default(), @@ -7289,14 +7199,9 @@ mod tests { #[test] fn static_swaps_respect_cpython_no_location_line_boundary() { let mut block = Block::default(); - let mut swap = test_instr(Instruction::Swap { i: Arg::marker() }, 60); + let mut swap = test_instr(Opcode::Swap.into(), 60); swap.arg = OpArg::new(2); - let mut store = test_instr( - Instruction::StoreFast { - var_num: Arg::marker(), - }, - 60, - ); + let mut store = test_instr(Opcode::StoreFast.into(), 60); store.arg = OpArg::new(0); let mut pop = test_instr(Instruction::PopTop, 60); pop.lineno_override = Some(NO_LOCATION_OVERRIDE); @@ -7323,14 +7228,9 @@ mod tests { )); let mut block = Block::default(); - let mut swap = test_instr(Instruction::Swap { i: Arg::marker() }, 70); + let mut swap = test_instr(Opcode::Swap.into(), 70); swap.arg = OpArg::new(2); - let mut store = test_instr( - Instruction::StoreFast { - var_num: Arg::marker(), - }, - 70, - ); + let mut store = test_instr(Opcode::StoreFast.into(), 70); store.arg = OpArg::new(0); store.lineno_override = Some(NO_LOCATION_OVERRIDE); let pop = test_instr(Instruction::PopTop, 71); @@ -7343,32 +7243,24 @@ mod tests { // Conversely, when the first swaperand has NO_LOCATION, CPython passes // `-1` as the line filter and does not enforce a boundary. assert!(matches!( - block.instructions[0].instr.real(), - Some(Instruction::Nop) + block.instructions[0].instr.real_opcode(), + Some(Opcode::Nop) )); assert!(matches!( - block.instructions[1].instr.real(), - Some(Instruction::PopTop) + block.instructions[1].instr.real_opcode(), + Some(Opcode::PopTop) )); assert!(matches!( - block.instructions[2].instr.real(), - Some(Instruction::StoreFast { .. }) + block.instructions[2].instr.real_opcode(), + Some(Opcode::StoreFast) )); } #[test] fn optimize_load_const_tracks_cpython_copy_of_load_const() { let mut block = Block::default(); - test_block_push( - &mut block, - test_instr( - Instruction::LoadConst { - consti: Arg::marker(), - }, - 80, - ), - ); - let mut copy = test_instr(Instruction::Copy { i: Arg::marker() }, 80); + test_block_push(&mut block, test_instr(Opcode::LoadConst.into(), 80)); + let mut copy = test_instr(Opcode::Copy.into(), 80); copy.arg = OpArg::new(1); test_block_push(&mut block, copy); test_block_push(&mut block, test_instr(Instruction::ToBool, 80)); @@ -7409,17 +7301,9 @@ mod tests { #[test] fn optimize_load_fast_records_no_input_opcode_ref_at_cpython_produced_index() { let mut block = Block::default(); - test_block_push( - &mut block, - test_instr( - Instruction::LoadFast { - var_num: Arg::marker(), - }, - 10, - ), - ); + test_block_push(&mut block, test_instr(Opcode::LoadFast.into(), 10)); test_block_push(&mut block, test_instr(Instruction::GetLen, 10)); - let mut swap = test_instr(Instruction::Swap { i: Arg::marker() }, 10); + let mut swap = test_instr(Opcode::Swap.into(), 10); swap.arg = OpArg::new(2); test_block_push(&mut block, swap); test_block_push(&mut block, test_instr(Instruction::PopTop, 10)); @@ -7467,12 +7351,7 @@ mod tests { let mut mortal = test_instr(Instruction::Nop, 90); mortal.instr = Opcode::LoadConstMortal.into(); mortal.arg = OpArg::new(right as u32); - let mut build = test_instr( - Instruction::BuildTuple { - count: Arg::marker(), - }, - 90, - ); + let mut build = test_instr(Opcode::BuildTuple.into(), 90); build.arg = OpArg::new(2); let mut block = Block::default(); for info in [immortal, mortal, build] { diff --git a/crates/codegen/src/string_parser.rs b/crates/codegen/src/string_parser.rs index ee6c08a5639..0b5bcfffc9c 100644 --- a/crates/codegen/src/string_parser.rs +++ b/crates/codegen/src/string_parser.rs @@ -13,6 +13,7 @@ use rustpython_wtf8::{CodePoint, Wtf8, Wtf8Buf}; // use ruff_python_parser::{LexicalError, LexicalErrorType}; type LexicalError = Infallible; +#[derive(Clone, Copy, Debug, Eq, PartialEq)] enum EscapedChar { Literal(CodePoint), Escape(char), diff --git a/crates/compiler-core/src/bytecode.rs b/crates/compiler-core/src/bytecode.rs index 8994daadd4b..ee6b6e5d96c 100644 --- a/crates/compiler-core/src/bytecode.rs +++ b/crates/compiler-core/src/bytecode.rs @@ -919,6 +919,7 @@ impl ConstantData { /// bool([]) # False /// bool(...) # True /// ``` + #[must_use] pub fn truthiness(&self) -> bool { match self { Self::Tuple { elements } | Self::Frozenset { elements } => !elements.is_empty(), diff --git a/crates/vm/src/function/buffer.rs b/crates/vm/src/function/buffer.rs index 028f3633d06..213193bb9c8 100644 --- a/crates/vm/src/function/buffer.rs +++ b/crates/vm/src/function/buffer.rs @@ -13,11 +13,10 @@ use crate::{ pub struct ArgBytesLike(PyBuffer); impl PyObject { - pub fn try_bytes_like( - &self, - vm: &VirtualMachine, - f: impl FnOnce(&[u8]) -> R, - ) -> PyResult { + pub fn try_bytes_like(&self, vm: &VirtualMachine, f: F) -> PyResult + where + F: FnOnce(&[u8]) -> R, + { let buffer = PyBuffer::try_from_borrowed_object(vm, self)?; buffer .as_contiguous() @@ -25,11 +24,10 @@ impl PyObject { .ok_or_else(|| vm.new_buffer_error("non-contiguous buffer is not a bytes-like object")) } - pub fn try_rw_bytes_like( - &self, - vm: &VirtualMachine, - f: impl FnOnce(&mut [u8]) -> R, - ) -> PyResult { + pub fn try_rw_bytes_like(&self, vm: &VirtualMachine, f: F) -> PyResult + where + F: FnOnce(&mut [u8]) -> R, + { let buffer = PyBuffer::try_from_borrowed_object(vm, self)?; buffer .as_contiguous_mut() @@ -207,7 +205,10 @@ impl ArgAsciiBuffer { } #[inline] - pub fn with_ref(&self, f: impl FnOnce(&[u8]) -> R) -> R { + pub fn with_ref(&self, f: F) -> R + where + F: FnOnce(&[u8]) -> R, + { match self { Self::String(s) => f(s.as_bytes()), Self::Buffer(buffer) => buffer.with_ref(f), diff --git a/crates/vm/src/function/builtin.rs b/crates/vm/src/function/builtin.rs index 4fed5e4cf23..47cb8dfcb64 100644 --- a/crates/vm/src/function/builtin.rs +++ b/crates/vm/src/function/builtin.rs @@ -11,8 +11,9 @@ pub trait PyNativeFn: Fn(&VirtualMachine, FuncArgs) -> PyResult + PyThreadingConstraint + 'static { } -impl PyResult + PyThreadingConstraint + 'static> PyNativeFn - for F + +impl PyNativeFn for F where + F: Fn(&VirtualMachine, FuncArgs) -> PyResult + PyThreadingConstraint + 'static { } @@ -103,8 +104,10 @@ use sealed::PyNativeFnInternal; #[doc(hidden)] pub struct OwnedParam(PhantomData); + #[doc(hidden)] pub struct BorrowedParam(PhantomData); + #[doc(hidden)] pub struct RefParam(PhantomData); diff --git a/crates/vm/src/function/either.rs b/crates/vm/src/function/either.rs index 9ee7f028bd2..e7f6091b200 100644 --- a/crates/vm/src/function/either.rs +++ b/crates/vm/src/function/either.rs @@ -8,7 +8,11 @@ pub enum Either { B(B), } -impl, B: Borrow> Borrow for Either { +impl Borrow for Either +where + A: Borrow, + B: Borrow, +{ #[inline(always)] fn borrow(&self) -> &PyObject { match self { @@ -18,7 +22,11 @@ impl, B: Borrow> Borrow for Either } } -impl, B: AsRef> AsRef for Either { +impl AsRef for Either +where + A: AsRef, + B: AsRef, +{ #[inline(always)] fn as_ref(&self) -> &PyObject { match self { @@ -28,7 +36,11 @@ impl, B: AsRef> AsRef for Either { } } -impl, B: Into> From> for PyObjectRef { +impl From> for PyObjectRef +where + A: Into, + B: Into, +{ #[inline(always)] fn from(value: Either) -> Self { match value { @@ -38,7 +50,11 @@ impl, B: Into> From> for PyObjectRef { } } -impl ToPyObject for Either { +impl ToPyObject for Either +where + A: ToPyObject, + B: ToPyObject, +{ #[inline(always)] fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef { match self { diff --git a/crates/vm/src/function/getset.rs b/crates/vm/src/function/getset.rs index bcd745f561b..a1c003dbca6 100644 --- a/crates/vm/src/function/getset.rs +++ b/crates/vm/src/function/getset.rs @@ -1,6 +1,4 @@ -/*! Python `attribute` descriptor class. (PyGetSet) - -*/ +//! Python `attribute` descriptor class. (PyGetSet) use crate::{ Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine, convert::ToPyResult, diff --git a/crates/vm/src/function/method.rs b/crates/vm/src/function/method.rs index 12eda50c9d5..f0497fb384e 100644 --- a/crates/vm/src/function/method.rs +++ b/crates/vm/src/function/method.rs @@ -254,6 +254,7 @@ impl PyMethodDef { all_methods } + #[must_use] const fn const_copy(&self) -> Self { Self { name: self.name,