MATCH_SELF

This commit is contained in:
Jeong YunWon committed 2025-08-26 21:48:46 +09:00
1 parent 50c557419e
commit 8ae2dc75f6
13 files changed
+32 -38

No files matched your search

+7 -7
View File
@@ -36,7 +36,7 @@ use rustpython_compiler_core::{
Mode, OneIndexed, SourceFile, SourceLocation,
bytecode::{
self, Arg as OpArgMarker, BinaryOperator, CodeObject, ComparisonOperator, ConstantData,
Instruction, OpArg, OpArgType, TestOperator, UnpackExArgs,
Instruction, OpArg, OpArgType, UnpackExArgs,
},
};
use rustpython_wtf8::Wtf8Buf;
@@ -3484,7 +3484,7 @@ impl Compiler {
// Process each sub-pattern.
for subpattern in patterns.iter().chain(kwd_patterns.iter()) {
// Decrement the on_top counter BEFORE processing each sub-pattern
// Decrement the on_top counter before processing each sub-pattern
pc.on_top -= 1;
// Check if this is a true wildcard (underscore pattern without name binding)
@@ -3557,6 +3557,7 @@ impl Compiler {
// Check if the mapping has at least 'size' keys
emit!(self, Instruction::GetLen);
self.emit_load_const(ConstantData::Integer { value: size.into() });
// Stack: [subject, len, size]
emit!(
self,
Instruction::CompareOperation {
@@ -3564,6 +3565,7 @@ impl Compiler {
}
);
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
// Stack: [subject]
}
// Check for overflow (INT_MAX < size - 1)
@@ -3606,9 +3608,8 @@ impl Compiler {
self.compile_expression(key)?;
}
// Stack: [subject, key1, key2, ..., keyn]
}
// Stack: [subject] if size==0, or [subject, key1, ..., keyn] if size>0
// Stack: [subject, key1, key2, ..., key_n]
// Build tuple of keys (empty tuple if size==0)
emit!(self, Instruction::BuildTuple { size });
@@ -3628,7 +3629,7 @@ impl Compiler {
emit!(
self,
Instruction::TestOperation {
op: TestOperator::IsNot
op: bytecode::TestOperator::IsNot
}
);
// Stack: [subject, keys_tuple, values_tuple, bool]
@@ -3924,8 +3925,7 @@ impl Compiler {
Singleton::False => ConstantData::Boolean { value: false },
Singleton::True => ConstantData::Boolean { value: true },
});
// Compare using the "Is" operator (identity check, not equality).
// This is important: False should not match 0, even though False == 0
// Compare using the "Is" operator.
emit!(
self,
Instruction::TestOperation {
+1 -1
View File
@@ -109,7 +109,7 @@ impl Constructor for PyBool {
}
}
#[pyclass(with(Constructor, AsNumber, Representable))]
#[pyclass(with(Constructor, AsNumber, Representable), flags(_MATCH_SELF))]
impl PyBool {
#[pymethod]
fn __format__(obj: PyObjectRef, spec: PyStrRef, vm: &VirtualMachine) -> PyResult<String> {
+1 -1
View File
@@ -170,7 +170,7 @@ impl PyByteArray {
}
#[pyclass(
flags(BASETYPE),
flags(BASETYPE, _MATCH_SELF),
with(
Py,
PyRef,
+1 -1
View File
@@ -132,7 +132,7 @@ impl PyRef<PyBytes> {
}
#[pyclass(
flags(BASETYPE),
flags(BASETYPE, _MATCH_SELF),
with(
Py,
PyRef,
+1 -1
View File
@@ -176,7 +176,7 @@ impl PyDict {
AsMapping,
Representable
),
flags(BASETYPE, MAPPING)
flags(BASETYPE, MAPPING, _MATCH_SELF)
)]
impl PyDict {
#[pyclassmethod]
+1 -1
View File
@@ -201,7 +201,7 @@ fn float_from_string(val: PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> {
}
#[pyclass(
flags(BASETYPE),
flags(BASETYPE, _MATCH_SELF),
with(Comparable, Hashable, Constructor, AsNumber, Representable)
)]
impl PyFloat {
+1 -1
View File
@@ -317,7 +317,7 @@ impl PyInt {
}
#[pyclass(
flags(BASETYPE),
flags(BASETYPE, _MATCH_SELF),
with(PyRef, Comparable, Hashable, Constructor, AsNumber, Representable)
)]
impl PyInt {
+1 -1
View File
@@ -109,7 +109,7 @@ pub type PyListRef = PyRef<PyList>;
AsSequence,
Representable
),
flags(BASETYPE, SEQUENCE)
flags(BASETYPE, SEQUENCE, _MATCH_SELF)
)]
impl PyList {
#[pymethod]
+2 -2
View File
@@ -529,7 +529,7 @@ fn reduce_set(
AsNumber,
Representable
),
flags(BASETYPE)
flags(BASETYPE, _MATCH_SELF)
)]
impl PySet {
#[pymethod]
@@ -946,7 +946,7 @@ impl Constructor for PyFrozenSet {
}
#[pyclass(
flags(BASETYPE),
flags(BASETYPE, _MATCH_SELF),
with(
Constructor,
AsSequence,
+1 -1
View File
@@ -521,7 +521,7 @@ impl Py<PyStr> {
}
#[pyclass(
flags(BASETYPE),
flags(BASETYPE, _MATCH_SELF),
with(
PyRef,
AsMapping,
+1 -1
View File
@@ -244,7 +244,7 @@ impl<T> PyTuple<PyRef<T>> {
}
#[pyclass(
flags(BASETYPE, SEQUENCE),
flags(BASETYPE, SEQUENCE, _MATCH_SELF),
with(
AsMapping,
AsSequence,
+10 -20
View File
@@ -702,19 +702,17 @@ impl ExecutingFrame<'_> {
}
bytecode::Instruction::Swap { index } => {
let len = self.state.stack.len();
if len == 0 {
return Err(vm.new_runtime_error("stack underflow in SWAP".to_string()));
}
debug_assert!(len > 0, "stack underflow in SWAP");
let i = len - 1; // TOS index
let index_val = index.get(arg) as usize;
// CPython: SWAP(n) swaps TOS with PEEK(n) where PEEK(n) = stack_pointer[-n]
// This means swap TOS with the element at index (len - n)
if index_val > len {
return Err(vm.new_runtime_error(format!(
"SWAP index {} exceeds stack size {}",
index_val, len
)));
}
debug_assert!(
index_val <= len,
"SWAP index {} exceeds stack size {}",
index_val,
len
);
let j = len - index_val;
self.state.stack.swap(i, j);
Ok(None)
@@ -1433,17 +1431,9 @@ impl ExecutingFrame<'_> {
// No __match_args__, check if this is a type with MATCH_SELF behavior
// For built-in types like bool, int, str, list, tuple, dict, etc.
// they match the subject itself as the single positional argument
let is_match_self_type = cls.is(vm.ctx.types.bool_type)
|| cls.is(vm.ctx.types.int_type)
|| cls.is(vm.ctx.types.float_type)
|| cls.is(vm.ctx.types.str_type)
|| cls.is(vm.ctx.types.bytes_type)
|| cls.is(vm.ctx.types.bytearray_type)
|| cls.is(vm.ctx.types.list_type)
|| cls.is(vm.ctx.types.tuple_type)
|| cls.is(vm.ctx.types.dict_type)
|| cls.is(vm.ctx.types.set_type)
|| cls.is(vm.ctx.types.frozenset_type);
let is_match_self_type = cls
.downcast::<PyType>()
.is_ok_and(|t| t.slots.flags.contains(PyTypeFlags::_MATCH_SELF));
if is_match_self_type {
if nargs_val == 1 {
+4
View File
@@ -129,6 +129,10 @@ bitflags! {
const HEAPTYPE = 1 << 9;
const BASETYPE = 1 << 10;
const METHOD_DESCRIPTOR = 1 << 17;
// For built-in types that match the subject itself in pattern matching
// (bool, int, float, str, bytes, bytearray, list, tuple, dict, set, frozenset)
// This is not a stable API
const _MATCH_SELF = 1 << 22;
const HAS_DICT = 1 << 40;
#[cfg(debug_assertions)]