mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Decide tp_new inheritance of static types at type initialization (#9386)
A static type with no tp_new of its own whose base is object now gets DISALLOW_INSTANTIATION instead of inheriting object's tp_new, following type_ready_set_new. Such types no longer expose an inherited __new__. A static type that inherits a non-NULL tp_new from its base must have the same basicsize as that base; type initialization panics otherwise. Types flagged HEAPTYPE are exempt, like classes created at runtime. _IOBase is flagged HEAPTYPE so that it keeps inheriting object's tp_new. FutureIter, TaskStepMethWrapper, hamt, InstructionSequence and itertools._grouper get constructors of their own. Assisted-by: Claude:claude-opus-5-5 Assisted-by: Grok:grok-4.7
This commit is contained in:
1 parent
6934845753
commit
20042568fc
6 files changed
+112
-16
No files matched your search
@@ -965,7 +965,17 @@ pub(crate) mod _asyncio {
|
||||
future: PyRwLock<Option<PyObjectRef>>,
|
||||
}
|
||||
|
||||
#[pyclass(with(IterNext, Iterable))]
|
||||
impl Constructor for PyFutureIter {
|
||||
type Args = ();
|
||||
|
||||
fn py_new(_cls: &Py<PyType>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
|
||||
Ok(Self {
|
||||
future: PyRwLock::new(None),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(with(Constructor, IterNext, Iterable))]
|
||||
impl PyFutureIter {
|
||||
#[pymethod]
|
||||
fn send(zelf: &Py<Self>, _value: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
@@ -2926,7 +2936,17 @@ pub(crate) mod _asyncio {
|
||||
task: PyRwLock<Option<PyObjectRef>>,
|
||||
}
|
||||
|
||||
#[pyclass(with(Callable, Representable))]
|
||||
impl Constructor for TaskStepMethWrapper {
|
||||
type Args = ();
|
||||
|
||||
fn py_new(_cls: &Py<PyType>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
|
||||
Ok(Self {
|
||||
task: PyRwLock::new(None),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(with(Constructor, Callable, Representable))]
|
||||
impl TaskStepMethWrapper {
|
||||
fn new(task: PyObjectRef) -> Self {
|
||||
Self {
|
||||
|
||||
@@ -1219,7 +1219,7 @@ impl PyType {
|
||||
// Note: inherit_slots is called in PyClassImpl::init_class after
|
||||
// slots are fully initialized by make_slots()
|
||||
|
||||
Self::set_new(&new_type.slots, new_type.base.deref());
|
||||
Self::set_new(&new_type.slots, new_type.base.deref(), false);
|
||||
Self::set_alloc(&new_type.slots, new_type.base.deref());
|
||||
|
||||
let weakref_type = super::PyWeak::static_type();
|
||||
@@ -1271,7 +1271,7 @@ impl PyType {
|
||||
self.update_slot::<true>(attr_name, ctx);
|
||||
}
|
||||
|
||||
Self::set_new(&self.slots, self.base.deref());
|
||||
Self::set_new(&self.slots, self.base.deref(), true);
|
||||
Self::set_alloc(&self.slots, self.base.deref());
|
||||
}
|
||||
|
||||
@@ -1295,11 +1295,38 @@ impl PyType {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_new(slots: &PyTypeSlots, base: Option<&Py<Self>>) {
|
||||
/// type_ready_set_new: a static type with no tp_new whose base is object
|
||||
/// gets DISALLOW_INSTANTIATION and keeps tp_new unset. Heap types inherit
|
||||
/// the base's tp_new. A static type that inherits a non-NULL tp_new must
|
||||
/// have the same basicsize as that base, because the inherited function
|
||||
/// allocates the base payload. Heap types, including native types flagged
|
||||
/// HEAPTYPE, reuse the base payload like classes created at runtime.
|
||||
fn set_new(slots: &PyTypeSlots, base: Option<&Py<Self>>, heap: bool) {
|
||||
let is_heap = heap || slots.flags.has_feature(PyTypeFlags::HEAPTYPE);
|
||||
|
||||
if !is_heap
|
||||
&& slots.new.load().is_none()
|
||||
&& base.is_some_and(|b| core::ptr::eq(b, object::PyBaseObject::static_type()))
|
||||
{
|
||||
slots.flags.insert(PyTypeFlags::DISALLOW_INSTANTIATION);
|
||||
}
|
||||
|
||||
if slots.flags.has_feature(PyTypeFlags::DISALLOW_INSTANTIATION) {
|
||||
slots.new.store(None)
|
||||
slots.new.store(None);
|
||||
} else if slots.new.load().is_none() {
|
||||
slots.new.store(base.and_then(|base| base.slots.new.load()))
|
||||
let inherited = base.and_then(|base| base.slots.new.load());
|
||||
if !is_heap
|
||||
&& inherited.is_some()
|
||||
&& let Some(base) = base
|
||||
&& slots.basicsize != base.slots.basicsize
|
||||
{
|
||||
panic!(
|
||||
"static type '{}' inherits tp_new from '{}' but basicsize {} != {}; \
|
||||
the inherited tp_new allocates the base payload",
|
||||
slots.name, base.slots.name, slots.basicsize, base.slots.basicsize
|
||||
);
|
||||
}
|
||||
slots.new.store(inherited);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1312,7 +1339,7 @@ impl PyType {
|
||||
}
|
||||
|
||||
pub(crate) fn finalize_bootstrap_static(typ: &Py<Self>) {
|
||||
Self::set_new(&typ.slots, typ.base.deref());
|
||||
Self::set_new(&typ.slots, typ.base.deref(), false);
|
||||
Self::set_alloc(&typ.slots, typ.base.deref());
|
||||
}
|
||||
|
||||
|
||||
@@ -367,8 +367,14 @@ pub trait PyClassImpl: PyClassDef {
|
||||
|
||||
// Don't add __new__ attribute if slot_new is inherited from object
|
||||
// (Python doesn't add __new__ to __dict__ for inherited slots)
|
||||
// Exception: object itself should have __new__ in its dict
|
||||
if let Some(slot_new) = class.slots().new.load() {
|
||||
// Exception: object itself should have __new__ in its dict.
|
||||
// DISALLOW_INSTANTIATION types must not expose an inherited __new__.
|
||||
if !class
|
||||
.slots()
|
||||
.flags
|
||||
.has_feature(PyTypeFlags::DISALLOW_INSTANTIATION)
|
||||
&& let Some(slot_new) = class.slots().new.load()
|
||||
{
|
||||
let object_new = ctx.types.object_type.slots().new.load();
|
||||
let is_object_itself = core::ptr::eq(class, ctx.types.object_type);
|
||||
let is_inherited_from_object = !is_object_itself
|
||||
|
||||
@@ -520,7 +520,7 @@ mod _io {
|
||||
|
||||
#[pyclass(
|
||||
with(IterNext, Iterable, Destructor),
|
||||
flags(BASETYPE, HAS_DICT, HAS_WEAKREF)
|
||||
flags(BASETYPE, HAS_DICT, HAS_WEAKREF, HEAPTYPE)
|
||||
)]
|
||||
impl _IOBase {
|
||||
#[pymethod]
|
||||
|
||||
@@ -42,8 +42,8 @@ mod _testinternalcapi {
|
||||
protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods},
|
||||
stdlib::time::pytime::{self, Round},
|
||||
types::{
|
||||
AsMapping, AsSequence, Comparable, IterNext, Iterable, PyComparisonOp, PyTypeFlags,
|
||||
SelfIter,
|
||||
AsMapping, AsSequence, Comparable, Constructor, IterNext, Iterable, PyComparisonOp,
|
||||
PyTypeFlags, SelfIter,
|
||||
},
|
||||
};
|
||||
#[cfg(any(unix, windows))]
|
||||
@@ -779,7 +779,18 @@ mod _testinternalcapi {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(flags(HAS_WEAKREF), with(AsMapping, AsSequence, Comparable, Iterable))]
|
||||
impl Constructor for Hamt {
|
||||
type Args = ();
|
||||
|
||||
fn py_new(_cls: &Py<PyType>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
|
||||
Ok(Self::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(
|
||||
flags(HAS_WEAKREF),
|
||||
with(Constructor, AsMapping, AsSequence, Comparable, Iterable)
|
||||
)]
|
||||
impl Py<Hamt> {
|
||||
#[pymethod]
|
||||
fn set(
|
||||
@@ -1122,7 +1133,16 @@ mod _testinternalcapi {
|
||||
}
|
||||
|
||||
#[cfg(feature = "codegen")]
|
||||
#[pyclass(with(Py))]
|
||||
impl Constructor for PyInstructionSequence {
|
||||
type Args = ();
|
||||
|
||||
fn py_new(_cls: &Py<PyType>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
|
||||
Ok(Self::empty())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "codegen")]
|
||||
#[pyclass(with(Constructor, Py))]
|
||||
impl PyInstructionSequence {}
|
||||
|
||||
#[cfg(feature = "codegen")]
|
||||
|
||||
@@ -706,7 +706,30 @@ mod decl {
|
||||
tgtkey: PyObjectRef,
|
||||
}
|
||||
|
||||
#[pyclass(with(IterNext, Iterable), flags(HAS_WEAKREF))]
|
||||
#[derive(FromArgs)]
|
||||
struct GrouperArgs {
|
||||
#[pyarg(positional)]
|
||||
parent: PyRef<PyItertoolsGroupBy>,
|
||||
#[pyarg(positional)]
|
||||
tgtkey: PyObjectRef,
|
||||
}
|
||||
|
||||
impl Constructor for PyItertoolsGrouper {
|
||||
type Args = GrouperArgs;
|
||||
|
||||
fn py_new(
|
||||
_cls: &Py<PyType>,
|
||||
Self::Args { parent, tgtkey }: Self::Args,
|
||||
_vm: &VirtualMachine,
|
||||
) -> PyResult<Self> {
|
||||
Ok(Self {
|
||||
groupby: parent,
|
||||
tgtkey,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(with(Constructor, IterNext, Iterable), flags(HAS_WEAKREF))]
|
||||
impl PyItertoolsGrouper {}
|
||||
|
||||
impl SelfIter for PyItertoolsGrouper {}
|
||||
|
||||
Reference in new issue
Block a user