mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
Make HAVE_DICT a type flag
This commit is contained in:
13 files changed
+92
-65
No files matched your search
@@ -45,14 +45,12 @@ pub trait IntoPyException {
|
||||
}
|
||||
|
||||
impl PyValue for PyBaseException {
|
||||
const HAVE_DICT: bool = true;
|
||||
|
||||
fn class(vm: &VirtualMachine) -> PyClassRef {
|
||||
vm.ctx.exceptions.base_exception_type.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE))]
|
||||
#[pyimpl(flags(BASETYPE, HAS_DICT))]
|
||||
impl PyBaseException {
|
||||
pub(crate) fn new(args: Vec<PyObjectRef>, vm: &VirtualMachine) -> PyBaseException {
|
||||
PyBaseException {
|
||||
@@ -467,7 +465,7 @@ impl ExceptionZoo {
|
||||
pub fn new(type_type: &PyClassRef, object_type: &PyClassRef) -> Self {
|
||||
let create_exception_type = |name: &str, base: &PyClassRef| {
|
||||
let typ = create_type(name, type_type, base);
|
||||
typ.slots.write().flags |= PyTpFlags::BASETYPE;
|
||||
typ.slots.write().flags |= PyTpFlags::BASETYPE | PyTpFlags::HAS_DICT;
|
||||
typ
|
||||
};
|
||||
// Sorted By Hierarchy then alphabetized.
|
||||
|
||||
@@ -20,7 +20,6 @@ impl PyValue for PyBuiltinFunction {
|
||||
fn class(vm: &VirtualMachine) -> PyClassRef {
|
||||
vm.ctx.builtin_function_or_method_type()
|
||||
}
|
||||
const HAVE_DICT: bool = true;
|
||||
}
|
||||
|
||||
impl fmt::Debug for PyBuiltinFunction {
|
||||
@@ -59,7 +58,7 @@ impl SlotCall for PyBuiltinFunction {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotCall))]
|
||||
#[pyimpl(with(SlotCall), flags(HAS_DICT))]
|
||||
impl PyBuiltinFunction {
|
||||
#[pyproperty(magic)]
|
||||
fn module(&self) -> Option<PyStringRef> {
|
||||
|
||||
@@ -40,8 +40,6 @@ impl From<PyObjectRef> for PyClassMethod {
|
||||
}
|
||||
|
||||
impl PyValue for PyClassMethod {
|
||||
const HAVE_DICT: bool = true;
|
||||
|
||||
fn class(vm: &VirtualMachine) -> PyClassRef {
|
||||
vm.ctx.classmethod_type()
|
||||
}
|
||||
@@ -60,7 +58,7 @@ impl SlotDescriptor for PyClassMethod {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotDescriptor), flags(BASETYPE))]
|
||||
#[pyimpl(with(SlotDescriptor), flags(BASETYPE, HAS_DICT))]
|
||||
impl PyClassMethod {
|
||||
#[pyslot]
|
||||
fn tp_new(
|
||||
|
||||
@@ -259,7 +259,7 @@ impl PyValue for PyFunction {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotDescriptor))]
|
||||
#[pyimpl(with(SlotDescriptor), flags(HAS_DICT))]
|
||||
impl PyFunction {
|
||||
#[pyslot]
|
||||
#[pymethod(magic)]
|
||||
@@ -309,7 +309,7 @@ impl PyBoundMethod {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotCall))]
|
||||
#[pyimpl(with(SlotCall), flags(HAS_DICT))]
|
||||
impl PyBoundMethod {
|
||||
#[pymethod(magic)]
|
||||
fn repr(&self, vm: &VirtualMachine) -> PyResult<String> {
|
||||
|
||||
@@ -13,8 +13,6 @@ pub struct PyModule {}
|
||||
pub type PyModuleRef = PyRef<PyModule>;
|
||||
|
||||
impl PyValue for PyModule {
|
||||
const HAVE_DICT: bool = true;
|
||||
|
||||
fn class(vm: &VirtualMachine) -> PyClassRef {
|
||||
vm.ctx.module_type()
|
||||
}
|
||||
@@ -43,7 +41,7 @@ pub fn init_module_dict(
|
||||
.expect("Failed to set __spec__ on module");
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE))]
|
||||
#[pyimpl(flags(BASETYPE, HAS_DICT))]
|
||||
impl PyModuleRef {
|
||||
#[pyslot]
|
||||
fn tp_new(cls: PyClassRef, _args: PyFuncArgs, vm: &VirtualMachine) -> PyResult<PyModuleRef> {
|
||||
|
||||
@@ -11,13 +11,12 @@ use crate::vm::VirtualMachine;
|
||||
pub struct PyNamespace;
|
||||
|
||||
impl PyValue for PyNamespace {
|
||||
const HAVE_DICT: bool = true;
|
||||
fn class(vm: &VirtualMachine) -> PyClassRef {
|
||||
vm.ctx.namespace_type()
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE))]
|
||||
#[pyimpl(flags(BASETYPE, HAS_DICT))]
|
||||
impl PyNamespace {
|
||||
#[pyslot]
|
||||
fn tp_new(cls: PyClassRef, kwargs: KwArgs, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
|
||||
+10
-24
@@ -151,10 +151,7 @@ impl PyBaseObject {
|
||||
|
||||
// Get instance attributes:
|
||||
if let Some(object_dict) = obj.dict() {
|
||||
vm.invoke(
|
||||
&vm.get_attribute(dict.clone().into_object(), "update")?,
|
||||
object_dict.into_object(),
|
||||
)?;
|
||||
vm.call_method(dict.as_object(), "update", vec![object_dict.into_object()])?;
|
||||
}
|
||||
|
||||
let attributes: Vec<_> = dict.into_iter().map(|(k, _v)| k).collect();
|
||||
@@ -211,26 +208,6 @@ impl PyBaseObject {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproperty(magic)]
|
||||
fn dict(object: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyDictRef> {
|
||||
object.dict().ok_or_else(|| {
|
||||
vm.new_attribute_error(format!(
|
||||
"'{}' object has no attribute '__dict__'",
|
||||
object.lease_class().name
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
#[pyproperty(magic, setter)]
|
||||
fn set_dict(instance: PyObjectRef, value: PyDictRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
instance.set_dict(value).map_err(|_| {
|
||||
vm.new_attribute_error(format!(
|
||||
"'{}' object has no attribute '__dict__'",
|
||||
instance.lease_class().name
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn getattribute(obj: PyObjectRef, name: PyStringRef, vm: &VirtualMachine) -> PyResult {
|
||||
vm_trace!("object.__getattribute__({:?}, {:?})", obj, name);
|
||||
@@ -254,6 +231,15 @@ impl PyBaseObject {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn object_get_dict(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyDictRef> {
|
||||
obj.dict()
|
||||
.ok_or_else(|| vm.new_attribute_error("This object has no __dict__".to_owned()))
|
||||
}
|
||||
pub fn object_set_dict(obj: PyObjectRef, dict: PyDictRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
obj.set_dict(dict)
|
||||
.map_err(|_| vm.new_attribute_error("This object has no __dict__".to_owned()))
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame)]
|
||||
pub(crate) fn setattr(
|
||||
obj: PyObjectRef,
|
||||
|
||||
@@ -35,7 +35,7 @@ impl From<PyObjectRef> for PyStaticMethod {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotDescriptor), flags(BASETYPE))]
|
||||
#[pyimpl(with(SlotDescriptor), flags(BASETYPE, HAS_DICT))]
|
||||
impl PyStaticMethod {
|
||||
#[pyslot]
|
||||
fn tp_new(
|
||||
|
||||
+47
-15
@@ -6,13 +6,14 @@ use super::objclassmethod::PyClassMethod;
|
||||
use super::objdict::PyDictRef;
|
||||
use super::objlist::PyList;
|
||||
use super::objmappingproxy::PyMappingProxy;
|
||||
use super::objobject;
|
||||
use super::objstaticmethod::PyStaticMethod;
|
||||
use super::objstr::PyStringRef;
|
||||
use super::objtuple::PyTuple;
|
||||
use super::objweakref::PyWeak;
|
||||
use crate::function::{KwArgs, OptionalArg, PyFuncArgs};
|
||||
use crate::pyobject::{
|
||||
BorrowValue, IdProtocol, PyAttributes, PyClassImpl, PyContext, PyIterable, PyLease, PyObject,
|
||||
BorrowValue, IdProtocol, PyAttributes, PyClassImpl, PyContext, PyIterable, PyLease,
|
||||
PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
|
||||
};
|
||||
use crate::slots::{PyClassSlots, PyTpFlags};
|
||||
@@ -311,16 +312,41 @@ impl PyClassRef {
|
||||
}
|
||||
}
|
||||
|
||||
if !attributes.contains_key("__dict__") {
|
||||
attributes.insert(
|
||||
"__dict__".to_owned(),
|
||||
vm.ctx.new_getset(
|
||||
"__dict__",
|
||||
objobject::object_get_dict,
|
||||
objobject::object_set_dict,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
let slots = PyClassSlots {
|
||||
// TODO: how do we know if it should have a dict?
|
||||
flags: base.slots.read().flags | PyTpFlags::HAS_DICT,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// TODO: is this correct behavior?
|
||||
let cls_dict = if metatype.is(&vm.ctx.types.type_type) {
|
||||
None
|
||||
} else {
|
||||
Some(vm.ctx.new_dict())
|
||||
};
|
||||
|
||||
let typ = new(
|
||||
metatype,
|
||||
name.borrow_value(),
|
||||
base.clone(),
|
||||
base,
|
||||
bases,
|
||||
attributes,
|
||||
slots,
|
||||
cls_dict,
|
||||
)
|
||||
.map_err(|e| vm.new_type_error(e))?;
|
||||
|
||||
typ.slots.write().flags = base.slots.read().flags;
|
||||
vm.ctx.add_tp_new_wrapper(&typ);
|
||||
|
||||
for (name, obj) in typ.attributes.read().clone().iter() {
|
||||
@@ -582,9 +608,11 @@ fn linearise_mro(mut bases: Vec<Vec<PyClassRef>>) -> Result<Vec<PyClassRef>, Str
|
||||
pub fn new(
|
||||
typ: PyClassRef,
|
||||
name: &str,
|
||||
_base: PyClassRef,
|
||||
base: PyClassRef,
|
||||
bases: Vec<PyClassRef>,
|
||||
dict: HashMap<String, PyObjectRef>,
|
||||
attrs: HashMap<String, PyObjectRef>,
|
||||
mut slots: PyClassSlots,
|
||||
dict: Option<PyDictRef>,
|
||||
) -> Result<PyClassRef, String> {
|
||||
// Check for duplicates in bases.
|
||||
let mut unique_bases = HashSet::new();
|
||||
@@ -599,21 +627,21 @@ pub fn new(
|
||||
.map(|x| x.iter_mro().cloned().collect())
|
||||
.collect();
|
||||
let mro = linearise_mro(mros)?;
|
||||
let new_type = PyObject {
|
||||
payload: PyClass {
|
||||
if base.slots.read().flags.has_feature(PyTpFlags::HAS_DICT) {
|
||||
slots.flags |= PyTpFlags::HAS_DICT
|
||||
}
|
||||
let new_type = PyRef::new_ref(
|
||||
PyClass {
|
||||
name: String::from(name),
|
||||
bases,
|
||||
mro,
|
||||
subclasses: PyRwLock::default(),
|
||||
attributes: PyRwLock::new(dict),
|
||||
slots: PyRwLock::default(),
|
||||
attributes: PyRwLock::new(attrs),
|
||||
slots: PyRwLock::new(slots),
|
||||
},
|
||||
dict: None,
|
||||
typ: PyRwLock::new(typ.into_typed_pyobj()),
|
||||
}
|
||||
.into_ref();
|
||||
|
||||
let new_type: PyClassRef = new_type.downcast().unwrap();
|
||||
typ,
|
||||
dict,
|
||||
);
|
||||
|
||||
for base in &new_type.bases {
|
||||
base.subclasses
|
||||
@@ -718,6 +746,8 @@ mod tests {
|
||||
object.clone(),
|
||||
vec![object.clone()],
|
||||
HashMap::new(),
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let b = new(
|
||||
@@ -726,6 +756,8 @@ mod tests {
|
||||
object.clone(),
|
||||
vec![object.clone()],
|
||||
HashMap::new(),
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
+21
-9
@@ -1334,8 +1334,6 @@ cfg_if::cfg_if! {
|
||||
}
|
||||
|
||||
pub trait PyValue: fmt::Debug + PyThreadingConstraint + Sized + 'static {
|
||||
const HAVE_DICT: bool = false;
|
||||
|
||||
fn class(vm: &VirtualMachine) -> PyClassRef;
|
||||
|
||||
fn into_simple_object(self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
@@ -1352,18 +1350,13 @@ pub trait PyValue: fmt::Debug + PyThreadingConstraint + Sized + 'static {
|
||||
}
|
||||
|
||||
fn into_ref(self, vm: &VirtualMachine) -> PyRef<Self> {
|
||||
PyRef::new_ref(self, Self::class(vm), None)
|
||||
pyvalue_into_ref(self, Self::class(vm), vm)
|
||||
}
|
||||
|
||||
fn into_ref_with_type(self, vm: &VirtualMachine, cls: PyClassRef) -> PyResult<PyRef<Self>> {
|
||||
let class = Self::class(vm);
|
||||
if objtype::issubclass(&cls, &class) {
|
||||
let dict = if !Self::HAVE_DICT && cls.is(&class) {
|
||||
None
|
||||
} else {
|
||||
Some(vm.ctx.new_dict())
|
||||
};
|
||||
PyRef::from_obj(self.into_object(vm, cls, dict), vm)
|
||||
Ok(pyvalue_into_ref(self, cls, vm))
|
||||
} else {
|
||||
let subtype = vm.to_str(&cls.obj)?;
|
||||
let basetype = vm.to_str(&class.obj)?;
|
||||
@@ -1372,6 +1365,15 @@ pub trait PyValue: fmt::Debug + PyThreadingConstraint + Sized + 'static {
|
||||
}
|
||||
}
|
||||
|
||||
fn pyvalue_into_ref<T: PyValue>(value: T, cls: PyClassRef, vm: &VirtualMachine) -> PyRef<T> {
|
||||
let dict = if cls.slots.read().flags.has_feature(PyTpFlags::HAS_DICT) {
|
||||
Some(vm.ctx.new_dict())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
PyRef::new_ref(value, cls, dict)
|
||||
}
|
||||
|
||||
pub trait BorrowValue<'a>: PyValue {
|
||||
type Borrowed: 'a + Deref;
|
||||
fn borrow_value(&'a self) -> Self::Borrowed;
|
||||
@@ -1457,6 +1459,16 @@ pub trait PyClassImpl: PyClassDef {
|
||||
fn impl_extend_class(ctx: &PyContext, class: &PyClassRef);
|
||||
|
||||
fn extend_class(ctx: &PyContext, class: &PyClassRef) {
|
||||
if Self::TP_FLAGS.has_feature(PyTpFlags::HAS_DICT) {
|
||||
class.set_str_attr(
|
||||
"__dict__",
|
||||
ctx.new_getset(
|
||||
"__dict__",
|
||||
objobject::object_get_dict,
|
||||
objobject::object_set_dict,
|
||||
),
|
||||
);
|
||||
}
|
||||
Self::impl_extend_class(ctx, class);
|
||||
class.slots.write().flags = Self::TP_FLAGS;
|
||||
ctx.add_tp_new_wrapper(&class);
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::VirtualMachine;
|
||||
bitflags! {
|
||||
pub struct PyTpFlags: u64 {
|
||||
const BASETYPE = 1 << 10;
|
||||
const HAS_DICT = 1 << 40;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ use rustpython_parser::{ast, mode::Mode, parser};
|
||||
use crate::obj::objlist::PyListRef;
|
||||
use crate::obj::objtype::PyClassRef;
|
||||
use crate::pyobject::{PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::slots::PyTpFlags;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -644,6 +645,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let ctx = &vm.ctx;
|
||||
|
||||
let ast_base = py_class!(ctx, "AST", ctx.object(), {});
|
||||
ast_base.slots.write().flags |= PyTpFlags::HAS_DICT;
|
||||
py_module!(vm, MODULE_NAME, {
|
||||
// TODO: There's got to be a better way!
|
||||
"alias" => py_class!(ctx, "alias", ast_base.clone(), {}),
|
||||
|
||||
@@ -264,6 +264,8 @@ pub fn create_type(name: &str, type_type: &PyClassRef, base: &PyClassRef) -> PyC
|
||||
base.clone(),
|
||||
vec![base.clone()],
|
||||
dict,
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.expect("Failed to create a new type in internal code.")
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user