diff --git a/derive/src/pyclass.rs b/derive/src/pyclass.rs index b26520f60..8ead38119 100644 --- a/derive/src/pyclass.rs +++ b/derive/src/pyclass.rs @@ -16,9 +16,63 @@ use syn_ext::ext::*; struct ImplContext { impl_extend_items: ItemNursery, getset_items: GetSetNursery, + extend_slots_items: ItemNursery, errors: Vec, } +fn extract_items_into_context<'a, Item>( + context: &mut ImplContext, + items: impl Iterator, +) where + Item: ItemLike + ToTokens + GetIdent + syn_ext::ext::ItemAttrExt + 'a, +{ + for item in items { + let r = item.try_split_attr_mut(|attrs, item| { + let (pyitems, cfgs) = attrs_to_content_items(&attrs, new_impl_item::)?; + for pyitem in pyitems.iter().rev() { + let r = pyitem.gen_impl_item(ImplItemArgs:: { + item, + attrs, + context, + cfgs: cfgs.as_slice(), + }); + context.errors.ok_or_push(r); + } + Ok(()) + }); + context.errors.ok_or_push(r); + } + context.errors.ok_or_push(context.getset_items.validate()); +} + +fn raw_extend_methods(context: &ImplContext) -> impl Iterator { + let getset_impl = &context.getset_items; + let extend_impl = &context.impl_extend_items; + let slots_impl = &context.extend_slots_items; + macro_rules! iter_chain { + ($($it:expr),*$(,)?) => { + std::iter::empty() + $(.chain(std::iter::once($it)))* + }; + } + iter_chain![ + parse_quote! { + fn __extend_py_class( + ctx: &::rustpython_vm::pyobject::PyContext, + class: &::rustpython_vm::obj::objtype::PyClassRef, + ) { + #getset_impl + #extend_impl + } + }, + parse_quote! { + fn __extend_slots(slots: &mut ::rustpython_vm::slots::PyClassSlots) { + #slots_impl + } + }, + ] +} + pub(crate) fn impl_pyimpl( attr: AttributeArgs, item: Item, @@ -26,80 +80,55 @@ pub(crate) fn impl_pyimpl( let mut context = ImplContext::default(); let mut tokens = match item { Item::Impl(mut imp) => { - for item in imp.items.iter_mut() { - let r = item.try_split_attr_mut(|attrs, item| { - let (pyitems, cfgs) = - attrs_to_content_items(&attrs, new_impl_item::)?; - for pyitem in pyitems.iter().rev() { - let r = pyitem.gen_impl_item(ImplItemArgs { - item, - attrs, - context: &mut context, - cfgs: cfgs.as_slice(), - }); - context.errors.ok_or_push(r); - } - Ok(()) - }); - context.errors.ok_or_push(r); - } - context.errors.ok_or_push(context.getset_items.validate()); + extract_items_into_context(&mut context, imp.items.iter_mut()); + + let ExtractedImplAttrs { + with_impl, + flags, + with_slots, + structseq_impl, + } = extract_impl_attrs(attr)?; - let (with_impl, flags) = extract_impl_attrs(attr)?; let ty = &imp.self_ty; - let getset_impl = &context.getset_items; - let extend_impl = &context.impl_extend_items; - quote! { - #imp - impl ::rustpython_vm::pyobject::PyClassImpl for #ty { - const TP_FLAGS: ::rustpython_vm::slots::PyTpFlags = ::rustpython_vm::slots::PyTpFlags::from_bits_truncate(#flags); - fn impl_extend_class( - ctx: &::rustpython_vm::pyobject::PyContext, - class: &::rustpython_vm::obj::objtype::PyClassRef, - ) { - #getset_impl - #extend_impl - #with_impl + if structseq_impl { + imp.items.extend(raw_extend_methods(&context)); + imp.into_token_stream() + } else { + let getset_impl = &context.getset_items; + let extend_impl = &context.impl_extend_items; + let slots_impl = &context.extend_slots_items; + quote! { + #imp + impl ::rustpython_vm::pyobject::PyClassImpl for #ty { + const TP_FLAGS: ::rustpython_vm::slots::PyTpFlags = ::rustpython_vm::slots::PyTpFlags::from_bits_truncate(#flags); + + fn impl_extend_class( + ctx: &::rustpython_vm::pyobject::PyContext, + class: &::rustpython_vm::obj::objtype::PyClassRef, + ) { + #getset_impl + #extend_impl + #with_impl + } + + fn extend_slots(slots: &mut ::rustpython_vm::slots::PyClassSlots) { + #with_slots + #slots_impl + } } } } } Item::Trait(mut trai) => { let mut context = ImplContext::default(); - for item in trai.items.iter_mut() { - let r = item.try_split_attr_mut(|attrs, item| { - let (pyitems, cfgs) = - attrs_to_content_items(&attrs, new_impl_item::)?; - for pyitem in pyitems.iter().rev() { - let r = pyitem.gen_impl_item(ImplItemArgs { - item, - attrs, - context: &mut context, - cfgs: cfgs.as_slice(), - }); - context.errors.ok_or_push(r); - } - Ok(()) - }); - context.errors.ok_or_push(r); - } - context.errors.ok_or_push(context.getset_items.validate()); + extract_items_into_context(&mut context, trai.items.iter_mut()); + + trai.items.extend(raw_extend_methods(&context)); - let getset_impl = &context.getset_items; - let extend_impl = &context.impl_extend_items; - trai.items.push(parse_quote! { - fn __extend_py_class( - ctx: &::rustpython_vm::pyobject::PyContext, - class: &::rustpython_vm::obj::objtype::PyClassRef, - ) { - #getset_impl - #extend_impl - } - }); trai.into_token_stream() } - item => quote!(#item), + item => item.into_token_stream(), }; if let Some(error) = context.errors.into_error() { let error = Diagnostic::from(error); @@ -161,6 +190,19 @@ pub(crate) fn impl_pyclass( Ok(ret) } +struct StructSeqItemMeta(ItemMetaInner); + +impl ItemMeta for StructSeqItemMeta { + const ALLOWED_NAMES: &'static [&'static str] = &["module", "name", "with_pyimpl"]; + + fn from_inner(inner: ItemMetaInner) -> Self { + Self(inner) + } + fn inner(&self) -> &ItemMetaInner { + &self.0 + } +} + pub(crate) fn impl_pystruct_sequence( attr: AttributeArgs, item: Item, @@ -174,7 +216,9 @@ pub(crate) fn impl_pystruct_sequence( ) }; let fake_ident = Ident::new("pystruct_sequence", struc.span()); - let class_meta = ClassItemMeta::from_nested(struc.ident.clone(), fake_ident, attr.into_iter())?; + let meta = StructSeqItemMeta::from_nested(struc.ident.clone(), fake_ident, attr.into_iter())?; + let with_pyimpl = meta.inner()._bool("with_pyimpl")?; + let class_meta = ClassItemMeta(meta.0); let class_name = class_meta.class_name()?; let module_name = class_meta.mandatory_module()?; @@ -206,6 +250,19 @@ pub(crate) fn impl_pystruct_sequence( } } + let (with_extend, with_slots) = if with_pyimpl { + ( + quote! { + Self::__extend_py_class(ctx, class); + }, + quote! { + Self::__extend_slots(slots); + }, + ) + } else { + (quote! {}, quote! {}) + }; + let ty = &struc.ident; let ret = quote! { #struc @@ -242,6 +299,7 @@ pub(crate) fn impl_pystruct_sequence( #(#properties)* class.set_str_attr("__repr__", ctx.new_method(Self::repr)); + #with_extend } fn make_class( @@ -250,6 +308,10 @@ pub(crate) fn impl_pystruct_sequence( use crate::pyobject::PyClassDef; Self::make_class_with_base(ctx, Self::NAME, &ctx.types.tuple_type) } + + fn extend_slots(slots: &mut ::rustpython_vm::slots::PyClassSlots) { + #with_slots + } } }; Ok(ret) @@ -394,11 +456,11 @@ where #transform(Self::#ident) }; quote! { - (*class.slots.write()).#slot_ident = Some(#into_func); + slots.#slot_ident = Some(#into_func); } }; - args.context.impl_extend_items.add_item( + args.context.extend_slots_items.add_item( format!("(slot {})", slot_name), args.cfgs.to_vec(), tokens, @@ -639,11 +701,18 @@ impl SlotItemMeta { } } -fn extract_impl_attrs( - attr: AttributeArgs, -) -> std::result::Result<(TokenStream, TokenStream), Diagnostic> { +struct ExtractedImplAttrs { + with_impl: TokenStream, + with_slots: TokenStream, + flags: TokenStream, + structseq_impl: bool, +} + +fn extract_impl_attrs(attr: AttributeArgs) -> std::result::Result { let mut withs = Vec::new(); + let mut with_slots = Vec::new(); let mut flags = vec![quote! { ::rustpython_vm::slots::PyTpFlags::DEFAULT.bits() }]; + let mut structseq_impl = false; #[cfg(debug_assertions)] { flags.push(quote! { @@ -658,9 +727,21 @@ fn extract_impl_attrs( for meta in nested { match meta { NestedMeta::Meta(Meta::Path(path)) => { - withs.push(quote! { - ::__extend_py_class(ctx, class); - }); + if path_eq(&path, "Self") { + withs.push(quote! { + Self::__extend_py_class(ctx, class); + }); + with_slots.push(quote! { + Self::__extend_slots(slots); + }); + } else { + withs.push(quote! { + ::__extend_py_class(ctx, class); + }); + with_slots.push(quote! { + ::__extend_slots(slots); + }); + } } meta => { bail_span!(meta, "#[pyimpl(with(...))] arguments should be paths") @@ -691,18 +772,25 @@ fn extract_impl_attrs( bail_span!(path, "Unknown pyimpl attribute") } } + NestedMeta::Meta(Meta::Path(path)) if path_eq(&path, "structseq_impl") => { + structseq_impl = true + } attr => bail_span!(attr, "Unknown pyimpl attribute"), } } - Ok(( - quote! { + Ok(ExtractedImplAttrs { + with_impl: quote! { #(#withs)* }, - quote! { + flags: quote! { #(#flags)* }, - )) + with_slots: quote! { + #(#with_slots)* + }, + structseq_impl, + }) } fn new_impl_item(index: usize, attr_name: String) -> Box> diff --git a/derive/src/util.rs b/derive/src/util.rs index 0759ce91a..59e028cd3 100644 --- a/derive/src/util.rs +++ b/derive/src/util.rs @@ -223,7 +223,7 @@ impl ItemMeta for SimpleItemMeta { } } -pub(crate) struct ClassItemMeta(ItemMetaInner); +pub(crate) struct ClassItemMeta(pub ItemMetaInner); impl ItemMeta for ClassItemMeta { const ALLOWED_NAMES: &'static [&'static str] = &["module", "name"]; diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index f1bebec9d..bf989ea8d 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -10,7 +10,7 @@ use crate::pyobject::{ BorrowValue, PyClassDef, PyClassImpl, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, }; -use crate::types::create_type_with_flags; +use crate::types::create_type_with_slots; use crate::VirtualMachine; use crate::{py_serde, sysmodule}; @@ -463,7 +463,7 @@ pub struct ExceptionZoo { impl ExceptionZoo { pub fn new(type_type: &PyClassRef, object_type: &PyClassRef) -> Self { let create_exception_type = |name: &str, base: &PyClassRef| { - create_type_with_flags(name, type_type, base, PyBaseException::TP_FLAGS) + create_type_with_slots(name, type_type, base, PyBaseException::make_slots()) }; // Sorted By Hierarchy then alphabetized. let base_exception_type = create_exception_type(PyBaseExceptionRef::NAME, &object_type); diff --git a/vm/src/macros.rs b/vm/src/macros.rs index 9349c7c09..cb5d7bc6e 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -38,30 +38,35 @@ macro_rules! py_class { }; ( $ctx:expr, $class_name:expr, $class_base:expr, $flags:expr, { $($name:tt => $value:expr),* $(,)* }) => { { - let py_class = $ctx.new_class($class_name, $class_base, $crate::slots::PyTpFlags::DEFAULT | $flags); - $crate::extend_class!($ctx, &py_class, { $($name => $value),* }); + #[allow(unused_mut)] + let mut slots: $crate::slots::PyClassSlots = ($crate::slots::PyTpFlags::DEFAULT | $flags).into(); + $($crate::py_class!(@extract_slots($ctx, &mut slots, $name, $value));)* + let py_class = $ctx.new_class($class_name, $class_base, slots); + $($crate::py_class!(@extract_attrs($ctx, &py_class, $name, $value));)* + $ctx.add_tp_new_wrapper(&py_class); py_class } }; + (@extract_slots($ctx:expr, $slots:expr, (slot $slot_name:ident), $value:expr)) => { + $slots.$slot_name = Some( + $crate::function::IntoPyNativeFunc::into_func($value) + ); + }; + (@extract_slots($ctx:expr, $class:expr, $name:expr, $value:expr)) => {}; + (@extract_attrs($ctx:expr, $slots:expr, (slot $slot_name:ident), $value:expr)) => {}; + (@extract_attrs($ctx:expr, $class:expr, $name:expr, $value:expr)) => { + $class.set_str_attr($name, $value); + }; } #[macro_export] macro_rules! extend_class { - ( $ctx:expr, $class:expr, { $($name:tt => $value:expr),* $(,)* }) => { + ( $ctx:expr, $class:expr, { $($name:expr => $value:expr),* $(,)* }) => { $( - $crate::extend_class!(@set_attr($ctx, $class, $name, $value)); + $class.set_str_attr($name, $value); )* $ctx.add_tp_new_wrapper(&$class); }; - - (@set_attr($ctx:expr, $class:expr, (slot $slot_name:ident), $value:expr)) => { - $class.slots.write().$slot_name = Some( - $crate::function::IntoPyNativeFunc::into_func($value) - ); - }; - (@set_attr($ctx:expr, $class:expr, $name:expr, $value:expr)) => { - $class.set_str_attr($name, $value); - }; } #[macro_export] diff --git a/vm/src/obj/objmodule.rs b/vm/src/obj/objmodule.rs index 5646ac624..e156e424c 100644 --- a/vm/src/obj/objmodule.rs +++ b/vm/src/obj/objmodule.rs @@ -56,6 +56,7 @@ impl PyModuleRef { vm: &VirtualMachine, ) -> PyResult<()> { debug_assert!(crate::pyobject::TypeProtocol::lease_class(self.as_object()) + .slots .flags .has_feature(crate::slots::PyTpFlags::HAS_DICT)); init_module_dict( diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index 70b618a44..da3b62798 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -32,8 +32,7 @@ pub struct PyClass { pub mro: Vec, pub subclasses: PyRwLock>, pub attributes: PyRwLock, - pub flags: PyTpFlags, - pub slots: PyRwLock, + pub slots: PyClassSlots, } impl fmt::Display for PyClass { @@ -58,7 +57,7 @@ impl PyValue for PyClass { impl PyClassRef { fn tp_name(zelf: Self, vm: &VirtualMachine) -> String { - let opt_name = zelf.slots.read().name.clone(); + let opt_name = zelf.slots.name.read().clone(); opt_name.unwrap_or_else(|| { let module = zelf.attributes.read().get("__module__").cloned(); let new_name = if let Some(module) = module { @@ -69,7 +68,7 @@ impl PyClassRef { } else { zelf.name.clone() }; - zelf.slots.write().name = Some(new_name.clone()); + *zelf.slots.name.write() = Some(new_name.clone()); new_name }) } @@ -104,7 +103,7 @@ impl PyClassRef { #[pyproperty(magic)] fn flags(self) -> u64 { - self.flags.bits() + self.slots.flags.bits() } #[pymethod(magic)] @@ -158,7 +157,7 @@ impl PyClassRef { #[pyproperty(magic, setter)] fn set_module(self, value: PyObjectRef) { - self.slots.write().name = None; + *self.slots.name.write() = None; self.attributes .write() .insert("__module__".to_owned(), value); @@ -188,7 +187,7 @@ impl PyClassRef { if let Some(attr) = self.get_attr(&name) { let attr_class = attr.class(); - let slots = attr_class.slots.read(); + let slots = &attr_class.slots; if let Some(ref descr_get) = slots.descr_get { drop(mcl); return descr_get(vm, attr, None, OptionalArg::Present(self.into_object())); @@ -321,12 +320,10 @@ impl PyClassRef { let winner = calculate_meta_class(metatype.clone(), &bases, vm)?; let metatype = if !winner.is(&metatype) { #[allow(clippy::redundant_clone)] // false positive - { - if let Some(ref tp_new) = winner.clone().slots.read().new { - // Pass it to the winner + if let Some(ref tp_new) = winner.clone().slots.new { + // Pass it to the winner - return tp_new(vm, args.insert(winner.into_object())); - } + return tp_new(vm, args.insert(winner.into_object())); } winner } else { @@ -360,7 +357,7 @@ impl PyClassRef { } // TODO: how do we know if it should have a dict? - let flags = base.flags | PyTpFlags::HAS_DICT; + let flags = base.slots.flags | PyTpFlags::HAS_DICT; let typ = new( metatype, @@ -368,7 +365,7 @@ impl PyClassRef { base, bases, attributes, - flags, + flags.into(), ) .map_err(|e| vm.new_type_error(e))?; @@ -544,7 +541,7 @@ fn call_tp_new( return vm.invoke(&new_meth, args.insert(typ.clone().into_object())); } } - if let Some(tp_new) = cls.slots.read().new.as_ref() { + if let Some(tp_new) = cls.slots.new.as_ref() { return tp_new(vm, args.insert(subtype.into_object())); } } @@ -677,7 +674,7 @@ pub fn new( base: PyClassRef, bases: Vec, attrs: HashMap, - mut flags: PyTpFlags, + mut slots: PyClassSlots, ) -> Result { // Check for duplicates in bases. let mut unique_bases = HashSet::new(); @@ -693,8 +690,8 @@ pub fn new( .collect(); let mro = linearise_mro(mros)?; - if base.flags.has_feature(PyTpFlags::HAS_DICT) { - flags |= PyTpFlags::HAS_DICT + if base.slots.flags.has_feature(PyTpFlags::HAS_DICT) { + slots.flags |= PyTpFlags::HAS_DICT } let new_type = PyRef::new_ref( PyClass { @@ -704,8 +701,7 @@ pub fn new( mro, subclasses: PyRwLock::default(), attributes: PyRwLock::new(attrs), - flags, - slots: PyRwLock::default(), + slots, }, typ, None, @@ -763,7 +759,7 @@ fn best_base<'a>(bases: &'a [PyClassRef], vm: &VirtualMachine) -> PyResult PyClassRef { - create_type_with_flags(name, &self.types.type_type, base, flags) + pub fn new_class(&self, name: &str, base: &PyClassRef, slots: PyClassSlots) -> PyClassRef { + create_type_with_slots(name, &self.types.type_type, base, slots) } pub fn new_namespace(&self) -> PyObjectRef { @@ -1177,7 +1177,7 @@ pub trait PyValue: fmt::Debug + PyThreadingConstraint + Sized + 'static { } fn into_ref_with_type_unchecked(self, cls: PyClassRef, vm: &VirtualMachine) -> PyRef { - let dict = if cls.flags.has_feature(PyTpFlags::HAS_DICT) { + let dict = if cls.slots.flags.has_feature(PyTpFlags::HAS_DICT) { Some(vm.ctx.new_dict()) } else { None @@ -1282,7 +1282,7 @@ pub trait PyClassImpl: PyClassDef { fn extend_class(ctx: &PyContext, class: &PyClassRef) { #[cfg(debug_assertions)] { - assert!(class.flags.is_created_with_flags()); + assert!(class.slots.flags.is_created_with_flags()); } if Self::TP_FLAGS.has_feature(PyTpFlags::HAS_DICT) { class.set_str_attr( @@ -1295,7 +1295,6 @@ pub trait PyClassImpl: PyClassDef { ); } Self::impl_extend_class(ctx, class); - class.slots.write().name = Some(Self::TP_NAME.to_owned()); ctx.add_tp_new_wrapper(&class); if let Some(doc) = Self::DOC { class.set_str_attr("__doc__", ctx.new_str(doc)); @@ -1310,13 +1309,23 @@ pub trait PyClassImpl: PyClassDef { } fn make_class_with_base(ctx: &PyContext, name: &str, base: &PyClassRef) -> PyClassRef { - let py_class = ctx.new_class(name, base, Self::TP_FLAGS); + let py_class = ctx.new_class(name, base, Self::make_slots()); Self::extend_class(ctx, &py_class); py_class } fn create_bare_type(type_type: &PyClassRef, base: &PyClassRef) -> PyClassRef { - create_type_with_flags(Self::NAME, type_type, base, Self::TP_FLAGS) + create_type_with_slots(Self::NAME, type_type, base, Self::make_slots()) + } + + fn extend_slots(slots: &mut PyClassSlots); + + fn make_slots() -> PyClassSlots { + let mut slots = PyClassSlots::default(); + slots.flags = Self::TP_FLAGS; + slots.name = PyRwLock::new(Some(Self::TP_NAME.to_owned())); + Self::extend_slots(&mut slots); + slots } } diff --git a/vm/src/slots.rs b/vm/src/slots.rs index a4653c7b9..345b1d099 100644 --- a/vm/src/slots.rs +++ b/vm/src/slots.rs @@ -1,3 +1,4 @@ +use crate::common::cell::PyRwLock; use crate::function::{OptionalArg, PyFuncArgs, PyNativeFunc}; use crate::pyobject::{IdProtocol, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject}; use crate::VirtualMachine; @@ -35,12 +36,22 @@ impl Default for PyTpFlags { #[derive(Default)] pub struct PyClassSlots { - pub name: Option, // tp_name, not class name + pub flags: PyTpFlags, + pub name: PyRwLock>, // tp_name, not class name pub new: Option, pub call: Option, pub descr_get: Option, } +impl From for PyClassSlots { + fn from(flags: PyTpFlags) -> Self { + Self { + flags, + ..Default::default() + } + } +} + impl std::fmt::Debug for PyClassSlots { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("PyClassSlots") diff --git a/vm/src/stdlib/time_module.rs b/vm/src/stdlib/time_module.rs index 936be534e..3184ef97e 100644 --- a/vm/src/stdlib/time_module.rs +++ b/vm/src/stdlib/time_module.rs @@ -170,7 +170,7 @@ fn time_strptime( Ok(PyStructTime::new(vm, instant, -1).into_obj(vm)) } -#[pystruct_sequence(module = "time", name = "struct_time")] +#[pystruct_sequence(with_pyimpl, module = "time", name = "struct_time")] #[allow(dead_code)] struct PyStructTime { tm_year: PyObjectRef, @@ -190,6 +190,7 @@ impl fmt::Debug for PyStructTime { } } +#[pyimpl(structseq_impl)] impl PyStructTime { fn new(vm: &VirtualMachine, tm: NaiveDateTime, isdst: i32) -> Self { PyStructTime { @@ -227,6 +228,7 @@ impl PyStructTime { .into_object() } + #[pyslot] fn tp_new(cls: PyClassRef, seq: PyObjectRef, vm: &VirtualMachine) -> PyResult { Self::try_from_object(vm, seq)?.into_struct_sequence(vm, cls) } @@ -260,11 +262,6 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { let struct_time_type = PyStructTime::make_class(ctx); - // TODO: allow $[pyimpl]s for struct_sequences - extend_class!(ctx, struct_time_type, { - (slot new) => PyStructTime::tp_new, - }); - py_module!(vm, "time", { "asctime" => ctx.new_function(time_asctime), "ctime" => ctx.new_function(time_ctime), diff --git a/vm/src/sysmodule.rs b/vm/src/sysmodule.rs index fee1c93eb..12a41a31f 100644 --- a/vm/src/sysmodule.rs +++ b/vm/src/sysmodule.rs @@ -69,7 +69,7 @@ fn getframe(offset: OptionalArg, vm: &VirtualMachine) -> PyResult Self { // Start with sensible defaults: @@ -119,6 +120,11 @@ impl SysFlags { flags.dont_write_bytecode = settings.dont_write_bytecode as u8; flags } + + #[pyslot] + fn tp_new(_cls: PyClassRef, _args: PyFuncArgs, vm: &VirtualMachine) -> PyResult { + Err(vm.new_type_error("cannot create 'sys.flags' instances".to_owned())) + } } fn sys_getrefcount(obj: PyObjectRef) -> usize { @@ -433,21 +439,11 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectR let ctx = &vm.ctx; let flags_type = SysFlags::make_class(ctx); - extend_class!(ctx, flags_type, { - (slot new) => |_cls: PyClassRef, _args: PyFuncArgs, vm: &VirtualMachine| -> PyResult { - Err(vm.new_type_error("cannot create 'sys.flags' instances".to_owned())) - }, - }); let flags = SysFlags::from_settings(&vm.state.settings) .into_struct_sequence(vm, flags_type) .unwrap(); let version_info_type = version::VersionInfo::make_class(ctx); - extend_class!(ctx, version_info_type, { - (slot new) => |_cls: PyClassRef, _args: PyFuncArgs, vm: &VirtualMachine| -> PyResult { - Err(vm.new_type_error("cannot create 'sys.version_info' instances".to_owned())) - }, - }); let version_info = version::VersionInfo::VERSION .into_struct_sequence(vm, version_info_type) .unwrap(); diff --git a/vm/src/types.rs b/vm/src/types.rs index 41393d069..5bf28904a 100644 --- a/vm/src/types.rs +++ b/vm/src/types.rs @@ -40,7 +40,7 @@ use crate::obj::objweakproxy; use crate::obj::objweakref; use crate::obj::objzip; use crate::pyobject::{PyAttributes, PyClassDef, PyClassImpl, PyContext, PyObject}; -use crate::slots::PyTpFlags; +use crate::slots::PyClassSlots; use rustpython_common::{cell::PyRwLock, rc::PyRc}; use std::mem::MaybeUninit; use std::ptr; @@ -202,14 +202,14 @@ impl TypeZoo { } pub fn create_type(name: &str, type_type: &PyClassRef, base: &PyClassRef) -> PyClassRef { - create_type_with_flags(name, type_type, base, Default::default()) + create_type_with_slots(name, type_type, base, Default::default()) } -pub fn create_type_with_flags( +pub fn create_type_with_slots( name: &str, type_type: &PyClassRef, base: &PyClassRef, - flags: PyTpFlags, + slots: PyClassSlots, ) -> PyClassRef { let dict = PyAttributes::new(); objtype::new( @@ -218,7 +218,7 @@ pub fn create_type_with_flags( base.clone(), vec![base.clone()], dict, - PyTpFlags::default() | flags, + slots, ) .expect("Failed to create a new type in internal code.") } @@ -265,8 +265,7 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) { mro: vec![], subclasses: PyRwLock::default(), attributes: PyRwLock::new(PyAttributes::new()), - flags: objtype::PyClassRef::TP_FLAGS, - slots: PyRwLock::default(), + slots: objtype::PyClassRef::make_slots(), }, }, Uninit { typ } @@ -281,8 +280,7 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) { mro: vec![], subclasses: PyRwLock::default(), attributes: PyRwLock::new(PyAttributes::new()), - flags: objobject::PyBaseObject::TP_FLAGS, - slots: PyRwLock::default(), + slots: objobject::PyBaseObject::make_slots(), }, }, Uninit { typ }, diff --git a/vm/src/version.rs b/vm/src/version.rs index 66c2d5fa1..ad1a17128 100644 --- a/vm/src/version.rs +++ b/vm/src/version.rs @@ -15,7 +15,7 @@ const SERIAL: usize = 0; pub const VERSION_HEX: usize = (MAJOR << 24) | (MINOR << 16) | (MICRO << 8) | (RELEASELEVEL_N << 4) | SERIAL; -#[pystruct_sequence(module = "sys", name = "version_info")] +#[pystruct_sequence(with_pyimpl, module = "sys", name = "version_info")] #[derive(Default, Debug)] pub struct VersionInfo { major: usize, @@ -34,6 +34,7 @@ pub fn get_version() -> String { ) } +#[pyimpl(structseq_impl)] impl VersionInfo { pub const VERSION: VersionInfo = VersionInfo { major: MAJOR, @@ -42,6 +43,14 @@ impl VersionInfo { releaselevel: RELEASELEVEL, serial: SERIAL, }; + #[pyslot] + fn tp_new( + _cls: crate::obj::objtype::PyClassRef, + _args: crate::function::PyFuncArgs, + vm: &crate::VirtualMachine, + ) -> crate::pyobject::PyResult { + Err(vm.new_type_error("cannot create 'sys.version_info' instances".to_owned())) + } } pub fn get_version_number() -> String { diff --git a/vm/src/vm.rs b/vm/src/vm.rs index de6020304..1f12888f7 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -767,7 +767,7 @@ impl VirtualMachine { cls: Option, ) -> Option { let descr_class = descr.class(); - let slots = descr_class.slots.read(); + let slots = &descr_class.slots; if let Some(descr_get) = slots.descr_get.as_ref() { Some(descr_get(self, descr, obj, OptionalArg::from_option(cls))) } else if let Some(ref descriptor) = descr_class.get_attr("__get__") { @@ -819,7 +819,7 @@ impl VirtualMachine { fn _invoke(&self, callable: &PyObjectRef, args: PyFuncArgs) -> PyResult { vm_trace!("Invoke: {:?} {:?}", callable, args); - if let Some(slot_call) = callable.lease_class().slots.read().call.as_ref() { + if let Some(slot_call) = callable.lease_class().slots.call.as_ref() { self.trace_event(TraceEvent::Call)?; let args = args.insert(callable.clone()); let result = slot_call(self, args); @@ -1052,8 +1052,7 @@ impl VirtualMachine { pub fn is_callable(&self, obj: &PyObjectRef) -> bool { let class = obj.lease_class(); - let lock = class.slots.read(); - lock.call.is_some() || class.has_attr("__call__") + class.slots.call.is_some() || class.has_attr("__call__") } #[inline]