Make HAVE_DICT a type flag

This commit is contained in:
Noah committed 2020-08-12 16:04:13 -05:00
1 parent 1385c06e25
commit cc4ae0831c
13 files changed
+92 -65

No files matched your search

+2 -4
View File
@@ -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.
+1 -2
View File
@@ -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> {
+1 -3
View File
@@ -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(
+2 -2
View File
@@ -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> {
+1 -3
View File
@@ -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> {
+1 -2
View File
@@ -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
View File
@@ -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,
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+1
View File
@@ -5,6 +5,7 @@ use crate::VirtualMachine;
bitflags! {
pub struct PyTpFlags: u64 {
const BASETYPE = 1 << 10;
const HAS_DICT = 1 << 40;
}
}
+2
View File
@@ -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(), {}),
+2
View File
@@ -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.")
}