Skip to content

Commit afe436d

Browse files
committed
Revise downcastable
1 parent 3f937aa commit afe436d

17 files changed

Lines changed: 69 additions & 124 deletions

File tree

crates/derive-impl/src/pyclass.rs

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ pub(crate) fn impl_pyclass(attr: PunctuatedNestedMeta, item: Item) -> Result<Tok
473473
ident,
474474
&class_name,
475475
module_name.as_deref(),
476-
base,
476+
base.clone(),
477477
metaclass,
478478
unhashable,
479479
attrs,
@@ -528,19 +528,45 @@ pub(crate) fn impl_pyclass(attr: PunctuatedNestedMeta, item: Item) -> Result<Tok
528528
}
529529
};
530530

531-
let impl_payload = if let Some(ctx_type_name) = class_meta.ctx_name()? {
532-
let ctx_type_ident = Ident::new(&ctx_type_name, ident.span()); // FIXME span
531+
// Generate PyPayload impl based on whether base exists
532+
let impl_payload = if let Some(base_type) = &base {
533+
let class_fn = if let Some(ctx_type_name) = class_meta.ctx_name()? {
534+
let ctx_type_ident = Ident::new(&ctx_type_name, ident.span());
535+
quote! { ctx.types.#ctx_type_ident }
536+
} else {
537+
quote! { <Self as ::rustpython_vm::class::StaticType>::static_type() }
538+
};
533539

534-
// We need this to make extend mechanism work:
535540
quote! {
536541
impl ::rustpython_vm::PyPayload for #ident {
542+
#[inline]
543+
fn payload_type_id() -> ::std::any::TypeId {
544+
<#base_type as ::rustpython_vm::PyPayload>::payload_type_id()
545+
}
546+
547+
#[inline]
548+
fn validate_downcastable_from(obj: &::rustpython_vm::PyObject) -> bool {
549+
<Self as ::rustpython_vm::class::PyClassDef>::BASICSIZE <= obj.class().slots.basicsize && obj.class().fast_issubclass(<Self as ::rustpython_vm::class::StaticType>::static_type())
550+
}
551+
537552
fn class(ctx: &::rustpython_vm::vm::Context) -> &'static ::rustpython_vm::Py<::rustpython_vm::builtins::PyType> {
538-
ctx.types.#ctx_type_ident
553+
#class_fn
539554
}
540555
}
541556
}
542557
} else {
543-
quote! {}
558+
if let Some(ctx_type_name) = class_meta.ctx_name()? {
559+
let ctx_type_ident = Ident::new(&ctx_type_name, ident.span());
560+
quote! {
561+
impl ::rustpython_vm::PyPayload for #ident {
562+
fn class(ctx: &::rustpython_vm::vm::Context) -> &'static ::rustpython_vm::Py<::rustpython_vm::builtins::PyType> {
563+
ctx.types.#ctx_type_ident
564+
}
565+
}
566+
}
567+
} else {
568+
quote! {}
569+
}
544570
};
545571

