From 7536554ceb520d17a4d52c4583d820251fa681cf Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Tue, 4 May 2021 21:10:03 +0100 Subject: [PATCH] type_object: remove layout and base type from PyTypeInfo --- CHANGELOG.md | 4 +- guide/src/class.md | 6 +- pyo3-macros-backend/src/pyclass.rs | 19 ++-- src/class/impl_.rs | 38 +++++++- src/derive_utils.rs | 19 ---- src/instance.rs | 6 +- src/pycell.rs | 99 ++++++++++----------- src/pyclass.rs | 6 +- src/pyclass_init.rs | 34 ++++--- src/serde.rs | 6 +- src/type_object.rs | 36 +------- src/types/any.rs | 8 +- src/types/mod.rs | 33 +++---- tests/ui/abi3_nativetype_inheritance.stderr | 35 +++++--- tests/ui/invalid_pymethod_receiver.stderr | 8 +- 15 files changed, 156 insertions(+), 201 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b8f040b..2a2a821a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,7 +48,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - `PyMethodDef_INIT` [#1426](https://github.com/PyO3/pyo3/pull/1426) - `PyTypeObject_INIT` [#1429](https://github.com/PyO3/pyo3/pull/1429) - `PyObject_Check`, `PySuper_Check`, and `FreeFunc` [#1438](https://github.com/PyO3/pyo3/pull/1438) -- Remove pyclass implementation details `Type`, `DESCRIPTION`, and `FLAGS` from `PyTypeInfo`. [#1456](https://github.com/PyO3/pyo3/pull/1456) +- Remove pyclass implementation details from `PyTypeInfo`: + - `Type`, `DESCRIPTION`, and `FLAGS` [#1456](https://github.com/PyO3/pyo3/pull/1456) + - `BaseType`, `BaseLayout`, `Layout`, `Initializer` [#1596](https://github.com/PyO3/pyo3/pull/1596) - Remove `__doc__` from module's `__all__`. [#1509](https://github.com/PyO3/pyo3/pull/1509) - Remove `PYO3_CROSS_INCLUDE_DIR` environment variable and the associated C header parsing functionality. diff --git a/guide/src/class.md b/guide/src/class.md index 3451463b..6b164ab1 100644 --- a/guide/src/class.md +++ b/guide/src/class.md @@ -723,10 +723,6 @@ struct MyClass { impl pyo3::pyclass::PyClassAlloc for MyClass {} unsafe impl pyo3::PyTypeInfo for MyClass { - type BaseType = PyAny; - type BaseLayout = pyo3::pycell::PyCellBase; - type Layout = PyCell; - type Initializer = PyClassInitializer; type AsRefTarget = PyCell; const NAME: &'static str = "MyClass"; @@ -757,6 +753,8 @@ impl pyo3::class::impl_::PyClassImpl for MyClass { const IS_GC: bool = false; const IS_BASETYPE: bool = false; const IS_SUBCLASS: bool = false; + type Layout = PyCell; + type BaseType = PyAny; type ThreadChecker = pyo3::class::impl_::ThreadCheckerStub; fn for_each_method_def(visitor: impl FnMut(&pyo3::class::PyMethodDefType)) { diff --git a/pyo3-macros-backend/src/pyclass.rs b/pyo3-macros-backend/src/pyclass.rs index f570850d..1dd8db90 100644 --- a/pyo3-macros-backend/src/pyclass.rs +++ b/pyo3-macros-backend/src/pyclass.rs @@ -312,14 +312,14 @@ fn impl_class( let weakref = if attr.has_weaklist { quote! { pyo3::pyclass_slots::PyClassWeakRefSlot } } else if attr.has_extends { - quote! { ::WeakRef } + quote! { ::WeakRef } } else { quote! { pyo3::pyclass_slots::PyClassDummySlot } }; let dict = if attr.has_dict { quote! { pyo3::pyclass_slots::PyClassDictSlot } } else if attr.has_extends { - quote! { ::Dict } + quote! { ::Dict } } else { quote! { pyo3::pyclass_slots::PyClassDummySlot } }; @@ -358,13 +358,8 @@ fn impl_class( }; let base = &attr.base; - let base_layout = if attr.has_extends { - quote! { ::LayoutAsBase } - } else { - quote! { pyo3::pycell::PyCellBase } - }; let base_nativetype = if attr.has_extends { - quote! { ::BaseNativeType } + quote! { ::BaseNativeType } } else { quote! { pyo3::PyAny } }; @@ -386,7 +381,7 @@ fn impl_class( quote! { pyo3::class::impl_::ThreadCheckerImpl<#cls> } } else if attr.has_extends { quote! { - pyo3::class::impl_::ThreadCheckerInherited<#cls, <#cls as pyo3::type_object::PyTypeInfo>::BaseType> + pyo3::class::impl_::ThreadCheckerInherited<#cls, <#cls as pyo3::class::impl_::PyClassImpl>::BaseType> } } else { quote! { pyo3::class::impl_::ThreadCheckerStub<#cls> } @@ -398,10 +393,6 @@ fn impl_class( Ok(quote! { unsafe impl pyo3::type_object::PyTypeInfo for #cls { - type BaseType = #base; - type Layout = pyo3::PyCell; - type BaseLayout = #base_layout; - type Initializer = pyo3::pyclass_init::PyClassInitializer; type AsRefTarget = pyo3::PyCell; const NAME: &'static str = #cls_name; @@ -441,6 +432,8 @@ fn impl_class( const IS_BASETYPE: bool = #is_basetype; const IS_SUBCLASS: bool = #is_subclass; + type Layout = PyCell; + type BaseType = #base; type ThreadChecker = #thread_checker; fn for_each_method_def(visitor: impl FnMut(&pyo3::class::PyMethodDefType)) { diff --git a/src/class/impl_.rs b/src/class/impl_.rs index 4e87df97..3113be2b 100644 --- a/src/class/impl_.rs +++ b/src/class/impl_.rs @@ -1,6 +1,12 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::{derive_utils::PyBaseTypeUtils, ffi, PyMethodDefType, PyNativeType}; +use crate::{ + ffi, + pycell::PyCellLayout, + pyclass_init::PyObjectInit, + type_object::{PyLayout, PyTypeObject}, + PyClass, PyMethodDefType, PyNativeType, PyTypeInfo, +}; use std::{marker::PhantomData, thread}; /// This type is used as a "dummy" type on which dtolnay specializations are @@ -44,6 +50,12 @@ pub trait PyClassImpl: Sized { /// #[pyclass(extends=...)] const IS_SUBCLASS: bool = false; + /// Layout + type Layout: PyLayout; + + /// Base class + type BaseType: PyTypeInfo + PyTypeObject + PyClassBaseType; + /// This handles following two situations: /// 1. In case `T` is `Send`, stub `ThreadChecker` is used and does nothing. /// This implementation is used by default. Compile fails if `T: !Send`. @@ -241,9 +253,9 @@ impl PyClassThreadChecker for ThreadCheckerImpl { /// Thread checker for types that have `Send` and `extends=...`. /// Ensures that `T: Send` and the parent is not accessed by another thread. #[doc(hidden)] -pub struct ThreadCheckerInherited(PhantomData, U::ThreadChecker); +pub struct ThreadCheckerInherited(PhantomData, U::ThreadChecker); -impl PyClassThreadChecker for ThreadCheckerInherited { +impl PyClassThreadChecker for ThreadCheckerInherited { fn ensure(&self) { self.1.ensure(); } @@ -252,3 +264,23 @@ impl PyClassThreadChecker for ThreadCheckerInher } private_impl! {} } + +/// Trait denoting that this class is suitable to be used as a base type for PyClass. +pub trait PyClassBaseType: Sized { + type Dict; + type WeakRef; + type LayoutAsBase: PyCellLayout; + type BaseNativeType; + type ThreadChecker: PyClassThreadChecker; + type Initializer: PyObjectInit; +} + +/// All PyClasses can be used as a base type. +impl PyClassBaseType for T { + type Dict = T::Dict; + type WeakRef = T::WeakRef; + type LayoutAsBase = crate::pycell::PyCellInner; + type BaseNativeType = T::BaseNativeType; + type ThreadChecker = T::ThreadChecker; + type Initializer = crate::pyclass_init::PyClassInitializer; +} diff --git a/src/derive_utils.rs b/src/derive_utils.rs index f24e93cc..e784fab5 100644 --- a/src/derive_utils.rs +++ b/src/derive_utils.rs @@ -4,7 +4,6 @@ //! Functionality for the code generated by the derive backend -use crate::class::impl_::PyClassThreadChecker; use crate::err::{PyErr, PyResult}; use crate::exceptions::PyTypeError; use crate::instance::PyNativeType; @@ -326,24 +325,6 @@ impl ModuleDef { } } -/// Utilities for basetype -#[doc(hidden)] -pub trait PyBaseTypeUtils: Sized { - type Dict; - type WeakRef; - type LayoutAsBase; - type BaseNativeType; - type ThreadChecker: PyClassThreadChecker; -} - -impl PyBaseTypeUtils for T { - type Dict = T::Dict; - type WeakRef = T::WeakRef; - type LayoutAsBase = crate::pycell::PyCellInner; - type BaseNativeType = T::BaseNativeType; - type ThreadChecker = T::ThreadChecker; -} - /// Utility trait to enable &PyClass as a pymethod/function argument #[doc(hidden)] pub trait ExtractExt<'a> { diff --git a/src/instance.rs b/src/instance.rs index 00ab5abf..5a01d065 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -3,7 +3,6 @@ use crate::conversion::{PyTryFrom, ToBorrowedObject}; use crate::err::{PyDowncastError, PyErr, PyResult}; use crate::gil; use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell}; -use crate::type_object::PyBorrowFlagLayout; use crate::types::{PyDict, PyTuple}; use crate::{ ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyClass, PyClassInitializer, @@ -59,10 +58,7 @@ where T: PyClass, { /// Create a new instance `Py` of a `#[pyclass]` on the Python heap. - pub fn new(py: Python, value: impl Into>) -> PyResult> - where - T::BaseLayout: PyBorrowFlagLayout, - { + pub fn new(py: Python, value: impl Into>) -> PyResult> { let initializer = value.into(); let obj = initializer.create_cell(py)?; let ob = unsafe { Py::from_owned_ptr(py, obj as _) }; diff --git a/src/pycell.rs b/src/pycell.rs index 412c3499..9a5c40e5 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -1,12 +1,12 @@ //! Includes `PyCell` implementation. -use crate::class::impl_::PyClassThreadChecker; use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject}; use crate::exceptions::PyRuntimeError; use crate::pyclass::PyClass; use crate::pyclass_init::PyClassInitializer; use crate::pyclass_slots::{PyClassDict, PyClassWeakRef}; -use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout, PyTypeInfo}; +use crate::type_object::{PyLayout, PySizedLayout}; use crate::types::PyAny; +use crate::{class::impl_::PyClassBaseType, class::impl_::PyClassThreadChecker}; use crate::{ffi, IntoPy, PyErr, PyNativeType, PyObject, PyResult, Python}; use std::cell::{Cell, UnsafeCell}; use std::fmt; @@ -17,34 +17,18 @@ use std::ops::{Deref, DerefMut}; /// This is necessary for sharing BorrowFlag between parents and children. #[doc(hidden)] #[repr(C)] -pub struct PyCellBase { - ob_base: T::Layout, +pub struct PyCellBase { + ob_base: T, borrow_flag: Cell, } -unsafe impl PyLayout for PyCellBase +unsafe impl PyLayout for PyCellBase where - T: PyTypeInfo + PyNativeType, - T::Layout: PySizedLayout, + U: PySizedLayout, { const IS_NATIVE_TYPE: bool = true; } -// Thes impls ensures `PyCellBase` can be a base type. -impl PySizedLayout for PyCellBase -where - T: PyTypeInfo + PyNativeType, - T::Layout: PySizedLayout, -{ -} - -unsafe impl PyBorrowFlagLayout for PyCellBase -where - T: PyTypeInfo + PyNativeType, - T::Layout: PySizedLayout, -{ -} - /// Inner type of `PyCell` without dict slots and reference counter. /// This struct has two usages: /// 1. As an inner type of `PyRef` and `PyRefMut`. @@ -52,7 +36,7 @@ where #[doc(hidden)] #[repr(C)] pub struct PyCellInner { - ob_base: T::BaseLayout, + ob_base: ::LayoutAsBase, value: ManuallyDrop>, } @@ -64,9 +48,6 @@ impl AsPyPointer for PyCellInner { unsafe impl PyLayout for PyCellInner { const IS_NATIVE_TYPE: bool = false; - fn get_super(&mut self) -> Option<&mut T::BaseLayout> { - Some(&mut self.ob_base) - } fn py_init(&mut self, value: T) { self.value = ManuallyDrop::new(UnsafeCell::new(value)); } @@ -78,20 +59,11 @@ unsafe impl PyLayout for PyCellInner { // These impls ensures `PyCellInner` can be a base type. impl PySizedLayout for PyCellInner {} -unsafe impl PyBorrowFlagLayout for PyCellInner {} impl PyCellInner { fn get_ptr(&self) -> *mut T { self.value.get() } - fn get_borrow_flag(&self) -> BorrowFlag { - let base = (&self.ob_base) as *const _ as *const PyCellBase; - unsafe { (*base).borrow_flag.get() } - } - fn set_borrow_flag(&self, flag: BorrowFlag) { - let base = (&self.ob_base) as *const _ as *const PyCellBase; - unsafe { (*base).borrow_flag.set(flag) } - } } /// `PyCell` is the container type for [`PyClass`](../pyclass/trait.PyClass.html). @@ -203,10 +175,7 @@ impl PyCell { /// In cases where the value in the cell does not need to be accessed immediately after /// creation, consider [`Py::new`](../instance/struct.Py.html#method.new) as a more efficient /// alternative. - pub fn new(py: Python, value: impl Into>) -> PyResult<&Self> - where - T::BaseLayout: PyBorrowFlagLayout, - { + pub fn new(py: Python, value: impl Into>) -> PyResult<&Self> { unsafe { let initializer = value.into(); let self_ = initializer.create_cell(py)?; @@ -370,14 +339,10 @@ impl PyCell { } /// Allocates a new PyCell given a type object `subtype`. Used by our `tp_new` implementation. - /// Requires `T::BaseLayout: PyBorrowFlagLayout` to ensure `self` has a borrow flag. pub(crate) unsafe fn internal_new( py: Python, subtype: *mut ffi::PyTypeObject, - ) -> PyResult<*mut Self> - where - T::BaseLayout: PyBorrowFlagLayout, - { + ) -> PyResult<*mut Self> { let base = T::new(py, subtype); if base.is_null() { return Err(PyErr::fetch(py)); @@ -394,9 +359,6 @@ impl PyCell { unsafe impl PyLayout for PyCell { const IS_NATIVE_TYPE: bool = false; - fn get_super(&mut self) -> Option<&mut T::BaseLayout> { - Some(&mut self.inner.ob_base) - } fn py_init(&mut self, value: T) { self.inner.value = ManuallyDrop::new(UnsafeCell::new(value)); } @@ -504,7 +466,7 @@ impl<'p, T: PyClass> PyRef<'p, T> { impl<'p, T, U> AsRef for PyRef<'p, T> where - T: PyClass + PyTypeInfo>, + T: PyClass, U: PyClass, { fn as_ref(&self) -> &T::BaseType { @@ -514,7 +476,7 @@ where impl<'p, T, U> PyRef<'p, T> where - T: PyClass + PyTypeInfo>, + T: PyClass, U: PyClass, { /// Get `PyRef`. @@ -621,7 +583,7 @@ impl<'p, T: PyClass> PyRefMut<'p, T> { impl<'p, T, U> AsRef for PyRefMut<'p, T> where - T: PyClass + PyTypeInfo>, + T: PyClass, U: PyClass, { fn as_ref(&self) -> &T::BaseType { @@ -631,7 +593,7 @@ where impl<'p, T, U> AsMut for PyRefMut<'p, T> where - T: PyClass + PyTypeInfo>, + T: PyClass, U: PyClass, { fn as_mut(&mut self) -> &mut T::BaseType { @@ -641,7 +603,7 @@ where impl<'p, T, U> PyRefMut<'p, T> where - T: PyClass + PyTypeInfo>, + T: PyClass, U: PyClass, { /// Get `PyRef`. @@ -702,8 +664,9 @@ impl fmt::Debug for PyRefMut<'_, T> { } } +#[doc(hidden)] #[derive(Copy, Clone, Eq, PartialEq)] -struct BorrowFlag(usize); +pub struct BorrowFlag(usize); impl BorrowFlag { const UNUSED: BorrowFlag = BorrowFlag(0); @@ -765,3 +728,33 @@ impl From for PyErr { PyRuntimeError::new_err(other.to_string()) } } + +#[doc(hidden)] +pub trait PyCellLayout: PyLayout { + fn get_borrow_flag(&self) -> BorrowFlag; + fn set_borrow_flag(&self, flag: BorrowFlag); +} + +impl PyCellLayout for PyCellBase +where + U: PySizedLayout, +{ + fn get_borrow_flag(&self) -> BorrowFlag { + self.borrow_flag.get() + } + fn set_borrow_flag(&self, flag: BorrowFlag) { + self.borrow_flag.set(flag) + } +} + +impl PyCellLayout for PyCellInner +where + ::LayoutAsBase: PyCellLayout, +{ + fn get_borrow_flag(&self) -> BorrowFlag { + self.ob_base.get_borrow_flag() + } + fn set_borrow_flag(&self, flag: BorrowFlag) { + self.ob_base.set_borrow_flag(flag) + } +} diff --git a/src/pyclass.rs b/src/pyclass.rs index b1eab814..da2d3e2a 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -1,8 +1,8 @@ //! `PyClass` and related traits. -use crate::class::impl_::PyClassImpl; use crate::class::methods::PyMethodDefType; use crate::pyclass_slots::{PyClassDict, PyClassWeakRef}; use crate::type_object::PyLayout; +use crate::{class::impl_::PyClassBaseType, class::impl_::PyClassImpl}; use crate::{ffi, PyCell, PyErr, PyNativeType, PyResult, PyTypeInfo, Python}; use std::convert::TryInto; use std::ffi::CString; @@ -45,7 +45,7 @@ pub(crate) unsafe fn default_new( subtype: *mut ffi::PyTypeObject, ) -> *mut ffi::PyObject { // if the class derives native types(e.g., PyDict), call special new - if T::IS_SUBCLASS && T::BaseLayout::IS_NATIVE_TYPE { + if T::IS_SUBCLASS && ::LayoutAsBase::IS_NATIVE_TYPE { #[cfg(not(Py_LIMITED_API))] { let base_tp = T::BaseType::type_object_raw(py); @@ -137,7 +137,7 @@ pub(crate) unsafe fn tp_free_fallback(ty: *mut ffi::PyTypeObject) -> ffi::freefu /// The `#[pyclass]` attribute automatically implements this trait for your Rust struct, /// so you don't have to use this trait directly. pub trait PyClass: - PyTypeInfo, AsRefTarget = PyCell> + Sized + PyClassAlloc + PyClassImpl + PyTypeInfo> + Sized + PyClassAlloc + PyClassImpl> { /// Specify this class has `#[pyclass(dict)]` or not. type Dict: PyClassDict; diff --git a/src/pyclass_init.rs b/src/pyclass_init.rs index 7b1ed2b5..b5619730 100644 --- a/src/pyclass_init.rs +++ b/src/pyclass_init.rs @@ -1,6 +1,6 @@ //! Initialization utilities for `#[pyclass]`. -use crate::callback::IntoPyCallbackOutput; -use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout, PyTypeInfo}; +use crate::type_object::{PyLayout, PyTypeInfo}; +use crate::{callback::IntoPyCallbackOutput, class::impl_::PyClassBaseType}; use crate::{PyCell, PyClass, PyResult, Python}; use std::marker::PhantomData; @@ -8,7 +8,7 @@ use std::marker::PhantomData; /// /// This trait is intended to use internally for distinguishing `#[pyclass]` and /// Python native types. -pub trait PyObjectInit: Sized { +pub trait PyObjectInit: Sized { fn init_class>(self, layout: &mut L); private_decl! {} } @@ -71,14 +71,14 @@ impl PyObjectInit for PyNativeTypeInitializer { /// ``` pub struct PyClassInitializer { init: T, - super_init: ::Initializer, + super_init: ::Initializer, } impl PyClassInitializer { /// Construct new initializer from value `T` and base class' initializer. /// /// We recommend to mainly use `add_subclass`, instead of directly call `new`. - pub fn new(init: T, super_init: ::Initializer) -> Self { + pub fn new(init: T, super_init: ::Initializer) -> Self { Self { init, super_init } } @@ -113,9 +113,8 @@ impl PyClassInitializer { /// ``` pub fn add_subclass(self, subclass_value: S) -> PyClassInitializer where - S: PyClass + PyTypeInfo, - S::BaseLayout: PySizedLayout, - S::BaseType: PyTypeInfo, + S: PyClass, + S::BaseType: PyClassBaseType, { PyClassInitializer::new(subclass_value, self) } @@ -125,7 +124,6 @@ impl PyClassInitializer { pub fn create_cell(self, py: Python) -> PyResult<*mut PyCell> where T: PyClass, - T::BaseLayout: PyBorrowFlagLayout, { unsafe { self.create_cell_from_subtype(py, T::type_object_raw(py)) } } @@ -143,7 +141,6 @@ impl PyClassInitializer { ) -> PyResult<*mut PyCell> where T: PyClass, - T::BaseLayout: PyBorrowFlagLayout, { let cell = PyCell::internal_new(py, subtype)?; self.init_class(&mut *cell); @@ -154,10 +151,12 @@ impl PyClassInitializer { impl PyObjectInit for PyClassInitializer { fn init_class>(self, layout: &mut L) { let Self { init, super_init } = self; + // Safety: A valid PyLayout must contain the base layout as the first entry, so casting L to + // T::BaseType::LayoutAsBase is ok. + super_init.init_class(unsafe { + &mut *(layout as *mut _ as *mut ::LayoutAsBase) + }); layout.py_init(init); - if let Some(super_obj) = layout.get_super() { - super_init.init_class(super_obj); - } } private_impl! {} } @@ -165,7 +164,7 @@ impl PyObjectInit for PyClassInitializer { impl From for PyClassInitializer where T: PyClass, - T::BaseType: PyTypeInfo>, + T::BaseType: PyClassBaseType>, { fn from(value: T) -> PyClassInitializer { Self::new(value, PyNativeTypeInitializer(PhantomData)) @@ -174,10 +173,9 @@ where impl From<(S, B)> for PyClassInitializer where - S: PyClass + PyTypeInfo, - S::BaseLayout: PySizedLayout, - B: PyClass + PyTypeInfo>, - B::BaseType: PyTypeInfo>, + S: PyClass, + B: PyClass, + B::BaseType: PyClassBaseType>, { fn from(sub_and_base: (S, B)) -> PyClassInitializer { let (sub, base) = sub_and_base; diff --git a/src/serde.rs b/src/serde.rs index e036e374..0d527c19 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -1,5 +1,4 @@ -use crate::type_object::PyBorrowFlagLayout; -use crate::{Py, PyClass, PyClassInitializer, PyTypeInfo, Python}; +use crate::{Py, PyAny, PyClass, Python}; use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer}; impl Serialize for Py @@ -20,8 +19,7 @@ where impl<'de, T> Deserialize<'de> for Py where - T: Into> + PyClass + Deserialize<'de>, - ::BaseLayout: PyBorrowFlagLayout<::BaseType>, + T: PyClass + Deserialize<'de>, { fn deserialize(deserializer: D) -> Result, D::Error> where diff --git a/src/type_object.rs b/src/type_object.rs index bf8c43e3..ebf7df8a 100644 --- a/src/type_object.rs +++ b/src/type_object.rs @@ -4,7 +4,6 @@ use crate::internal_tricks::extract_cstr_or_leak_cstring; use crate::once_cell::GILOnceCell; use crate::pyclass::{create_type_object, PyClass}; -use crate::pyclass_init::PyObjectInit; use crate::types::{PyAny, PyType}; use crate::{conversion::IntoPyPointer, PyMethodDefType}; use crate::{ffi, AsPyPointer, PyErr, PyNativeType, PyObject, PyResult, Python}; @@ -16,11 +15,8 @@ use std::thread::{self, ThreadId}; /// is of `PyAny`. /// /// This trait is intended to be used internally. -pub unsafe trait PyLayout { +pub unsafe trait PyLayout { const IS_NATIVE_TYPE: bool = true; - fn get_super(&mut self) -> Option<&mut T::BaseLayout> { - None - } fn py_init(&mut self, _value: T) {} unsafe fn py_drop(&mut self, _py: Python) {} } @@ -28,23 +24,7 @@ pub unsafe trait PyLayout { /// `T: PySizedLayout` represents `T` is not a instance of /// [`PyVarObject`](https://docs.python.org/3.8/c-api/structures.html?highlight=pyvarobject#c.PyVarObject). /// , in addition that `T` is a concrete representaion of `U`. -pub trait PySizedLayout: PyLayout + Sized {} - -/// Marker type indicates that `Self` can be a base layout of `PyClass`. -/// -/// # Safety -/// -/// Self should be laid out as follows: -/// ```ignore -/// #[repr(C)] -/// struct Self { -/// obj: ffi::PyObject, -/// borrow_flag: u64, -/// ... -/// } -/// ``` -/// Otherwise, implementing this trait is undefined behavior. -pub unsafe trait PyBorrowFlagLayout: PyLayout + Sized {} +pub trait PySizedLayout: PyLayout + Sized {} /// Python type information. /// All Python native types(e.g., `PyDict`) and `#[pyclass]` structs implement this trait. @@ -59,18 +39,6 @@ pub unsafe trait PyTypeInfo: Sized { /// Module name, if any const MODULE: Option<&'static str>; - /// Base class - type BaseType: PyTypeInfo + PyTypeObject; - - /// Layout - type Layout: PyLayout; - - /// Layout of Basetype. - type BaseLayout: PySizedLayout; - - /// Initializer for layout - type Initializer: PyObjectInit; - /// Utility type to make Py::as_ref work type AsRefTarget: crate::PyNativeType; diff --git a/src/types/any.rs b/src/types/any.rs index 15353faf..a1f396af 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -46,9 +46,6 @@ impl crate::AsPyPointer for PyAny { } } -unsafe impl crate::type_object::PyLayout for ffi::PyObject {} -impl crate::type_object::PySizedLayout for ffi::PyObject {} - #[allow(non_snake_case)] // Copied here as the macro does not accept deprecated functions. // Originally ffi::object::PyObject_Check, but this is not in the Python C API. @@ -56,9 +53,10 @@ fn PyObject_Check(_: *mut ffi::PyObject) -> c_int { 1 } +pyobject_native_type_base!(PyAny); + pyobject_native_type_info!( PyAny, - ffi::PyObject, ffi::PyBaseObject_Type, Some("builtins"), #checkfunction=PyObject_Check @@ -66,7 +64,7 @@ pyobject_native_type_info!( pyobject_native_type_extract!(PyAny); -pyobject_native_type_base!(PyAny); +pyobject_native_type_sized!(PyAny, ffi::PyObject); impl PyAny { /// Convert this PyAny to a concrete Python type. diff --git a/src/types/mod.rs b/src/types/mod.rs index bcfe16f5..caf1e277 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -128,13 +128,8 @@ macro_rules! pyobject_native_type_named ( #[macro_export] macro_rules! pyobject_native_type_info( - ($name:ty, $layout:path, $typeobject:expr, - $module:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => { + ($name:ty, $typeobject:expr, $module:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => { unsafe impl<$($generics,)*> $crate::type_object::PyTypeInfo for $name { - type BaseType = $crate::PyAny; - type Layout = $layout; - type BaseLayout = $crate::ffi::PyObject; - type Initializer = $crate::pyclass_init::PyNativeTypeInitializer; type AsRefTarget = Self; const NAME: &'static str = stringify!($name); @@ -176,35 +171,27 @@ macro_rules! pyobject_native_type_extract { #[macro_export] macro_rules! pyobject_native_type_core { ($name:ty, $typeobject:expr, #module=$module:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => { - $crate::pyobject_native_type_core!(@impl $name, $crate::PyAny, $typeobject, #module=$module $(, #checkfunction=$checkfunction)? $(;$generics)*); - }; - ($name:ty, $typeobject:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => { - $crate::pyobject_native_type_core!(@impl $name, $crate::PyAny, $typeobject, #module=Some("builtins") $(, #checkfunction=$checkfunction)? $(;$generics)*); - }; - - (@impl $name:ty, $layout:path, $typeobject:expr, #module=$module:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => { - unsafe impl $crate::type_object::PyLayout<$name> for $layout {} $crate::pyobject_native_type_named!($name $(;$generics)*); - $crate::pyobject_native_type_info!($name, $layout, $typeobject, $module $(, #checkfunction=$checkfunction)? $(;$generics)*); + $crate::pyobject_native_type_info!($name, $typeobject, $module $(, #checkfunction=$checkfunction)? $(;$generics)*); $crate::pyobject_native_type_extract!($name $(;$generics)*); }; - (@impl $name:ty, $layout:path, $typeobject:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => { - $crate::pyobject_native_type_core!(@impl $name, $layout, $typeobject, #module=Some("builtins") $(, #checkfunction=$checkfunction)? $(;$generics)*); + ($name:ty, $typeobject:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => { + $crate::pyobject_native_type_core!($name, $typeobject, #module=Some("builtins") $(, #checkfunction=$checkfunction)? $(;$generics)*); }; } #[macro_export] macro_rules! pyobject_native_type_sized { ($name:ty, $layout:path $(;$generics:ident)*) => { - // To prevent inheriting native types with ABI3 - #[cfg(not(Py_LIMITED_API))] + unsafe impl $crate::type_object::PyLayout<$name> for $layout {} impl $crate::type_object::PySizedLayout<$name> for $layout {} - impl<'a, $($generics,)*> $crate::derive_utils::PyBaseTypeUtils for $name { + impl<'a, $($generics,)*> $crate::class::impl_::PyClassBaseType for $name { type Dict = $crate::pyclass_slots::PyClassDummySlot; type WeakRef = $crate::pyclass_slots::PyClassDummySlot; - type LayoutAsBase = $crate::pycell::PyCellBase<$name>; + type LayoutAsBase = $crate::pycell::PyCellBase<$layout>; type BaseNativeType = $name; type ThreadChecker = $crate::class::impl_::ThreadCheckerStub<$crate::PyObject>; + type Initializer = $crate::pyclass_init::PyNativeTypeInitializer; } } } @@ -214,7 +201,9 @@ macro_rules! pyobject_native_type_sized { #[macro_export] macro_rules! pyobject_native_type { ($name:ty, $layout:path, $typeobject:expr $(, #module=$module:expr)? $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => { - $crate::pyobject_native_type_core!(@impl $name, $layout, $typeobject $(, #module=$module)? $(, #checkfunction=$checkfunction)? $(;$generics)*); + $crate::pyobject_native_type_core!($name, $typeobject $(, #module=$module)? $(, #checkfunction=$checkfunction)? $(;$generics)*); + // To prevent inheriting native types with ABI3 + #[cfg(not(Py_LIMITED_API))] $crate::pyobject_native_type_sized!($name, $layout $(;$generics)*); }; } diff --git a/tests/ui/abi3_nativetype_inheritance.stderr b/tests/ui/abi3_nativetype_inheritance.stderr index cf825281..c4f21ac4 100644 --- a/tests/ui/abi3_nativetype_inheritance.stderr +++ b/tests/ui/abi3_nativetype_inheritance.stderr @@ -1,13 +1,22 @@ -error[E0277]: the trait bound `PyDictObject: PySizedLayout` is not satisfied - --> $DIR/abi3_nativetype_inheritance.rs:5:1 - | -5 | #[pyclass(extends=PyDict)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PySizedLayout` is not implemented for `PyDictObject` - | - ::: $WORKSPACE/src/type_object.rs - | - | type BaseLayout: PySizedLayout; - | ----------------------------- required by this bound in `pyo3::PyTypeInfo::BaseLayout` - | - = note: required because of the requirements on the impl of `PySizedLayout` for `PyCellBase` - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0277]: the trait bound `PyDict: PyClass` is not satisfied + --> $DIR/abi3_nativetype_inheritance.rs:5:1 + | +5 | #[pyclass(extends=PyDict)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict` + | + = note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict` + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `PyDict: PyClass` is not satisfied + --> $DIR/abi3_nativetype_inheritance.rs:5:1 + | +5 | #[pyclass(extends=PyDict)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict` + | + ::: $WORKSPACE/src/class/impl_.rs + | + | pub struct ThreadCheckerInherited(PhantomData, U::ThreadChecker); + | --------------- required by this bound in `ThreadCheckerInherited` + | + = note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict` + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/invalid_pymethod_receiver.stderr b/tests/ui/invalid_pymethod_receiver.stderr index d6dc0ac6..babc831e 100644 --- a/tests/ui/invalid_pymethod_receiver.stderr +++ b/tests/ui/invalid_pymethod_receiver.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `i32: From<&PyCell>` is not satisfied +error[E0277]: the trait bound `i32: From<&pyo3::PyCell>` is not satisfied --> $DIR/invalid_pymethod_receiver.rs:8:43 | 8 | fn method_with_invalid_self_type(slf: i32, py: Python, index: u32) {} - | ^^^ the trait `From<&PyCell>` is not implemented for `i32` + | ^^^ the trait `From<&pyo3::PyCell>` is not implemented for `i32` | = help: the following implementations were found: > @@ -10,6 +10,6 @@ error[E0277]: the trait bound `i32: From<&PyCell>` is not satisfied > > and 2 others - = note: required because of the requirements on the impl of `Into` for `&PyCell` - = note: required because of the requirements on the impl of `TryFrom<&PyCell>` for `i32` + = note: required because of the requirements on the impl of `Into` for `&pyo3::PyCell` + = note: required because of the requirements on the impl of `TryFrom<&pyo3::PyCell>` for `i32` = note: required by `std::convert::TryFrom::try_from`