Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions crates/stdlib/src/_asyncio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
39 changes: 33 additions & 6 deletions crates/vm/src/builtins/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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());
}

Expand All @@ -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);
}
}

Expand All @@ -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());
}

Expand Down
10 changes: 8 additions & 2 deletions crates/vm/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion crates/vm/src/stdlib/_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
28 changes: 24 additions & 4 deletions crates/vm/src/stdlib/_testinternalcapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))]
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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")]
Expand Down
25 changes: 24 additions & 1 deletion crates/vm/src/stdlib/itertools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
}

#[pyclass(with(Constructor, IterNext, Iterable), flags(HAS_WEAKREF))]
impl PyItertoolsGrouper {}

impl SelfIter for PyItertoolsGrouper {}
Expand Down
Loading