546572
let empty_impl = if let Some(attrs) = class_meta.impl_attrs()? {
@@ -579,26 +605,6 @@ pub(crate) fn impl_pyexception(attr: PunctuatedNestedMeta, item: Item) -> Result
579605
let class_name = class_meta.class_name()?;
580606

581607
let base_class_name = class_meta.base()?;
582-
let impl_payload = if let Some(ctx_type_name) = class_meta.ctx_name()? {
583-
let ctx_type_ident = Ident::new(&ctx_type_name, ident.span()); // FIXME span
584-
585-
// We need this to make extend mechanism work:
586-
quote! {
587-
impl ::rustpython_vm::PyPayload for #ident {
588-
fn class(ctx: &::rustpython_vm::vm::Context) -> &'static ::rustpython_vm::Py<::rustpython_vm::builtins::PyType> {
589-
ctx.exceptions.#ctx_type_ident
590-
}
591-
}
592-
}
593-
} else {
594-
quote! {
595-
impl ::rustpython_vm::PyPayload for #ident {
596-
fn class(_ctx: &::rustpython_vm::vm::Context) -> &'static ::rustpython_vm::Py<::rustpython_vm::builtins::PyType> {
597-
<Self as ::rustpython_vm::class::StaticType>::static_type()
598-
}
599-
}
600-
}
601-
};
602608
let impl_pyclass = if class_meta.has_impl()? {
603609
quote! {
604610
#[pyexception]
@@ -611,7 +617,6 @@ pub(crate) fn impl_pyexception(attr: PunctuatedNestedMeta, item: Item) -> Result
611617
let ret = quote! {
612618
#[pyclass(module = false, name = #class_name, base = #base_class_name)]
613619
#item
614-
#impl_payload
615620
#impl_pyclass
616621
};
617622
Ok(ret)

crates/vm/src/builtins/bool.rs

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
use super::{PyInt, PyStrRef, PyType, PyTypeRef};
1+
use super::{PyInt, PyStrRef, PyTypeRef};
22
use crate::common::format::FormatSpec;
33
use crate::{
4-
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyResult, TryFromBorrowedObject,
5-
VirtualMachine,
6-
class::{PyClassImpl, StaticType},
4+
AsObject, Context, Py, PyObject, PyObjectRef, PyResult, TryFromBorrowedObject, VirtualMachine,
5+
class::PyClassImpl,
76
convert::{IntoPyException, ToPyObject, ToPyResult},
87
function::OptionalArg,
98
identifier,
@@ -82,39 +81,10 @@ impl PyObjectRef {
8281
}
8382
}
8483

85-
#[pyclass(name = "bool", module = false, base = PyInt)]
84+
#[pyclass(name = "bool", module = false, base = PyInt, ctx = "bool_type")]
8685
#[repr(transparent)]
8786
pub struct PyBool(pub PyInt);
8887

89-
impl PyPayload for PyBool {
90-
#[inline]
91-
fn class(ctx: &Context) -> &'static Py<PyType> {
92-
ctx.types.bool_type
93-
}
94-
95-
/// PyBool reuses PyInt's TypeId
96-
#[inline]
97-
fn payload_type_id() -> std::any::TypeId {
98-
std::any::TypeId::of::<PyInt>()
99-
}
100-
101-
fn downcastable_from(obj: &PyObject) -> bool {
102-
obj.class().is(PyBool::static_type())
103-
}
104-
105-
fn try_downcast_from(obj: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
106-
if obj.class().is(vm.ctx.types.bool_type) {
107-
return Ok(());
108-
}
109-
110-
Err(crate::object::cold_downcast_type_error(
111-
vm,
112-
Self::class(&vm.ctx),
113-
obj,
114-
))
115-
}
116-
}
117-
11888
impl Debug for PyBool {
11989
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
12090
let value = !self.0.as_bigint().is_zero();

crates/vm/src/builtins/builtin_func.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ impl Representable for PyNativeFunction {
148148
impl Unconstructible for PyNativeFunction {}
149149

150150
// `PyCMethodObject` in CPython
151-
#[pyclass(name = "builtin_method", module = false, base = PyNativeFunction)]
151+
#[pyclass(name = "builtin_method", module = false, base = PyNativeFunction, ctx = "builtin_method_type")]
152152
pub struct PyNativeMethod {
153153
pub(crate) func: PyNativeFunction,
154154
pub(crate) class: &'static Py<PyType>, // TODO: the actual life is &'self
@@ -189,12 +189,6 @@ impl PyNativeMethod {
189189
}
190190
}
191191

192-
impl PyPayload for PyNativeMethod {
193-
fn class(ctx: &Context) -> &'static Py<PyType> {
194-
ctx.types.builtin_method_type
195-
}
196-
}
197-
198192
impl fmt::Debug for PyNativeMethod {
199193
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200194
write!(

crates/vm/src/builtins/str.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,12 +1932,10 @@ impl PyPayload for PyUtf8Str {
19321932
std::any::TypeId::of::<PyStr>()
19331933
}
19341934

1935-
fn downcastable_from(obj: &PyObject) -> bool {
1936-
obj.typeid() == Self::payload_type_id() && {
1937-
// SAFETY: we know the object is a PyStr in this context
1938-
let wtf8 = unsafe { obj.downcast_unchecked_ref::<PyStr>() };
1939-
wtf8.is_utf8()
1940-
}
1935+
fn validate_downcastable_from(obj: &PyObject) -> bool {
1936+
// SAFETY: we know the object is a PyStr in this context
1937+
let wtf8 = unsafe { obj.downcast_unchecked_ref::<PyStr>() };
1938+
wtf8.is_utf8()
19411939
}
19421940

19431941
fn try_downcast_from(obj: &PyObject, vm: &VirtualMachine) -> PyResult<()> {

crates/vm/src/object/core.rs

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,30 +1070,14 @@ impl<T: PyPayload + std::fmt::Debug> PyRef<T> {
10701070
}
10711071
}
10721072

1073-
impl<T: crate::class::PySubclass> PyRef<T> {
1074-
/// Returns a reference to the base type's payload.
1075-
#[inline]
1076-
pub fn as_base(&self) -> &T::Base {
1077-
(**self).as_base()
1078-
}
1079-
}
1080-
1081-
impl<T: crate::class::PySubclassTransparent> PyRef<T> {
1073+
impl<T: crate::class::PySubclassTransparent + std::fmt::Debug> PyRef<T>
1074+
where
1075+
T::Base: std::fmt::Debug,
1076+
{
10821077
/// Converts this reference to the base type (ownership transfer).
1083-
///
1084-
/// Only available for `#[repr(transparent)]` types where memory layout
1085-
/// is identical to the base type.
1086-
#[inline]
1087-
pub fn into_base_ref(self) -> PyRef<T::Base> {
1088-
// SAFETY: #[repr(transparent)] guarantees same memory layout
1089-
unsafe { std::mem::transmute(self) }
1090-
}
1091-
1092-
/// Returns a reference to this as a PyRef of the base type.
1093-
///
10941078
/// Only available for `#[repr(transparent)]` types.
10951079
#[inline]
1096-
pub fn as_base_ref(&self) -> &PyRef<T::Base> {
1080+
pub fn into_base_ref(self) -> PyRef<T::Base> {
10971081
// SAFETY: #[repr(transparent)] guarantees same memory layout
10981082
unsafe { std::mem::transmute(self) }
10991083
}

crates/vm/src/object/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,3 @@ pub use self::core::*;
88
pub use self::ext::*;
99
pub use self::payload::*;
1010
pub use traverse::{MaybeTraverse, Traverse, TraverseFn};
11-
12-
pub(crate) use self::payload::cold_downcast_type_error;

crates/vm/src/object/payload.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,12 @@ pub trait PyPayload: MaybeTraverse + PyThreadingConstraint + Sized + 'static {
3434
/// # Safety: this function should only be called if `payload_type_id` matches the type of `obj`.
3535
#[inline]
3636
fn downcastable_from(obj: &PyObject) -> bool {
37-
obj.typeid() == Self::payload_type_id()
37+
obj.typeid() == Self::payload_type_id() && Self::validate_downcastable_from(obj)
38+
}
39+
40+
#[inline]
41+
fn validate_downcastable_from(_obj: &PyObject) -> bool {
42+
true
3843
}
3944

4045
fn try_downcast_from(obj: &PyObject, vm: &VirtualMachine) -> PyResult<()> {

crates/vm/src/stdlib/ast/pyast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ macro_rules! impl_node {
7878
}
7979

8080
#[pyclass(module = "_ast", name = "mod", base = NodeAst)]
81-
pub(crate) struct NodeMod;
81+
pub(crate) struct NodeMod(NodeAst);
8282

8383
#[pyclass(flags(HAS_DICT, BASETYPE))]
8484
impl NodeMod {}

crates/vm/src/stdlib/ctypes/array.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use rustpython_vm::stdlib::ctypes::_ctypes::get_size;
2121
use rustpython_vm::stdlib::ctypes::base::PyCData;
2222

2323
#[pyclass(name = "PyCArrayType", base = PyType, module = "_ctypes")]
24-
#[derive(PyPayload)]
2524
pub struct PyCArrayType {
2625
pub(super) stg_info: StgInfo,
2726
pub(super) typ: PyRwLock<PyObjectRef>,
@@ -228,7 +227,6 @@ impl AsNumber for PyCArrayType {
228227
metaclass = "PyCArrayType",
229228
module = "_ctypes"
230229
)]
231-
#[derive(PyPayload)]
232230
pub struct PyCArray {
233231
/// Element type - can be a simple type (c_int) or an array type (c_int * 5)
234232
pub(super) typ: PyRwLock<PyObjectRef>,

crates/vm/src/stdlib/ctypes/base.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ impl PyCData {
230230
}
231231

232232
#[pyclass(module = "_ctypes", name = "PyCSimpleType", base = PyType)]
233-
#[derive(Debug, PyPayload, Default)]
233+
#[derive(Debug, Default)]
234234
pub struct PyCSimpleType {
235235
#[allow(dead_code)]
236236
pub stg_info: StgInfo,
@@ -416,7 +416,6 @@ impl AsNumber for PyCSimpleType {
416416
base = PyCData,
417417
metaclass = "PyCSimpleType"
418418
)]
419-
#[derive(PyPayload)]
420419
pub struct PyCSimple {
421420
pub _type_: String,
422421
pub value: AtomicCell<PyObjectRef>,

0 commit comments

Comments
 (0)