From 370b2b3f996d3949138dc97e67bf5cd0a08f0e94 Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Sat, 14 May 2022 22:05:00 +0900 Subject: [PATCH 1/9] static object --- common/src/refcount.rs | 22 +++++++++++++-- vm/src/intern.rs | 63 ++++++++++++++++++++++++++++++------------ vm/src/object/core.rs | 10 +++++++ vm/src/vm/context.rs | 6 +++- 4 files changed, 80 insertions(+), 21 deletions(-) diff --git a/common/src/refcount.rs b/common/src/refcount.rs index 6db81e5ab0..cbac8424dc 100644 --- a/common/src/refcount.rs +++ b/common/src/refcount.rs @@ -5,7 +5,7 @@ use crate::atomic::{Ordering::*, PyAtomic, Radium}; /// /// Going above this limit will abort your program (although not /// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references. -const MAX_REFCOUNT: usize = (isize::MAX) as usize; +const MAX_REFCOUNT: usize = isize::MAX as usize; pub struct RefCount { strong: PyAtomic, @@ -18,6 +18,8 @@ impl Default for RefCount { } impl RefCount { + const MASK: usize = MAX_REFCOUNT; + pub fn new() -> Self { RefCount { strong: Radium::new(1), @@ -33,7 +35,7 @@ impl RefCount { pub fn inc(&self) { let old_size = self.strong.fetch_add(1, Relaxed); - if old_size > MAX_REFCOUNT { + if old_size & Self::MASK == Self::MASK { std::process::abort(); } } @@ -58,3 +60,19 @@ impl RefCount { true } } + +impl RefCount { + // move these functions out and give separated type once type range is stabilized + + pub fn leak(&self) { + debug_assert!(!self.is_leaked()); + const BIT_MARKER: usize = (std::isize::MAX as usize) + 1; + debug_assert_eq!(BIT_MARKER.count_ones(), 1); + debug_assert_eq!(BIT_MARKER.leading_zeros(), 0); + self.strong.fetch_add(BIT_MARKER, Relaxed); + } + + pub fn is_leaked(&self) -> bool { + (self.strong.load(Acquire) as isize) < 0 + } +} diff --git a/vm/src/intern.rs b/vm/src/intern.rs index c07828a82d..74c192cf6e 100644 --- a/vm/src/intern.rs +++ b/vm/src/intern.rs @@ -2,7 +2,7 @@ use crate::{ builtins::{PyStr, PyTypeRef}, common::lock::PyRwLock, convert::ToPyObject, - Py, PyExact, PyObject, PyObjectRef, PyRef, PyRefExact, + AsObject, Py, PyExact, PyObject, PyObjectRef, PyRef, PyRefExact, }; use std::{ borrow::{Borrow, ToOwned}, @@ -43,14 +43,17 @@ impl StringPool { let inserted = zelf.inner.write().insert(cache.clone()); if inserted { let interned = unsafe { PyStrInterned::borrow_cache(&cache) }; - // unsafe { interned.as_object().mark_intern() }; + unsafe { interned.as_object().mark_intern() }; interned } else { - zelf.inner - .read() - .get(cache.as_str()) - .map(|cached| unsafe { PyStrInterned::borrow_cache(cached) }) - .expect("") + unsafe { + PyStrInterned::borrow_cache( + zelf.inner + .read() + .get(cache.as_ref()) + .expect("inserted is false"), + ) + } } } let str_ref = s.into_pyref_exact(typ); @@ -152,18 +155,20 @@ impl Borrow for PyStrInterned { } } -impl Deref for PyStrInterned { - type Target = Py; +// NOTE: std::hash::Hash of Self and Self::Borrowed *must* be the same +// This is ok only because PyObject doesn't implement Hash +impl std::hash::Hash for PyStrInterned { #[inline(always)] - fn deref(&self) -> &Self::Target { - &self.inner + fn hash(&self, state: &mut H) { + self.get_id().hash(state) } } -impl std::hash::Hash for PyStrInterned { +impl Deref for PyStrInterned { + type Target = Py; #[inline(always)] - fn hash(&self, state: &mut H) { - std::hash::Hash::hash(&(self as *const _), state) + fn deref(&self) -> &Self::Target { + &self.inner } } @@ -177,7 +182,7 @@ impl PartialEq for PyStrInterned { impl Eq for PyStrInterned {} impl AsRef for PyStrInterned { - #[inline] + #[inline(always)] fn as_ref(&self) -> &str { self.as_str() } @@ -216,8 +221,12 @@ mod sealed { } /// A sealed marker trait for `DictKey` types that always become an exact instance of `str` -pub trait Internable: sealed::SealedInternable + ToPyObject + AsRef { - type Interned: ?Sized + MaybeInterned; +pub trait Internable +where + Self: sealed::SealedInternable + ToPyObject + AsRef, + Self::Interned: MaybeInterned, +{ + type Interned: ?Sized; fn into_pyref_exact(self, str_type: PyTypeRef) -> PyRefExact; } @@ -269,6 +278,24 @@ impl MaybeInterned for PyExact { impl MaybeInterned for Py { #[inline(always)] fn as_interned(&self) -> Option<&'static PyStrInterned> { - None + if self.as_object().is_interned() { + Some(unsafe { std::mem::transmute(self) }) + } else { + None + } + } +} + +impl PyObject { + #[inline] + pub fn as_interned_str(&self, vm: &crate::VirtualMachine) -> Option<&'static PyStrInterned> { + let s: Option<&Py> = self.downcast_ref(); + if self.is_interned() { + s.unwrap().as_interned() + } else if let Some(s) = s { + vm.ctx.interned_str(s.as_str()) + } else { + None + } } } diff --git a/vm/src/object/core.rs b/vm/src/object/core.rs index 19c7aa47ec..378aa1aa6c 100644 --- a/vm/src/object/core.rs +++ b/vm/src/object/core.rs @@ -783,6 +783,16 @@ impl PyObject { // call drop only when there are no references in scope - stacked borrows stuff drop_dealloc(ptr.as_ptr()) } + + /// # Safety + /// This call will make the object live forever. + pub(crate) unsafe fn mark_intern(&self) { + self.0.ref_count.leak(); + } + + pub(crate) fn is_interned(&self) -> bool { + self.0.ref_count.is_leaked() + } } impl Borrow for PyObjectRef { diff --git a/vm/src/vm/context.rs b/vm/src/vm/context.rs index 1e362c3c5e..747a8fa571 100644 --- a/vm/src/vm/context.rs +++ b/vm/src/vm/context.rs @@ -13,7 +13,7 @@ use crate::{ class::{PyClassImpl, StaticType}, exceptions, function::IntoPyNativeFunc, - intern::{Internable, PyStrInterned, StringPool}, + intern::{Internable, MaybeInterned, PyStrInterned, StringPool}, object::{PyObjectPayload, PyObjectRef, PyPayload, PyRef}, types::{PyTypeFlags, PyTypeSlots, TypeZoo}, }; @@ -119,6 +119,10 @@ impl Context { unsafe { self.string_pool.intern(s, self.types.str_type.clone()) } } + pub fn interned_str(&self, s: &S) -> Option<&'static PyStrInterned> { + self.string_pool.interned(s) + } + #[inline(always)] pub fn none(&self) -> PyObjectRef { self.none.clone().into() From bbc31364bbfcf2d5ca525a622f47d908d1e8790b Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Wed, 18 May 2022 11:40:09 +0900 Subject: [PATCH 2/9] PyInterned --- stdlib/src/array.rs | 2 +- vm/src/builtins/bool.rs | 1 - vm/src/builtins/code.rs | 2 +- vm/src/builtins/str.rs | 2 +- vm/src/intern.rs | 84 +++++++++++++++++++++++++---------------- vm/src/stdlib/sys.rs | 4 +- vm/src/vm/context.rs | 5 +-- 7 files changed, 58 insertions(+), 42 deletions(-) diff --git a/stdlib/src/array.rs b/stdlib/src/array.rs index 6ceef4f205..937dfb2b25 100644 --- a/stdlib/src/array.rs +++ b/stdlib/src/array.rs @@ -683,7 +683,7 @@ mod array { fn typecode(&self, vm: &VirtualMachine) -> PyStrRef { vm.ctx .intern_str(self.read().typecode().to_string()) - .to_str() + .to_owned() } #[pyproperty] diff --git a/vm/src/builtins/bool.rs b/vm/src/builtins/bool.rs index fab3e9cfe9..38b20d31b0 100644 --- a/vm/src/builtins/bool.rs +++ b/vm/src/builtins/bool.rs @@ -117,7 +117,6 @@ impl PyBool { vm.ctx.false_str } .to_owned() - .into_pyref() } #[pymethod(magic)] diff --git a/vm/src/builtins/code.rs b/vm/src/builtins/code.rs index c0f216f13e..d9205982e7 100644 --- a/vm/src/builtins/code.rs +++ b/vm/src/builtins/code.rs @@ -104,7 +104,7 @@ impl ConstantBag for PyObjBag<'_> { } fn make_name(&self, name: &str) -> PyStrRef { - self.0.intern_str(name).to_str() + self.0.intern_str(name).to_owned() } } diff --git a/vm/src/builtins/str.rs b/vm/src/builtins/str.rs index 40f610c45d..151a1f1d32 100644 --- a/vm/src/builtins/str.rs +++ b/vm/src/builtins/str.rs @@ -230,7 +230,7 @@ impl IntoPyStrRef for &str { impl IntoPyStrRef for &'static crate::intern::PyStrInterned { #[inline] fn into_pystr_ref(self, _vm: &VirtualMachine) -> PyRef { - self.to_str() + self.to_owned() } } diff --git a/vm/src/intern.rs b/vm/src/intern.rs index 74c192cf6e..817871a194 100644 --- a/vm/src/intern.rs +++ b/vm/src/intern.rs @@ -2,7 +2,7 @@ use crate::{ builtins::{PyStr, PyTypeRef}, common::lock::PyRwLock, convert::ToPyObject, - AsObject, Py, PyExact, PyObject, PyObjectRef, PyRef, PyRefExact, + AsObject, Py, PyExact, PyObject, PyObjectRef, PyPayload, PyRef, PyRefExact, VirtualMachine, }; use std::{ borrow::{Borrow, ToOwned}, @@ -113,42 +113,36 @@ impl CachedPyStrRef { } } -/// The unique reference of interned PyStr -/// Always intended to be used as a static reference -pub struct PyStrInterned { - inner: Py, +pub struct PyInterned +where + T: PyPayload, +{ + inner: Py, } -impl PyStrInterned { - /// # Safety - /// the given cache must be alive while returned reference is alive +impl PyInterned { #[inline] - unsafe fn borrow_cache(cache: &CachedPyStrRef) -> &'static Self { - std::mem::transmute_copy(cache) + pub fn leak(cache: PyRef) -> &'static Self { + unsafe { std::mem::transmute(cache) } } #[inline] - fn as_ptr(&self) -> *const Py { + fn as_ptr(&self) -> *const Py { self as *const _ as *const _ } #[inline] - pub fn to_owned(&'static self) -> PyRefExact { - unsafe { (*(&self as *const _ as *const PyRefExact)).clone() } - } - - #[inline] - pub fn to_str(&'static self) -> PyRef { - self.to_owned().into_pyref() + pub fn to_owned(&'static self) -> PyRef { + unsafe { (*(&self as *const _ as *const PyRef)).clone() } } #[inline] pub fn to_object(&'static self) -> PyObjectRef { - self.to_str().into() + self.to_owned().into() } } -impl Borrow for PyStrInterned { +impl Borrow for PyInterned { #[inline(always)] fn borrow(&self) -> &PyObject { self.inner.borrow() @@ -157,41 +151,58 @@ impl Borrow for PyStrInterned { // NOTE: std::hash::Hash of Self and Self::Borrowed *must* be the same // This is ok only because PyObject doesn't implement Hash -impl std::hash::Hash for PyStrInterned { +impl std::hash::Hash for PyInterned { #[inline(always)] fn hash(&self, state: &mut H) { self.get_id().hash(state) } } -impl Deref for PyStrInterned { - type Target = Py; +impl Deref for PyInterned { + type Target = Py; #[inline(always)] fn deref(&self) -> &Self::Target { &self.inner } } -impl PartialEq for PyStrInterned { +impl PartialEq for PyInterned { #[inline(always)] fn eq(&self, other: &Self) -> bool { std::ptr::eq(self, other) } } -impl Eq for PyStrInterned {} +impl Eq for PyInterned {} -impl AsRef for PyStrInterned { - #[inline(always)] - fn as_ref(&self) -> &str { - self.as_str() +impl std::fmt::Debug for PyInterned { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Debug::fmt(&**self, f)?; + write!(f, "@{:p}", self.as_ptr()) } } -impl std::fmt::Debug for PyStrInterned { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Debug::fmt(self.as_str(), f)?; - write!(f, "@{:p}", self.as_ptr()) +impl ToPyObject for &'static PyInterned { + fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef { + self.to_owned().into() + } +} + +/// The unique reference of interned PyStr +/// Always intended to be used as a static reference +pub type PyStrInterned = PyInterned; + +impl PyStrInterned { + /// # Safety + /// the given cache must be alive while returned reference is alive + #[inline] + unsafe fn borrow_cache(cache: &CachedPyStrRef) -> &'static Self { + std::mem::transmute_copy(cache) + } + + #[inline] + pub fn to_exact(&'static self) -> PyRefExact { + unsafe { PyRefExact::new_unchecked(self.to_owned()) } } } @@ -201,6 +212,13 @@ impl std::fmt::Display for PyStrInterned { } } +impl AsRef for PyStrInterned { + #[inline(always)] + fn as_ref(&self) -> &str { + self.as_str() + } +} + mod sealed { use crate::{ builtins::PyStr, diff --git a/vm/src/stdlib/sys.rs b/vm/src/stdlib/sys.rs index c94df5e689..d21229dfe2 100644 --- a/vm/src/stdlib/sys.rs +++ b/vm/src/stdlib/sys.rs @@ -132,7 +132,7 @@ mod sys { } else { "unknown" }) - .to_str() + .to_owned() } #[pyattr] @@ -513,7 +513,7 @@ mod sys { #[pyfunction] fn intern(s: PyRefExact, vm: &VirtualMachine) -> PyRefExact { - vm.ctx.intern_str(s).to_owned() + vm.ctx.intern_str(s).to_exact() } #[pyattr] diff --git a/vm/src/vm/context.rs b/vm/src/vm/context.rs index 747a8fa571..c4ec499a4e 100644 --- a/vm/src/vm/context.rs +++ b/vm/src/vm/context.rs @@ -80,15 +80,14 @@ impl Context { let new_str = unsafe { string_pool.intern("__new__", types.str_type.clone()) }; let slot_new_wrapper = create_object( - PyNativeFuncDef::new(PyType::__new__.into_func(), new_str.to_owned().into_pyref()) - .into_function(), + PyNativeFuncDef::new(PyType::__new__.into_func(), new_str.to_owned()).into_function(), &types.builtin_function_or_method_type, ) .into(); let true_str = unsafe { string_pool.intern("True", types.str_type.clone()) }; let false_str = unsafe { string_pool.intern("False", types.str_type.clone()) }; - let empty_str = unsafe { string_pool.intern("", types.str_type.clone()) }.to_str(); + let empty_str = unsafe { string_pool.intern("", types.str_type.clone()) }.to_owned(); let context = Context { true_value, From f8b1c65ede2a1c5d2180aa266dc9c8b9ced59bb5 Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Thu, 19 May 2022 07:32:21 +0900 Subject: [PATCH 3/9] PyStrInterned --- vm/src/builtins/mod.rs | 2 +- vm/src/builtins/str.rs | 27 ++++++++++++++++++++- vm/src/intern.rs | 55 ++++++++++++------------------------------ vm/src/stdlib/sys.rs | 4 +-- vm/src/vm/context.rs | 6 ++--- 5 files changed, 47 insertions(+), 47 deletions(-) diff --git a/vm/src/builtins/mod.rs b/vm/src/builtins/mod.rs index b3fd1a317c..1b3cbb7a0f 100644 --- a/vm/src/builtins/mod.rs +++ b/vm/src/builtins/mod.rs @@ -59,7 +59,7 @@ pub(crate) mod bool_; pub use bool_::PyBool; #[path = "str.rs"] pub(crate) mod pystr; -pub use pystr::{PyStr, PyStrRef}; +pub use pystr::{PyStr, PyStrInterned, PyStrRef}; #[path = "super.rs"] pub(crate) mod super_; pub use super_::PySuper; diff --git a/vm/src/builtins/str.rs b/vm/src/builtins/str.rs index 151a1f1d32..0137337c15 100644 --- a/vm/src/builtins/str.rs +++ b/vm/src/builtins/str.rs @@ -9,6 +9,7 @@ use crate::{ convert::{ToPyException, ToPyObject}, format::{FormatSpec, FormatString, FromTemplate}, function::{ArgIterable, FuncArgs, OptionalArg, OptionalOption, PyComparisonValue}, + intern::PyInterned, protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods}, sequence::SequenceOp, sliceable::{SequenceIndex, SliceableSequenceOp}, @@ -227,7 +228,7 @@ impl IntoPyStrRef for &str { } } -impl IntoPyStrRef for &'static crate::intern::PyStrInterned { +impl IntoPyStrRef for &'static PyStrInterned { #[inline] fn into_pystr_ref(self, _vm: &VirtualMachine) -> PyRef { self.to_owned() @@ -1741,3 +1742,27 @@ impl<'s> AnyStr<'s> for str { splited } } + +/// The unique reference of interned PyStr +/// Always intended to be used as a static reference +pub type PyStrInterned = PyInterned; + +impl PyStrInterned { + #[inline] + pub fn to_exact(&'static self) -> PyRefExact { + unsafe { PyRefExact::new_unchecked(self.to_owned()) } + } +} + +impl std::fmt::Display for PyStrInterned { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.as_str(), f) + } +} + +impl AsRef for PyStrInterned { + #[inline(always)] + fn as_ref(&self) -> &str { + self.as_str() + } +} diff --git a/vm/src/intern.rs b/vm/src/intern.rs index 817871a194..ddef87c8e4 100644 --- a/vm/src/intern.rs +++ b/vm/src/intern.rs @@ -1,5 +1,5 @@ use crate::{ - builtins::{PyStr, PyTypeRef}, + builtins::{PyStr, PyStrInterned, PyTypeRef}, common::lock::PyRwLock, convert::ToPyObject, AsObject, Py, PyExact, PyObject, PyObjectRef, PyPayload, PyRef, PyRefExact, VirtualMachine, @@ -42,17 +42,16 @@ impl StringPool { let cache = CachedPyStrRef { inner: s }; let inserted = zelf.inner.write().insert(cache.clone()); if inserted { - let interned = unsafe { PyStrInterned::borrow_cache(&cache) }; + let interned = unsafe { cache.as_interned_str() }; unsafe { interned.as_object().mark_intern() }; interned } else { unsafe { - PyStrInterned::borrow_cache( - zelf.inner - .read() - .get(cache.as_ref()) - .expect("inserted is false"), - ) + zelf.inner + .read() + .get(cache.as_ref()) + .expect("inserted is false") + .as_interned_str() } } } @@ -68,7 +67,7 @@ impl StringPool { self.inner .read() .get(s.as_ref()) - .map(|cached| unsafe { PyStrInterned::borrow_cache(cached) }) + .map(|cached| unsafe { cached.as_interned_str() }) } } @@ -107,6 +106,13 @@ impl AsRef for CachedPyStrRef { } impl CachedPyStrRef { + /// # Safety + /// the given cache must be alive while returned reference is alive + #[inline] + unsafe fn as_interned_str(&self) -> &'static PyStrInterned { + std::mem::transmute_copy(self) + } + #[inline] fn as_str(&self) -> &str { self.inner.as_str() @@ -188,37 +194,6 @@ impl ToPyObject for &'static PyInterned { } } -/// The unique reference of interned PyStr -/// Always intended to be used as a static reference -pub type PyStrInterned = PyInterned; - -impl PyStrInterned { - /// # Safety - /// the given cache must be alive while returned reference is alive - #[inline] - unsafe fn borrow_cache(cache: &CachedPyStrRef) -> &'static Self { - std::mem::transmute_copy(cache) - } - - #[inline] - pub fn to_exact(&'static self) -> PyRefExact { - unsafe { PyRefExact::new_unchecked(self.to_owned()) } - } -} - -impl std::fmt::Display for PyStrInterned { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(self.as_str(), f) - } -} - -impl AsRef for PyStrInterned { - #[inline(always)] - fn as_ref(&self) -> &str { - self.as_str() - } -} - mod sealed { use crate::{ builtins::PyStr, diff --git a/vm/src/stdlib/sys.rs b/vm/src/stdlib/sys.rs index d21229dfe2..b342d1a85e 100644 --- a/vm/src/stdlib/sys.rs +++ b/vm/src/stdlib/sys.rs @@ -512,8 +512,8 @@ mod sys { } #[pyfunction] - fn intern(s: PyRefExact, vm: &VirtualMachine) -> PyRefExact { - vm.ctx.intern_str(s).to_exact() + fn intern(s: PyRefExact, vm: &VirtualMachine) -> PyRef { + vm.ctx.intern_str(s).to_owned() } #[pyattr] diff --git a/vm/src/vm/context.rs b/vm/src/vm/context.rs index c4ec499a4e..708d621c36 100644 --- a/vm/src/vm/context.rs +++ b/vm/src/vm/context.rs @@ -7,13 +7,13 @@ use crate::{ object, pystr, type_::PyAttributes, PyBaseException, PyComplex, PyDict, PyDictRef, PyEllipsis, PyFloat, PyFrozenSet, PyInt, - PyIntRef, PyList, PyListRef, PyNone, PyNotImplemented, PyStr, PyTuple, PyTupleRef, PyType, - PyTypeRef, + PyIntRef, PyList, PyListRef, PyNone, PyNotImplemented, PyStr, PyStrInterned, PyTuple, + PyTupleRef, PyType, PyTypeRef, }, class::{PyClassImpl, StaticType}, exceptions, function::IntoPyNativeFunc, - intern::{Internable, MaybeInterned, PyStrInterned, StringPool}, + intern::{Internable, MaybeInterned, StringPool}, object::{PyObjectPayload, PyObjectRef, PyPayload, PyRef}, types::{PyTypeFlags, PyTypeSlots, TypeZoo}, }; From fb52694e41b061c347a54d2d026545badbac6df9 Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Thu, 12 May 2022 09:40:06 +0900 Subject: [PATCH 4/9] PyAttributes key is PyStrInterned --- ast/asdl_rs.py | 4 +- benches/execution.rs | 2 +- derive/src/pyclass.rs | 8 +- derive/src/pymodule.rs | 2 +- src/shell/helper.rs | 13 +- stdlib/src/math.rs | 18 +- stdlib/src/pyexpat.rs | 2 +- stdlib/src/select.rs | 8 +- vm/src/builtins/bool.rs | 13 +- vm/src/builtins/complex.rs | 3 +- vm/src/builtins/dict.rs | 15 +- vm/src/builtins/float.rs | 3 +- vm/src/builtins/function.rs | 5 +- vm/src/builtins/genericalias.rs | 26 +- vm/src/builtins/int.rs | 4 +- vm/src/builtins/mappingproxy.rs | 30 +- vm/src/builtins/object.rs | 19 +- vm/src/builtins/str.rs | 4 +- vm/src/builtins/super.rs | 34 +- vm/src/builtins/type.rs | 138 +++-- vm/src/builtins/union.rs | 20 +- vm/src/bytesinner.rs | 3 +- vm/src/cformat.rs | 10 +- vm/src/class.rs | 18 +- vm/src/dictdatatype.rs | 31 +- vm/src/exceptions.rs | 3 +- vm/src/format.rs | 6 +- vm/src/frame.rs | 51 +- vm/src/function/protocol.rs | 3 +- vm/src/macros.rs | 11 +- vm/src/object/core.rs | 2 +- vm/src/object/ext.rs | 4 +- vm/src/protocol/mapping.rs | 18 +- vm/src/protocol/object.rs | 61 +- vm/src/stdlib/ast/gen.rs | 964 ++++++++++++++++++-------------- vm/src/stdlib/builtins.rs | 44 +- vm/src/stdlib/io.rs | 2 +- vm/src/stdlib/itertools.rs | 13 +- vm/src/stdlib/operator.rs | 9 +- vm/src/stdlib/os.rs | 14 +- vm/src/stdlib/sre.rs | 2 +- vm/src/stdlib/thread.rs | 3 +- vm/src/types/slot.rs | 124 ++-- vm/src/types/structseq.rs | 7 +- vm/src/vm/context.rs | 193 ++++++- vm/src/vm/interpreter.rs | 4 +- vm/src/vm/method.rs | 9 +- vm/src/vm/mod.rs | 48 +- vm/src/vm/vm_object.rs | 28 +- vm/src/vm/vm_ops.rs | 336 +++++++---- 50 files changed, 1494 insertions(+), 898 deletions(-) diff --git a/ast/asdl_rs.py b/ast/asdl_rs.py index be809a8e15..e03a6deaea 100755 --- a/ast/asdl_rs.py +++ b/ast/asdl_rs.py @@ -389,9 +389,9 @@ def gen_classdef(self, name, fields, attrs, depth, base="AstNode"): self.emit(f"#[extend_class]", depth + 1) self.emit("fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) {", depth + 1) fields = ",".join(f"ctx.new_str(ascii!({json.dumps(f.name)})).into()" for f in fields) - self.emit(f'class.set_str_attr("_fields", ctx.new_list(vec![{fields}]));', depth + 2) + self.emit(f'class.set_attr(interned!(ctx, _fields), ctx.new_list(vec![{fields}]).into());', depth + 2) attrs = ",".join(f"ctx.new_str(ascii!({json.dumps(attr.name)})).into()" for attr in attrs) - self.emit(f'class.set_str_attr("_attributes", ctx.new_list(vec![{attrs}]));', depth + 2) + self.emit(f'class.set_attr(interned!(ctx, _attributes), ctx.new_list(vec![{attrs}]).into());', depth + 2) self.emit("}", depth + 1) self.emit("}", depth) diff --git a/benches/execution.rs b/benches/execution.rs index d286365b84..b95941c2b5 100644 --- a/benches/execution.rs +++ b/benches/execution.rs @@ -116,7 +116,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { .map(|entry| { let path = entry.unwrap().path(); ( - path.file_name().unwrap().to_str().unwrap().to_owned(), + path.file_name().unwrap().to_owned().unwrap().to_owned(), std::fs::read_to_string(path).unwrap(), ) }) diff --git a/derive/src/pyclass.rs b/derive/src/pyclass.rs index 6cd2958914..3cdf19a8a0 100644 --- a/derive/src/pyclass.rs +++ b/derive/src/pyclass.rs @@ -503,7 +503,8 @@ where #py_name, ctx.make_funcdef(#py_name, Self::#ident) #doc - #build_func + #build_func, + ctx, ); } }; @@ -611,7 +612,7 @@ where ident, py_name.clone(), quote! { - class.set_str_attr(#py_name, #value); + class.set_str_attr(#py_name, #value, ctx); }, ) } else { @@ -736,7 +737,8 @@ impl ToTokens for GetSetNursery { ::rustpython_vm::builtins::PyGetSet::new(#name.into(), class.clone()) .with_get(&Self::#getter) #setter #deleter, - ctx.types.getset_type.clone(), None) + ctx.types.getset_type.clone(), None), + ctx ); } }); diff --git a/derive/src/pymodule.rs b/derive/src/pymodule.rs index fee1c9c2a6..8142c4e504 100644 --- a/derive/src/pymodule.rs +++ b/derive/src/pymodule.rs @@ -433,7 +433,7 @@ impl ModuleItem for ClassItem { }; let class_new = quote_spanned!(ident.span() => let new_class = <#ident as ::rustpython_vm::class::PyClassImpl>::make_class(&vm.ctx); - new_class.set_str_attr("__module__", vm.new_pyobj(#module_name)); + new_class.set_attr(rustpython_vm::identifier!(vm, __module__), vm.new_pyobj(#module_name)); ); (class_name, class_new) }; diff --git a/src/shell/helper.rs b/src/shell/helper.rs index 156667c96e..b0ead912ae 100644 --- a/src/shell/helper.rs +++ b/src/shell/helper.rs @@ -2,7 +2,7 @@ use rustpython_vm::{ builtins::{PyDictRef, PyStrRef}, function::ArgIterable, - PyResult, TryFromObject, VirtualMachine, + identifier, PyResult, TryFromObject, VirtualMachine, }; pub struct ShellHelper<'vm> { @@ -81,14 +81,19 @@ impl<'vm> ShellHelper<'vm> { current = current.get_attr(attr.as_str(), self.vm).ok()?; } - let current_iter = str_iter_method(current, "__dir__").ok()?; + let current_iter = str_iter_method(current, identifier!(self.vm, __dir__)).ok()?; (last, current_iter, None) } else { // we need to get a variable based off of globals/builtins - let globals = str_iter_method(self.globals.clone().into(), "keys").ok()?; - let builtins = str_iter_method(self.vm.builtins.clone().into(), "__dir__").ok()?; + let globals = + str_iter_method(self.globals.clone().into(), identifier!(self.vm, keys)).ok()?; + let builtins = str_iter_method( + self.vm.builtins.clone().into(), + identifier!(self.vm, __dir__), + ) + .ok()?; (first, globals, Some(builtins)) }; Some((word_start, iter1.chain(iter2.into_iter().flatten()))) diff --git a/stdlib/src/math.rs b/stdlib/src/math.rs index 5816f1e259..e118ce77c7 100644 --- a/stdlib/src/math.rs +++ b/stdlib/src/math.rs @@ -3,9 +3,9 @@ pub(crate) use math::make_module; #[pymodule] mod math { use crate::vm::{ - builtins::{try_bigint_to_f64, try_f64_to_bigint, PyFloat, PyInt, PyIntRef}, + builtins::{try_bigint_to_f64, try_f64_to_bigint, PyFloat, PyInt, PyIntRef, PyStrInterned}, function::{ArgIntoFloat, ArgIterable, Either, OptionalArg, PosArgs}, - AsObject, PyObject, PyObjectRef, PyRef, PyResult, VirtualMachine, + identifier, AsObject, PyObject, PyObjectRef, PyRef, PyResult, VirtualMachine, }; use num_bigint::BigInt; use num_traits::{One, Signed, Zero}; @@ -430,12 +430,16 @@ mod math { } } - fn try_magic_method(func_name: &str, vm: &VirtualMachine, value: &PyObject) -> PyResult { + fn try_magic_method( + func_name: &'static PyStrInterned, + vm: &VirtualMachine, + value: &PyObject, + ) -> PyResult { let method = vm.get_method_or_type_error(value.to_owned(), func_name, || { format!( "type '{}' doesn't define '{}' method", value.class().name(), - func_name, + func_name.as_str(), ) })?; vm.invoke(&method, ()) @@ -443,12 +447,12 @@ mod math { #[pyfunction] fn trunc(x: PyObjectRef, vm: &VirtualMachine) -> PyResult { - try_magic_method("__trunc__", vm, &x) + try_magic_method(identifier!(vm, __trunc__), vm, &x) } #[pyfunction] fn ceil(x: PyObjectRef, vm: &VirtualMachine) -> PyResult { - let result_or_err = try_magic_method("__ceil__", vm, &x); + let result_or_err = try_magic_method(identifier!(vm, __ceil__), vm, &x); if result_or_err.is_err() { if let Ok(Some(v)) = x.try_to_f64(vm) { let v = try_f64_to_bigint(v.ceil(), vm)?; @@ -460,7 +464,7 @@ mod math { #[pyfunction] fn floor(x: PyObjectRef, vm: &VirtualMachine) -> PyResult { - let result_or_err = try_magic_method("__floor__", vm, &x); + let result_or_err = try_magic_method(identifier!(vm, __floor__), vm, &x); if result_or_err.is_err() { if let Ok(Some(v)) = x.try_to_f64(vm) { let v = try_f64_to_bigint(v.floor(), vm)?; diff --git a/stdlib/src/pyexpat.rs b/stdlib/src/pyexpat.rs index 8a9cb33b91..0098a55e71 100644 --- a/stdlib/src/pyexpat.rs +++ b/stdlib/src/pyexpat.rs @@ -25,7 +25,7 @@ macro_rules! create_property { move |this: &PyExpatLikeXmlParser, func: PyObjectRef| *this.$element.write() = func, ); - $attributes.insert($name.to_owned(), attr.into()); + $attributes.insert($ctx.intern_str($name), attr.into()); }; } diff --git a/stdlib/src/select.rs b/stdlib/src/select.rs index 0a75fd5b4b..ee3864d452 100644 --- a/stdlib/src/select.rs +++ b/stdlib/src/select.rs @@ -75,9 +75,11 @@ struct Selectable { impl TryFromObject for Selectable { fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { let fno = obj.try_to_value(vm).or_else(|_| { - let meth = vm.get_method_or_type_error(obj.clone(), "fileno", || { - "select arg must be an int or object with a fileno() method".to_owned() - })?; + let meth = vm.get_method_or_type_error( + obj.clone(), + vm.ctx.interned_str("fileno").unwrap(), + || "select arg must be an int or object with a fileno() method".to_owned(), + )?; vm.invoke(&meth, ())?.try_into_value(vm) })?; Ok(Selectable { obj, fno }) diff --git a/vm/src/builtins/bool.rs b/vm/src/builtins/bool.rs index 38b20d31b0..d28e7e1f48 100644 --- a/vm/src/builtins/bool.rs +++ b/vm/src/builtins/bool.rs @@ -1,7 +1,8 @@ use super::{PyInt, PyStrRef, PyTypeRef}; use crate::{ - class::PyClassImpl, convert::ToPyObject, function::OptionalArg, types::Constructor, AsObject, - Context, PyObject, PyObjectRef, PyPayload, PyResult, TryFromBorrowedObject, VirtualMachine, + class::PyClassImpl, convert::ToPyObject, function::OptionalArg, identifier, types::Constructor, + AsObject, Context, PyObject, PyObjectRef, PyPayload, PyResult, TryFromBorrowedObject, + VirtualMachine, }; use num_bigint::Sign; use num_traits::Zero; @@ -32,7 +33,7 @@ impl PyObjectRef { if self.is(&vm.ctx.false_value) { return Ok(false); } - let rs_bool = match vm.get_method(self.clone(), "__bool__") { + let rs_bool = match vm.get_method(self.clone(), identifier!(vm, __bool__)) { Some(method_or_err) => { // If descriptor returns Error, propagate it further let method = method_or_err?; @@ -46,7 +47,7 @@ impl PyObjectRef { get_value(&bool_obj) } - None => match vm.get_method(self, "__len__") { + None => match vm.get_method(self, identifier!(vm, __len__)) { Some(method_or_err) => { let method = method_or_err?; let bool_obj = vm.invoke(&method, ())?; @@ -112,9 +113,9 @@ impl PyBool { #[pymethod(magic)] fn repr(zelf: bool, vm: &VirtualMachine) -> PyStrRef { if zelf { - vm.ctx.true_str + vm.ctx.names.True } else { - vm.ctx.false_str + vm.ctx.names.False } .to_owned() } diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index f33d4856f7..a43cf89767 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -7,6 +7,7 @@ use crate::{ PyArithmeticValue::{self, *}, PyComparisonValue, }, + identifier, types::{Comparable, Constructor, Hashable, PyComparisonOp}, AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; @@ -48,7 +49,7 @@ impl PyObjectRef { if let Some(complex) = self.payload_if_exact::(vm) { return Ok(Some((complex.value, true))); } - if let Some(method) = vm.get_method(self.clone(), "__complex__") { + if let Some(method) = vm.get_method(self.clone(), identifier!(vm, __complex__)) { let result = vm.invoke(&method?, ())?; // TODO: returning strict subclasses of complex in __complex__ is deprecated return match result.payload::() { diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index 9c1f0e8ed3..1895af874f 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -83,7 +83,7 @@ impl PyDict { Ok(dict_other) => return Self::merge_dict(dict, dict_other, vm), Err(other) => other, }; - if let Some(keys) = vm.get_method(other.clone(), "keys") { + if let Some(keys) = vm.get_method(other.clone(), vm.ctx.intern_str("keys")) { let keys = vm.invoke(&keys?, ())?.get_iter(vm)?; while let PyIterReturn::Return(key) = keys.next(vm)? { let val = other.get_item(&*key, vm)?; @@ -196,13 +196,13 @@ impl PyDict { } pub fn from_attributes(attrs: PyAttributes, vm: &VirtualMachine) -> PyResult { - let dict = DictContentType::default(); + let entries = DictContentType::default(); for (key, value) in attrs { - dict.insert(vm, key.as_str(), value)?; + entries.insert(vm, key, value)?; } - Ok(PyDict { entries: dict }) + Ok(Self { entries }) } pub fn contains_key(&self, key: &K, vm: &VirtualMachine) -> bool { @@ -527,7 +527,7 @@ impl Py { key: &K, vm: &VirtualMachine, ) -> PyResult> { - vm.get_method(self.to_owned().into(), "__missing__") + vm.get_method(self.to_owned().into(), identifier!(vm, __missing__)) .map(|methods| vm.invoke(&methods?, (key.to_pyobject(vm),))) .transpose() } @@ -548,11 +548,12 @@ impl Py { } /// Take a python dictionary and convert it to attributes. - pub fn to_attributes(&self) -> PyAttributes { + pub fn to_attributes(&self, vm: &VirtualMachine) -> PyAttributes { let mut attrs = PyAttributes::default(); for (key, value) in self { + // TODO: use PyRefExact for interning let key: PyStrRef = key.downcast().expect("dict has non-string keys"); - attrs.insert(key.as_str().to_owned(), value); + attrs.insert(vm.ctx.intern_str(key.as_str()), value); } attrs } diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index 5040ab3582..2679cf3d41 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -9,6 +9,7 @@ use crate::{ PyArithmeticValue::{self, *}, PyComparisonValue, }, + identifier, types::{Comparable, Constructor, Hashable, PyComparisonOp}, AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject, TryFromObject, VirtualMachine, @@ -59,7 +60,7 @@ impl PyObject { if let Some(float) = self.payload_if_exact::(vm) { return Ok(Some(float.value)); } - if let Some(method) = vm.get_method(self.to_owned(), "__float__") { + if let Some(method) = vm.get_method(self.to_owned(), identifier!(vm, __float__)) { let result = vm.invoke(&method?, ())?; // TODO: returning strict subclasses of float in __float__ is deprecated return match result.payload::() { diff --git a/vm/src/builtins/function.rs b/vm/src/builtins/function.rs index bf1451c920..de0ae96f93 100644 --- a/vm/src/builtins/function.rs +++ b/vm/src/builtins/function.rs @@ -458,7 +458,10 @@ impl Comparable for PyBoundMethod { impl GetAttr for PyBoundMethod { fn getattro(zelf: &Py, name: PyStrRef, vm: &VirtualMachine) -> PyResult { - let class_attr = zelf.get_class_attr(name.as_str()); + let class_attr = vm + .ctx + .interned_str(&*name) + .and_then(|attr_name| zelf.get_class_attr(attr_name)); if let Some(obj) = class_attr { return vm.call_if_get_descriptor(obj, zelf.to_owned().into()); } diff --git a/vm/src/builtins/genericalias.rs b/vm/src/builtins/genericalias.rs index 7ef891b8ae..0a675445ac 100644 --- a/vm/src/builtins/genericalias.rs +++ b/vm/src/builtins/genericalias.rs @@ -82,16 +82,20 @@ impl PyGenericAlias { return Ok("...".to_string()); } - if vm.get_attribute_opt(obj.clone(), "__origin__")?.is_some() - && vm.get_attribute_opt(obj.clone(), "__args__")?.is_some() + if vm + .get_attribute_opt(obj.clone(), identifier!(vm, __origin__))? + .is_some() + && vm + .get_attribute_opt(obj.clone(), identifier!(vm, __args__))? + .is_some() { return Ok(obj.repr(vm)?.as_str().to_string()); } match ( - vm.get_attribute_opt(obj.clone(), "__qualname__")? + vm.get_attribute_opt(obj.clone(), identifier!(vm, __qualname__))? .and_then(|o| o.downcast_ref::().map(|n| n.as_str().to_string())), - vm.get_attribute_opt(obj.clone(), "__module__")? + vm.get_attribute_opt(obj.clone(), identifier!(vm, __module__))? .and_then(|o| o.downcast_ref::().map(|m| m.as_str().to_string())), ) { (None, _) | (_, None) => Ok(obj.repr(vm)?.as_str().to_string()), @@ -186,11 +190,11 @@ impl PyGenericAlias { } } -fn is_typevar(obj: &PyObjectRef) -> bool { +fn is_typevar(obj: &PyObjectRef, vm: &VirtualMachine) -> bool { let class = obj.class(); class.slot_name() == "TypeVar" && class - .get_attr("__module__") + .get_attr(identifier!(vm, __module__)) .and_then(|o| o.downcast_ref::().map(|s| s.as_str() == "typing")) .unwrap_or(false) } @@ -198,13 +202,13 @@ fn is_typevar(obj: &PyObjectRef) -> bool { fn make_parameters(args: &PyTupleRef, vm: &VirtualMachine) -> PyTupleRef { let mut parameters: Vec = Vec::with_capacity(args.len()); for arg in args { - if is_typevar(arg) { + if is_typevar(arg, vm) { if !parameters.iter().any(|param| param.is(arg)) { parameters.push(arg.clone()); } } else if let Ok(subparams) = arg .clone() - .get_attr("__parameters__", vm) + .get_attr(identifier!(vm, __parameters__), vm) .and_then(|obj| PyTupleRef::try_from_object(vm, obj)) { for subparam in &subparams { @@ -231,7 +235,7 @@ fn subs_tvars( vm: &VirtualMachine, ) -> PyResult { obj.clone() - .get_attr("__parameters__", vm) + .get_attr(identifier!(vm, __parameters__), vm) .ok() .and_then(|sub_params| { PyTupleRef::try_from_object(vm, sub_params) @@ -290,7 +294,7 @@ pub fn subs_parameters PyResult>( let new_args = args .iter() .map(|arg| { - if is_typevar(arg) { + if is_typevar(arg, vm) { let idx = tuple_index(¶meters, arg).unwrap(); Ok(arg_items[idx].clone()) } else { @@ -322,7 +326,7 @@ impl Callable for PyGenericAlias { type Args = FuncArgs; fn call(zelf: &crate::Py, args: FuncArgs, vm: &VirtualMachine) -> PyResult { PyType::call(&zelf.origin, args, vm).map(|obj| { - if let Err(exc) = obj.set_attr("__orig_class__", zelf.to_owned(), vm) { + if let Err(exc) = obj.set_attr(identifier!(vm, __orig_class__), zelf.to_owned(), vm) { if !exc.fast_isinstance(&vm.ctx.exceptions.attribute_error) && !exc.fast_isinstance(&vm.ctx.exceptions.type_error) { diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 6710f238ad..0d1004f626 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -952,7 +952,7 @@ pub(crate) fn try_int(obj: &PyObject, vm: &VirtualMachine) -> PyResult { } // call __int__, then __index__, then __trunc__ (converting the __trunc__ result via __index__ if needed) // TODO: using __int__ is deprecated and removed in Python 3.10 - if let Some(method) = vm.get_method(obj.to_owned(), "__int__") { + if let Some(method) = vm.get_method(obj.to_owned(), identifier!(vm, __int__)) { let result = vm.invoke(&method?, ())?; return match result.payload::() { Some(int_obj) => Ok(int_obj.as_bigint().clone()), @@ -966,7 +966,7 @@ pub(crate) fn try_int(obj: &PyObject, vm: &VirtualMachine) -> PyResult { if let Some(r) = vm.to_index_opt(obj.to_owned()).transpose()? { return Ok(r.as_bigint().clone()); } - if let Some(method) = vm.get_method(obj.to_owned(), "__trunc__") { + if let Some(method) = vm.get_method(obj.to_owned(), identifier!(vm, __trunc__)) { let result = vm.invoke(&method?, ())?; return vm .to_index_opt(result.clone()) diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index 0e054571f0..a6b94b6cc1 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -1,14 +1,13 @@ use std::borrow::Cow; -use super::{PyDict, PyGenericAlias, PyList, PyStr, PyStrRef, PyTuple, PyTypeRef}; +use super::{PyDict, PyGenericAlias, PyList, PyTuple, PyTypeRef}; use crate::{ class::PyClassImpl, convert::ToPyObject, function::OptionalArg, protocol::{PyMapping, PyMappingMethods, PySequence, PySequenceMethods}, types::{AsMapping, AsSequence, Constructor, Iterable}, - AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, - VirtualMachine, + AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; #[pyclass(module = false, name = "mappingproxy")] @@ -63,10 +62,9 @@ impl Constructor for PyMappingProxy { impl PyMappingProxy { fn get_inner(&self, key: PyObjectRef, vm: &VirtualMachine) -> PyResult> { let opt = match &self.mapping { - MappingProxyInner::Class(class) => { - let key = PyStrRef::try_from_object(vm, key)?; - class.attributes.read().get(key.as_str()).cloned() - } + MappingProxyInner::Class(class) => key + .as_interned_str(vm) + .and_then(|key| class.attributes.read().get(key).cloned()), MappingProxyInner::Dict(obj) => obj.get_item(&*key, vm).ok(), }; Ok(opt) @@ -92,13 +90,9 @@ impl PyMappingProxy { fn _contains(&self, key: &PyObject, vm: &VirtualMachine) -> PyResult { match &self.mapping { - MappingProxyInner::Class(class) => { - // let key = PyStrRef::try_from_object(vm, key)?; - let key = key - .payload::() - .ok_or_else(|| vm.new_downcast_type_error(PyStr::class(vm), key))?; - Ok(class.attributes.read().contains_key(key.as_str())) - } + MappingProxyInner::Class(class) => Ok(key + .as_interned_str(vm) + .map_or(false, |key| class.attributes.read().contains_key(key))), MappingProxyInner::Dict(obj) => PySequence::from(obj.as_ref()).contains(key, vm), } } @@ -116,7 +110,7 @@ impl PyMappingProxy { PyDict::from_attributes(c.attributes.read().clone(), vm)?.to_pyobject(vm) } }; - vm.call_method(&obj, "items", ()) + vm.call_method(&obj, identifier!(vm, items).as_str(), ()) } #[pymethod] pub fn keys(&self, vm: &VirtualMachine) -> PyResult { @@ -126,7 +120,7 @@ impl PyMappingProxy { PyDict::from_attributes(c.attributes.read().clone(), vm)?.to_pyobject(vm) } }; - vm.call_method(&obj, "keys", ()) + vm.call_method(&obj, identifier!(vm, keys).as_str(), ()) } #[pymethod] pub fn values(&self, vm: &VirtualMachine) -> PyResult { @@ -136,12 +130,12 @@ impl PyMappingProxy { PyDict::from_attributes(c.attributes.read().clone(), vm)?.to_pyobject(vm) } }; - vm.call_method(&obj, "values", ()) + vm.call_method(&obj, identifier!(vm, values).as_str(), ()) } #[pymethod] pub fn copy(&self, vm: &VirtualMachine) -> PyResult { match &self.mapping { - MappingProxyInner::Dict(d) => vm.call_method(d, "copy", ()), + MappingProxyInner::Dict(d) => vm.call_method(d, identifier!(vm, copy).as_str(), ()), MappingProxyInner::Class(c) => { Ok(PyDict::from_attributes(c.attributes.read().clone(), vm)?.to_pyobject(vm)) } diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index 4d1173e1b4..ad4fd7e5fc 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -38,7 +38,7 @@ impl PyBaseObject { }; // Ensure that all abstract methods are implemented before instantiating instance. - if let Some(abs_methods) = cls.get_attr("__abstractmethods__") { + if let Some(abs_methods) = cls.get_attr(identifier!(vm, __abstractmethods__)) { if let Some(unimplemented_abstract_method_count) = abs_methods.length_opt(vm) { if unimplemented_abstract_method_count? > 0 { return Err( @@ -230,7 +230,11 @@ impl PyBaseObject { // Get instance attributes: if let Some(object_dict) = obj.dict() { - vm.call_method(dict.as_object(), "update", (object_dict,))?; + vm.call_method( + dict.as_object(), + identifier!(vm, update).as_str(), + (object_dict,), + )?; } let attributes: Vec<_> = dict.into_iter().map(|(k, _v)| k).collect(); @@ -305,10 +309,15 @@ impl PyBaseObject { #[pymethod(magic)] fn reduce_ex(obj: PyObjectRef, proto: usize, vm: &VirtualMachine) -> PyResult { - if let Some(reduce) = vm.get_attribute_opt(obj.clone(), "__reduce__")? { - let object_reduce = vm.ctx.types.object_type.get_attr("__reduce__").unwrap(); + if let Some(reduce) = vm.get_attribute_opt(obj.clone(), identifier!(vm, __reduce__))? { + let object_reduce = vm + .ctx + .types + .object_type + .get_attr(identifier!(vm, __reduce__)) + .unwrap(); let typ_obj: PyObjectRef = obj.class().clone().into(); - let class_reduce = typ_obj.get_attr("__reduce__", vm)?; + let class_reduce = typ_obj.get_attr(identifier!(vm, __reduce__), vm)?; if !class_reduce.is(&object_reduce) { return vm.invoke(&reduce, ()); } diff --git a/vm/src/builtins/str.rs b/vm/src/builtins/str.rs index 0137337c15..f35e6b2642 100644 --- a/vm/src/builtins/str.rs +++ b/vm/src/builtins/str.rs @@ -409,7 +409,7 @@ impl PyStr { Self::new_str_unchecked(bytes.into_bytes(), kind) } .to_pyobject(vm)) - } else if let Some(radd) = vm.get_method(other.clone(), "__radd__") { + } else if let Some(radd) = vm.get_method(other.clone(), identifier!(vm, __radd__)) { // hack to get around not distinguishing number add from seq concat vm.invoke(&radd?, (zelf,)) } else { @@ -1149,7 +1149,7 @@ impl PyStr { // https://docs.python.org/3/library/stdtypes.html#str.translate #[pymethod] fn translate(&self, table: PyObjectRef, vm: &VirtualMachine) -> PyResult { - vm.get_method_or_type_error(table.clone(), "__getitem__", || { + vm.get_method_or_type_error(table.clone(), identifier!(vm, __getitem__), || { format!("'{}' object is not subscriptable", table.class().name()) })?; diff --git a/vm/src/builtins/super.rs b/vm/src/builtins/super.rs index fb566f4777..3590353173 100644 --- a/vm/src/builtins/super.rs +++ b/vm/src/builtins/super.rs @@ -148,22 +148,24 @@ impl GetAttr for PySuper { return skip(zelf, name); } - // skip the classes in start_type.mro up to and including zelf.typ - let mro: Vec<_> = start_type - .iter_mro() - .skip_while(|cls| !cls.is(&zelf.typ)) - .skip(1) // skip su->type (if any) - .collect(); - for cls in mro { - if let Some(descr) = cls.get_direct_attr(name.as_str()) { - return vm - .call_get_descriptor_specific( - descr.clone(), - // Only pass 'obj' param if this is instance-mode super (See https://bugs.python.org/issue743267) - if obj.is(&start_type) { None } else { Some(obj) }, - Some(start_type.as_object().to_owned()), - ) - .unwrap_or(Ok(descr)); + if let Some(name) = vm.ctx.interned_str(&*name) { + // skip the classes in start_type.mro up to and including zelf.typ + let mro: Vec<_> = start_type + .iter_mro() + .skip_while(|cls| !cls.is(&zelf.typ)) + .skip(1) // skip su->type (if any) + .collect(); + for cls in mro { + if let Some(descr) = cls.get_direct_attr(name) { + return vm + .call_get_descriptor_specific( + descr.clone(), + // Only pass 'obj' param if this is instance-mode super (See https://bugs.python.org/issue743267) + if obj.is(&start_type) { None } else { Some(obj) }, + Some(start_type.as_object().to_owned()), + ) + .unwrap_or(Ok(descr)); + } } } skip(zelf, name) diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 3395a05e3e..777a9f5932 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -1,6 +1,6 @@ use super::{ mappingproxy::PyMappingProxy, object, union_, PyClassMethod, PyDictRef, PyList, PyStaticMethod, - PyStr, PyStrRef, PyTuple, PyTupleRef, PyWeak, + PyStr, PyStrInterned, PyStrRef, PyTuple, PyTupleRef, PyWeak, }; use crate::common::{ ascii, @@ -8,8 +8,10 @@ use crate::common::{ lock::{PyRwLock, PyRwLockReadGuard}, }; use crate::{ + builtins::PyBaseExceptionRef, class::{PyClassImpl, StaticType}, function::{FuncArgs, KwArgs, OptionalArg}, + identifier, types::{Callable, GetAttr, PyTypeFlags, PyTypeSlots, SetAttr}, AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; @@ -35,7 +37,7 @@ pub type PyTypeRef = PyRef; /// For attributes we do not use a dict, but an IndexMap, which is an Hash Table /// that maintains order and is compatible with the standard HashMap This is probably /// faster and only supports strings as keys. -pub type PyAttributes = IndexMap; +pub type PyAttributes = IndexMap<&'static PyStrInterned, PyObjectRef, ahash::RandomState>; impl fmt::Display for PyType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -116,7 +118,7 @@ impl PyType { ); for attr_name in new_type.attributes.read().keys() { - if attr_name.starts_with("__") && attr_name.ends_with("__") { + if attr_name.as_str().starts_with("__") && attr_name.as_str().ends_with("__") { new_type.update_slot(attr_name, true); } } @@ -155,34 +157,40 @@ impl PyType { } // This is used for class initialisation where the vm is not yet available. - pub fn set_str_attr>(&self, attr_name: &str, value: V) { - self._set_str_attr(attr_name, value.into()) + pub fn set_str_attr>( + &self, + attr_name: &str, + value: V, + ctx: impl AsRef, + ) { + let attr_name = ctx.as_ref().intern_str(attr_name); + self.set_attr(attr_name, value.into()) } - fn _set_str_attr(&self, attr_name: &str, value: PyObjectRef) { - self.attributes.write().insert(attr_name.to_owned(), value); + pub fn set_attr(&self, attr_name: &'static PyStrInterned, value: PyObjectRef) { + self.attributes.write().insert(attr_name, value); } /// This is the internal get_attr implementation for fast lookup on a class. - pub fn get_attr(&self, attr_name: &str) -> Option { + pub fn get_attr(&self, attr_name: &'static PyStrInterned) -> Option { flame_guard!(format!("class_get_attr({:?})", attr_name)); self.get_direct_attr(attr_name) .or_else(|| self.get_super_attr(attr_name)) } - pub fn get_direct_attr(&self, attr_name: &str) -> Option { + pub fn get_direct_attr(&self, attr_name: &'static PyStrInterned) -> Option { self.attributes.read().get(attr_name).cloned() } - pub fn get_super_attr(&self, attr_name: &str) -> Option { + pub fn get_super_attr(&self, attr_name: &'static PyStrInterned) -> Option { self.mro .iter() .find_map(|class| class.attributes.read().get(attr_name).cloned()) } // This is the internal has_attr implementation for fast lookup on a class. - pub fn has_attr(&self, attr_name: &str) -> bool { + pub fn has_attr(&self, attr_name: &'static PyStrInterned) -> bool { self.attributes.read().contains_key(attr_name) || self .mro @@ -264,11 +272,11 @@ impl PyType { } #[pymethod(magic)] - fn dir(zelf: PyRef, vm: &VirtualMachine) -> PyList { + fn dir(zelf: PyRef, _vm: &VirtualMachine) -> PyList { let attributes: Vec = zelf .get_attributes() .into_iter() - .map(|(k, _)| vm.ctx.new_str(k).into()) + .map(|(k, _)| k.to_object()) .collect(); PyList::from(attributes) } @@ -330,7 +338,7 @@ impl PyType { pub fn qualname(&self, vm: &VirtualMachine) -> PyObjectRef { self.attributes .read() - .get("__qualname__") + .get(identifier!(vm, __qualname__)) .cloned() // We need to exclude this method from going into recursion: .and_then(|found| { @@ -347,7 +355,7 @@ impl PyType { pub fn module(&self, vm: &VirtualMachine) -> PyObjectRef { self.attributes .read() - .get("__module__") + .get(identifier!(vm, __module__)) .cloned() // We need to exclude this method from going into recursion: .and_then(|found| { @@ -361,10 +369,10 @@ impl PyType { } #[pyproperty(magic, setter)] - fn set_module(&self, value: PyObjectRef) { + fn set_module(&self, value: PyObjectRef, vm: &VirtualMachine) { self.attributes .write() - .insert("__module__".to_owned(), value); + .insert(identifier!(vm, __module__), value); } #[pyclassmethod(magic)] @@ -441,7 +449,10 @@ impl PyType { .iter() .map(|obj| { obj.clone().downcast::().or_else(|obj| { - if vm.get_attribute_opt(obj, "__mro_entries__")?.is_some() { + if vm + .get_attribute_opt(obj, identifier!(vm, __mro_entries__))? + .is_some() + { Err(vm.new_type_error( "type() doesn't support MRO entry resolution; \ use types.new_class()" @@ -471,51 +482,56 @@ impl PyType { (metatype, base, bases) }; - let mut attributes = dict.to_attributes(); - if let Some(f) = attributes.get_mut("__new__") { + let mut attributes = dict.to_attributes(vm); + if let Some(f) = attributes.get_mut(identifier!(vm, __new__)) { if f.class().is(&vm.ctx.types.function_type) { *f = PyStaticMethod::from(f.clone()).into_pyobject(vm); } } - if let Some(f) = attributes.get_mut("__init_subclass__") { + if let Some(f) = attributes.get_mut(identifier!(vm, __init_subclass__)) { if f.class().is(&vm.ctx.types.function_type) { *f = PyClassMethod::from(f.clone()).into_pyobject(vm); } } - if let Some(f) = attributes.get_mut("__class_getitem__") { + if let Some(f) = attributes.get_mut(identifier!(vm, __class_getitem__)) { if f.class().is(&vm.ctx.types.function_type) { *f = PyClassMethod::from(f.clone()).into_pyobject(vm); } } if let Some(current_frame) = vm.current_frame() { - let entry = attributes.entry("__module__".to_owned()); + let entry = attributes.entry(identifier!(vm, __module__)); if matches!(entry, Entry::Vacant(_)) { - let module_name = - vm.unwrap_or_none(current_frame.globals.get_item_opt("__name__", vm)?); + let module_name = vm.unwrap_or_none( + current_frame + .globals + .get_item_opt(identifier!(vm, __name__), vm)?, + ); entry.or_insert(module_name); } } attributes - .entry("__qualname__".to_owned()) + .entry(identifier!(vm, __qualname__)) .or_insert_with(|| vm.ctx.new_str(name.as_str()).into()); // All *classes* should have a dict. Exceptions are *instances* of // classes that define __slots__ and instances of built-in classes // (with exceptions, e.g function) - attributes.entry("__dict__".to_owned()).or_insert_with(|| { - vm.ctx - .new_getset( - "__dict__", - vm.ctx.types.object_type.clone(), - subtype_get_dict, - subtype_set_dict, - ) - .into() - }); + attributes + .entry(identifier!(vm, __dict__)) + .or_insert_with(|| { + vm.ctx + .new_getset( + "__dict__", + vm.ctx.types.object_type.clone(), + subtype_get_dict, + subtype_set_dict, + ) + .into() + }); // TODO: Flags is currently initialized with HAS_DICT. Should be // updated when __slots__ are supported (toggling the flag off if @@ -532,13 +548,12 @@ impl PyType { .read() .iter() .filter_map(|(name, obj)| { - vm.get_method(obj.clone(), "__set_name__").map(|res| { - res.map(|meth| (obj.clone(), PyStr::from(name.clone()).into_ref(vm), meth)) - }) + vm.get_method(obj.clone(), identifier!(vm, __set_name__)) + .map(|res| res.map(|meth| (obj.clone(), name.to_owned(), meth))) }) .collect::>>()?; for (obj, name, set_name) in attributes { - vm.invoke(&set_name, (typ.clone(), name.clone())) + vm.invoke(&set_name, (typ.clone(), name.to_owned())) .map_err(|e| { let err = vm.new_runtime_error(format!( "Error calling __set_name__ on '{}' instance {} in '{}'", @@ -551,7 +566,7 @@ impl PyType { })?; } - if let Some(initter) = typ.get_super_attr("__init_subclass__") { + if let Some(initter) = typ.get_super_attr(identifier!(vm, __init_subclass__)) { let initter = vm .call_get_descriptor_specific(initter.clone(), None, Some(typ.clone().into())) .unwrap_or(Ok(initter))?; @@ -629,10 +644,26 @@ pub(crate) fn get_text_signature_from_internal_doc<'a>( impl GetAttr for PyType { fn getattro(zelf: &Py, name_str: PyStrRef, vm: &VirtualMachine) -> PyResult { - let name = name_str.as_str(); + #[cold] + fn attribute_error( + zelf: &Py, + name: &str, + vm: &VirtualMachine, + ) -> PyBaseExceptionRef { + vm.new_attribute_error(format!( + "type object '{}' has no attribute '{}'", + zelf.slot_name(), + name, + )) + } + + let name = if let Some(name) = vm.ctx.interned_str(&*name_str) { + name + } else { + return Err(attribute_error(zelf, name_str.as_str(), vm)); + }; vm_trace!("type.__getattribute__({:?}, {:?})", zelf, name); let mcl = zelf.class(); - let mcl_attr = mcl.get_attr(name); if let Some(ref attr) = mcl_attr { @@ -663,11 +694,7 @@ impl GetAttr for PyType { drop(mcl); vm.call_if_get_descriptor(attr, zelf.to_owned().into()) } else { - Err(vm.new_attribute_error(format!( - "type object '{}' has no attribute '{}'", - zelf.slot_name(), - name - ))) + return Err(attribute_error(zelf, name_str.as_str(), vm)); } } } @@ -679,7 +706,9 @@ impl SetAttr for PyType { value: Option, vm: &VirtualMachine, ) -> PyResult<()> { - if let Some(attr) = zelf.get_class_attr(attr_name.as_str()) { + // TODO: pass PyRefExact instead of &str + let attr_name = vm.ctx.intern_str(attr_name.as_str()); + if let Some(attr) = zelf.get_class_attr(attr_name) { let descr_set = attr.class().mro_find_map(|cls| cls.slots.descr_set.load()); if let Some(descriptor) = descr_set { return descriptor(attr, zelf.to_owned().into(), value, vm); @@ -689,18 +718,17 @@ impl SetAttr for PyType { let mut attributes = zelf.attributes.write(); if let Some(value) = value { - attributes.insert(attr_name.as_str().to_owned(), value); + attributes.insert(attr_name, value); } else { - let prev_value = attributes.remove(attr_name.as_str()); + let prev_value = attributes.remove(attr_name); if prev_value.is_none() { return Err(vm.new_exception( vm.ctx.exceptions.attribute_error.clone(), - vec![attr_name.into()], + vec![attr_name.to_object()], )); } } - let attr_name = attr_name.as_str(); - if attr_name.starts_with("__") && attr_name.ends_with("__") { + if attr_name.as_str().starts_with("__") && attr_name.as_str().ends_with("__") { zelf.update_slot(attr_name, assign); } Ok(()) @@ -731,7 +759,7 @@ fn find_base_dict_descr(cls: &PyTypeRef, vm: &VirtualMachine) -> Option().map(|n| n.as_str().to_string())), - vm.get_attribute_opt(obj.clone(), "__module__")? + vm.get_attribute_opt(obj.clone(), identifier!(vm, __module__))? .and_then(|o| o.downcast_ref::().map(|m| m.as_str().to_string())), ) { (None, _) | (_, None) => Ok(obj.repr(vm)?.as_str().to_string()), @@ -105,11 +109,11 @@ pub fn is_unionable(obj: PyObjectRef, vm: &VirtualMachine) -> bool { || obj.class().is(&vm.ctx.types.union_type) } -fn is_typevar(obj: &PyObjectRef) -> bool { +fn is_typevar(obj: &PyObjectRef, vm: &VirtualMachine) -> bool { let class = obj.class(); class.slot_name() == "TypeVar" && class - .get_attr("__module__") + .get_attr(identifier!(vm, __module__)) .and_then(|o| o.downcast_ref::().map(|s| s.as_str() == "typing")) .unwrap_or(false) } @@ -117,13 +121,13 @@ fn is_typevar(obj: &PyObjectRef) -> bool { fn make_parameters(args: &PyTupleRef, vm: &VirtualMachine) -> PyTupleRef { let mut parameters: Vec = Vec::with_capacity(args.len()); for arg in args { - if is_typevar(arg) { + if is_typevar(arg, vm) { if !parameters.iter().any(|param| param.is(arg)) { parameters.push(arg.clone()); } } else if let Ok(subparams) = arg .clone() - .get_attr("__parameters__", vm) + .get_attr(identifier!(vm, __parameters__), vm) .and_then(|obj| PyTupleRef::try_from_object(vm, obj)) { for subparam in &subparams { diff --git a/vm/src/bytesinner.rs b/vm/src/bytesinner.rs index 8e9613747b..7f3da63733 100644 --- a/vm/src/bytesinner.rs +++ b/vm/src/bytesinner.rs @@ -5,6 +5,7 @@ use crate::{ }, cformat::CFormatBytes, function::{ArgIterable, Either, OptionalArg, OptionalOption, PyComparisonValue}, + identifier, protocol::PyBuffer, sequence::{SequenceMutOp, SequenceOp}, types::PyComparisonOp, @@ -86,7 +87,7 @@ impl ByteInnerNewOptions { obj }; - if let Some(bytes_method) = vm.get_method(obj, "__bytes__") { + if let Some(bytes_method) = vm.get_method(obj, identifier!(vm, __bytes__)) { // construct an exact bytes from __bytes__ slot. // if __bytes__ return a bytes, use the bytes object except we are the subclass of the bytes let bytes = vm.invoke(&bytes_method?, ())?; diff --git a/vm/src/cformat.rs b/vm/src/cformat.rs index fd2486fedd..8e8d47e53b 100644 --- a/vm/src/cformat.rs +++ b/vm/src/cformat.rs @@ -395,7 +395,7 @@ impl CFormatSpec { Ok(buffer.contiguous_or_collect(|bytes| self.format_bytes(bytes))) } else { let bytes = vm - .get_special_method(obj, "__bytes__")? + .get_special_method(obj, identifier!(vm, __bytes__))? .map_err(|obj| { vm.new_type_error(format!( "%b requires a bytes-like object, or an object that \ @@ -420,7 +420,7 @@ impl CFormatSpec { .into_bytes()) } obj => { - if let Some(method) = vm.get_method(obj.clone(), "__int__") { + if let Some(method) = vm.get_method(obj.clone(), identifier!(vm, __int__)) { let result = vm.invoke(&method?, ())?; if let Some(i) = result.payload::() { return Ok(self.format_number(i.as_bigint()).into_bytes()); @@ -514,7 +514,7 @@ impl CFormatSpec { Ok(self.format_number(&try_f64_to_bigint(f.to_f64(), vm)?)) } obj => { - if let Some(method) = vm.get_method(obj.clone(), "__int__") { + if let Some(method) = vm.get_method(obj.clone(), identifier!(vm, __int__)) { let result = vm.invoke(&method?, ())?; if let Some(i) = result.payload::() { return Ok(self.format_number(i.as_bigint())); @@ -689,7 +689,7 @@ impl CFormatBytes { let (num_specifiers, mapping_required) = check_specifiers(&self.parts, vm)?; let mut result = vec![]; - let is_mapping = values_obj.class().has_attr("__getitem__") + let is_mapping = values_obj.class().has_attr(identifier!(vm, __getitem__)) && !values_obj.fast_isinstance(&vm.ctx.types.tuple_type) && !values_obj.fast_isinstance(&vm.ctx.types.bytes_type) && !values_obj.fast_isinstance(&vm.ctx.types.bytearray_type); @@ -841,7 +841,7 @@ impl CFormatString { let (num_specifiers, mapping_required) = check_specifiers(&self.parts, vm)?; let mut result = String::new(); - let is_mapping = values_obj.class().has_attr("__getitem__") + let is_mapping = values_obj.class().has_attr(identifier!(vm, __getitem__)) && !values_obj.fast_isinstance(&vm.ctx.types.tuple_type) && !values_obj.fast_isinstance(&vm.ctx.types.str_type); diff --git a/vm/src/class.rs b/vm/src/class.rs index c6e057929c..fc8ed9d13a 100644 --- a/vm/src/class.rs +++ b/vm/src/class.rs @@ -2,6 +2,7 @@ use crate::{ builtins::{PyBaseObject, PyBoundMethod, PyType, PyTypeRef}, + identifier, object::{PyObjectPayload, PyObjectRef, PyRef}, types::{PyTypeFlags, PyTypeSlots}, vm::Context, @@ -83,28 +84,33 @@ pub trait PyClassImpl: PyClassDef { assert!(class.slots.flags.is_created_with_flags()); } if Self::TP_FLAGS.has_feature(PyTypeFlags::HAS_DICT) { - class.set_str_attr( - "__dict__", + let __dict__ = identifier!(ctx, __dict__); + class.set_attr( + __dict__, ctx.new_getset( "__dict__", class.clone(), crate::builtins::object::object_get_dict, crate::builtins::object::object_set_dict, - ), + ) + .into(), ); } Self::impl_extend_class(ctx, class); if let Some(doc) = Self::DOC { - class.set_str_attr("__doc__", ctx.new_str(doc)); + class.set_attr(identifier!(ctx, __doc__), ctx.new_str(doc).into()); } if let Some(module_name) = Self::MODULE_NAME { - class.set_str_attr("__module__", ctx.new_str(module_name)); + class.set_attr( + identifier!(ctx, __module__), + ctx.new_str(module_name).into(), + ); } if class.slots.new.load().is_some() { let bound: PyObjectRef = PyBoundMethod::new_ref(class.clone().into(), ctx.slot_new_wrapper.clone(), ctx) .into(); - class.set_str_attr("__new__", bound); + class.set_attr(identifier!(ctx, __new__), bound); } } diff --git a/vm/src/dictdatatype.rs b/vm/src/dictdatatype.rs index 487207e880..5e173f0bd8 100644 --- a/vm/src/dictdatatype.rs +++ b/vm/src/dictdatatype.rs @@ -8,7 +8,7 @@ use crate::common::{ lock::{PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard}, }; use crate::{ - builtins::{PyInt, PyStr, PyStrRef}, + builtins::{PyInt, PyStr, PyStrInterned, PyStrRef}, convert::ToPyObject, AsObject, Py, PyExact, PyObject, PyObjectRef, PyRefExact, PyResult, VirtualMachine, }; @@ -751,9 +751,34 @@ impl DictKey for Py { } } +impl DictKey for PyStrInterned { + type Owned = PyRefExact; + #[inline] + fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned { + let zelf: &'static PyStrInterned = unsafe { &*(self as *const _) }; + zelf.to_exact() + } + #[inline] + fn key_hash(&self, vm: &VirtualMachine) -> PyResult { + (**self).key_hash(vm) + } + #[inline] + fn key_is(&self, other: &PyObject) -> bool { + (**self).key_is(other) + } + #[inline] + fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult { + (**self).key_eq(vm, other_key) + } + #[inline] + fn key_as_isize(&self, vm: &VirtualMachine) -> PyResult { + (**self).key_as_isize(vm) + } +} + impl DictKey for PyExact { type Owned = PyRefExact; - #[inline(always)] + #[inline] fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned { self.to_owned() } @@ -761,7 +786,7 @@ impl DictKey for PyExact { fn key_hash(&self, vm: &VirtualMachine) -> PyResult { (**self).key_hash(vm) } - #[inline] + #[inline(always)] fn key_is(&self, other: &PyObject) -> bool { (**self).key_is(other) } diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 91bf73f160..95bed54751 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -765,7 +765,8 @@ impl ExceptionZoo { }); // TODO: this isn't really accurate #[cfg(windows)] - excs.os_error.set_str_attr("winerror", errno_getter.clone()); + excs.os_error + .set_str_attr("winerror", errno_getter.clone(), ctx); extend_exception!(PyBlockingIOError, ctx, &excs.blocking_io_error); extend_exception!(PyChildProcessError, ctx, &excs.child_process_error); diff --git a/vm/src/format.rs b/vm/src/format.rs index 3ce39d7246..7c945e2d76 100644 --- a/vm/src/format.rs +++ b/vm/src/format.rs @@ -892,10 +892,12 @@ pub fn call_object_format( Some(FormatPreconversor::Str) => argument.str(vm)?.into(), Some(FormatPreconversor::Repr) => argument.repr(vm)?.into(), Some(FormatPreconversor::Ascii) => vm.ctx.new_str(builtins::ascii(argument, vm)?).into(), - Some(FormatPreconversor::Bytes) => vm.call_method(&argument, "decode", ())?, + Some(FormatPreconversor::Bytes) => { + vm.call_method(&argument, identifier!(vm, decode).as_str(), ())? + } None => argument, }; - let result = vm.call_special_method(argument, "__format__", (format_spec,))?; + let result = vm.call_special_method(argument, identifier!(vm, __format__), (format_spec,))?; result.downcast().map_err(|result| { vm.new_type_error(format!( "__format__ must return a str, not {}", diff --git a/vm/src/frame.rs b/vm/src/frame.rs index a0d49b41b5..ee95475471 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -723,6 +723,7 @@ impl ExecutingFrame<'_> { } bytecode::Instruction::YieldFrom => self.execute_yield_from(vm), bytecode::Instruction::SetupAnnotation => { + let __annotations__ = identifier!(vm, __annotations__); // Try using locals as dict first, if not, fallback to generic method. let has_annotations = match self .locals @@ -730,15 +731,15 @@ impl ExecutingFrame<'_> { .into_object() .downcast_exact::(vm) { - Ok(d) => d.contains_key("__annotations__", vm), + Ok(d) => d.contains_key(__annotations__, vm), Err(o) => { - let needle = vm.new_pyobj("__annotations__"); + let needle = __annotations__.to_object(); self._in(vm, needle, o)? } }; if !has_annotations { self.locals.as_object().set_item( - "__annotations__", + __annotations__, vm.ctx.new_dict().into(), vm, )?; @@ -786,19 +787,20 @@ impl ExecutingFrame<'_> { } bytecode::Instruction::SetupWith { end } => { let context_manager = self.pop_value(); - let exit = context_manager.get_attr("__exit__", vm)?; + let exit = context_manager.get_attr(identifier!(vm, __exit__), vm)?; self.push_value(exit); // Call enter: - let enter_res = vm.call_special_method(context_manager, "__enter__", ())?; + let enter_res = + vm.call_special_method(context_manager, identifier!(vm, __enter__), ())?; self.push_block(BlockType::Finally { handler: *end }); self.push_value(enter_res); Ok(None) } bytecode::Instruction::BeforeAsyncWith => { let mgr = self.pop_value(); - let aexit = mgr.get_attr("__aexit__", vm)?; + let aexit = mgr.get_attr(identifier!(vm, __aexit__), vm)?; self.push_value(aexit); - let aenter_res = vm.call_special_method(mgr, "__aenter__", ())?; + let aenter_res = vm.call_special_method(mgr, identifier!(vm, __aenter__), ())?; self.push_value(aenter_res); Ok(None) @@ -866,13 +868,16 @@ impl ExecutingFrame<'_> { let awaitable = if awaited_obj.payload_is::() { awaited_obj } else { - let await_method = - vm.get_method_or_type_error(awaited_obj.clone(), "__await__", || { + let await_method = vm.get_method_or_type_error( + awaited_obj.clone(), + identifier!(vm, __await__), + || { format!( "object {} can't be used in 'await' expression", awaited_obj.class().name(), ) - })?; + }, + )?; vm.invoke(&await_method, ())? }; self.push_value(awaitable); @@ -880,17 +885,17 @@ impl ExecutingFrame<'_> { } bytecode::Instruction::GetAIter => { let aiterable = self.pop_value(); - let aiter = vm.call_special_method(aiterable, "__aiter__", ())?; + let aiter = vm.call_special_method(aiterable, identifier!(vm, __aiter__), ())?; self.push_value(aiter); Ok(None) } bytecode::Instruction::GetANext => { let aiter = self.last_value(); - let awaitable = vm.call_special_method(aiter, "__anext__", ())?; + let awaitable = vm.call_special_method(aiter, identifier!(vm, __anext__), ())?; let awaitable = if awaitable.payload_is::() { awaitable } else { - vm.call_special_method(awaitable, "__await__", ())? + vm.call_special_method(awaitable, identifier!(vm, __await__), ())? }; self.push_value(awaitable); Ok(None) @@ -1009,7 +1014,7 @@ impl ExecutingFrame<'_> { Ok(None) } bytecode::Instruction::LoadBuildClass => { - self.push_value(vm.builtins.get_attr("__build_class__", vm)?); + self.push_value(vm.builtins.get_attr(identifier!(vm, __build_class__), vm)?); Ok(None) } bytecode::Instruction::UnpackSequence { size } => { @@ -1135,7 +1140,9 @@ impl ExecutingFrame<'_> { return Ok(obj); } // fallback to importing '{module.__name__}.{name}' from sys.modules - let mod_name = module.get_attr("__name__", vm).map_err(|_| err())?; + let mod_name = module + .get_attr(identifier!(vm, __name__), vm) + .map_err(|_| err())?; let mod_name = mod_name.downcast::().map_err(|_| err())?; let full_mod_name = format!("{}.{}", mod_name, name); let sys_modules = vm @@ -1153,7 +1160,7 @@ impl ExecutingFrame<'_> { // Grab all the names from the module and put them in the context if let Some(dict) = module.dict() { let filter_pred: Box bool> = - if let Ok(all) = dict.get_item("__all__", vm) { + if let Ok(all) = dict.get_item(identifier!(vm, __all__), vm) { let all: Vec = all.try_to_value(vm)?; let all: Vec = all .into_iter() @@ -1595,14 +1602,14 @@ impl ExecutingFrame<'_> { ) .into_pyobject(vm); - func_obj.set_attr("__doc__", vm.ctx.none(), vm)?; + func_obj.set_attr(identifier!(vm, __doc__), vm.ctx.none(), vm)?; let name = qualified_name.as_str().split('.').next_back().unwrap(); - func_obj.set_attr("__name__", vm.new_pyobj(name), vm)?; - func_obj.set_attr("__qualname__", qualified_name, vm)?; - let module = vm.unwrap_or_none(self.globals.get_item_opt("__name__", vm)?); - func_obj.set_attr("__module__", module, vm)?; - func_obj.set_attr("__annotations__", annotations, vm)?; + func_obj.set_attr(identifier!(vm, __name__), vm.new_pyobj(name), vm)?; + func_obj.set_attr(identifier!(vm, __qualname__), qualified_name, vm)?; + let module = vm.unwrap_or_none(self.globals.get_item_opt(identifier!(vm, __name__), vm)?); + func_obj.set_attr(identifier!(vm, __module__), module, vm)?; + func_obj.set_attr(identifier!(vm, __annotations__), annotations, vm)?; self.push_value(func_obj); Ok(None) diff --git a/vm/src/function/protocol.rs b/vm/src/function/protocol.rs index 9d5b54a5a1..de18517ce3 100644 --- a/vm/src/function/protocol.rs +++ b/vm/src/function/protocol.rs @@ -2,6 +2,7 @@ use super::IntoFuncArgs; use crate::{ builtins::{iter::PySequenceIterator, PyDict, PyDictRef}, convert::ToPyObject, + identifier, protocol::{PyIter, PyIterIter, PyMapping, PyMappingMethods}, AsObject, PyObject, PyObjectRef, PyPayload, PyResult, TryFromObject, VirtualMachine, }; @@ -86,7 +87,7 @@ where { let cls = obj.class(); iterfn = cls.mro_find_map(|x| x.slots.iter.load()); - if iterfn.is_none() && !cls.has_attr("__getitem__") { + if iterfn.is_none() && !cls.has_attr(identifier!(vm, __getitem__)) { return Err(vm.new_type_error(format!("'{}' object is not iterable", cls.name()))); } } diff --git a/vm/src/macros.rs b/vm/src/macros.rs index eff8917495..013926aa8e 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -30,7 +30,7 @@ macro_rules! py_class { (@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); + $class.set_attr($name, $value); }; } @@ -38,7 +38,7 @@ macro_rules! py_class { macro_rules! extend_class { ( $ctx:expr, $class:expr, { $($name:expr => $value:expr),* $(,)* }) => { $( - $class.set_str_attr($name, $value); + $class.set_attr($ctx.intern_str($name), $value.into()); )* }; } @@ -177,6 +177,13 @@ macro_rules! match_class { }; } +#[macro_export] +macro_rules! identifier( + ($as_ctx:expr, $name:ident) => { + $as_ctx.as_ref().names.$name + }; +); + /// Super detailed logging. Might soon overflow your logbuffers /// Default, this logging is discarded, except when a the `vm-tracing-logging` /// build feature is enabled. diff --git a/vm/src/object/core.rs b/vm/src/object/core.rs index 378aa1aa6c..1fedb708cb 100644 --- a/vm/src/object/core.rs +++ b/vm/src/object/core.rs @@ -744,7 +744,7 @@ impl PyObject { let ret = crate::vm::thread::with_vm(zelf, |vm| { zelf.0.ref_count.inc(); if let Err(e) = slot_del(zelf, vm) { - let del_method = zelf.get_class_attr("__del__").unwrap(); + let del_method = zelf.get_class_attr(identifier!(vm, __del__)).unwrap(); vm.run_unraisable(e, None, del_method); } zelf.0.ref_count.dec() diff --git a/vm/src/object/ext.rs b/vm/src/object/ext.rs index 47b7b91d67..0a38913ff2 100644 --- a/vm/src/object/ext.rs +++ b/vm/src/object/ext.rs @@ -4,7 +4,7 @@ use super::{ }; use crate::common::lock::PyRwLockReadGuard; use crate::{ - builtins::{PyBaseExceptionRef, PyType}, + builtins::{PyBaseExceptionRef, PyStrInterned, PyType}, convert::{ToPyException, ToPyObject, ToPyResult, TryFromObject}, VirtualMachine, }; @@ -251,7 +251,7 @@ where self.as_object().lease_class() } - fn get_class_attr(&self, attr_name: &str) -> Option { + fn get_class_attr(&self, attr_name: &'static PyStrInterned) -> Option { self.class().get_attr(attr_name) } diff --git a/vm/src/protocol/mapping.rs b/vm/src/protocol/mapping.rs index f8ec7437d4..b90dddc354 100644 --- a/vm/src/protocol/mapping.rs +++ b/vm/src/protocol/mapping.rs @@ -1,7 +1,7 @@ use crate::{ builtins::{ dict::{PyDictItems, PyDictKeys, PyDictValues}, - PyDict, + PyDict, PyStrInterned, }, common::lock::OnceCell, convert::ToPyResult, @@ -135,7 +135,7 @@ impl PyMapping<'_> { if let Some(dict) = self.obj.downcast_ref_if_exact::(vm) { PyDictKeys::new(dict.to_owned()).to_pyresult(vm) } else { - self.method_output_as_list("keys", vm) + self.method_output_as_list(identifier!(vm, keys), vm) } } @@ -143,7 +143,7 @@ impl PyMapping<'_> { if let Some(dict) = self.obj.downcast_ref_if_exact::(vm) { PyDictValues::new(dict.to_owned()).to_pyresult(vm) } else { - self.method_output_as_list("values", vm) + self.method_output_as_list(identifier!(vm, values), vm) } } @@ -151,12 +151,16 @@ impl PyMapping<'_> { if let Some(dict) = self.obj.downcast_ref_if_exact::(vm) { PyDictItems::new(dict.to_owned()).to_pyresult(vm) } else { - self.method_output_as_list("items", vm) + self.method_output_as_list(identifier!(vm, items), vm) } } - fn method_output_as_list(&self, method_name: &str, vm: &VirtualMachine) -> PyResult { - let meth_output = vm.call_method(self.obj, method_name, ())?; + fn method_output_as_list( + &self, + method_name: &'static PyStrInterned, + vm: &VirtualMachine, + ) -> PyResult { + let meth_output = vm.call_method(self.obj, method_name.as_str(), ())?; if meth_output.is(&vm.ctx.types.list_type) { return Ok(meth_output); } @@ -165,7 +169,7 @@ impl PyMapping<'_> { vm.new_type_error(format!( "{}.{}() returned a non-iterable (type {})", self.obj.class(), - method_name, + method_name.as_str(), meth_output.class() )) })?; diff --git a/vm/src/protocol/object.rs b/vm/src/protocol/object.rs index 5023eca11f..bc3e04ced5 100644 --- a/vm/src/protocol/object.rs +++ b/vm/src/protocol/object.rs @@ -143,8 +143,11 @@ impl PyObject { vm: &VirtualMachine, ) -> PyResult<()> { vm_trace!("object.__setattr__({:?}, {}, {:?})", obj, attr_name, value); - - if let Some(attr) = self.get_class_attr(attr_name.as_str()) { + if let Some(attr) = vm + .ctx + .interned_str(&*attr_name) + .and_then(|attr_name| self.get_class_attr(attr_name)) + { let descr_set = attr.class().mro_find_map(|cls| cls.slots.descr_set.load()); if let Some(descriptor) = descr_set { return descriptor(attr, self.to_owned(), value, vm); @@ -160,7 +163,7 @@ impl PyObject { vm.new_attribute_error(format!( "'{}' object has no attribute '{}'", self.class().name(), - attr_name, + attr_name.as_str(), )) } else { e @@ -172,7 +175,7 @@ impl PyObject { Err(vm.new_attribute_error(format!( "'{}' object has no attribute '{}'", self.class().name(), - attr_name, + attr_name.as_str(), ))) } } @@ -191,7 +194,8 @@ impl PyObject { ) -> PyResult> { let name = name_str.as_str(); let obj_cls = self.class(); - let cls_attr = match obj_cls.get_attr(name) { + let cls_attr_name = vm.ctx.interned_str(&*name_str); + let cls_attr = match cls_attr_name.and_then(|name| obj_cls.get_attr(name)) { Some(descr) => { let descr_cls = descr.class(); let descr_get = descr_cls.mro_find_map(|cls| cls.slots.descr_get.load()); @@ -229,7 +233,7 @@ impl PyObject { } None => Ok(Some(attr)), } - } else if let Some(getter) = obj_cls.get_attr("__getattr__") { + } else if let Some(getter) = obj_cls.get_attr(identifier!(vm, __getattr__)) { drop(obj_cls); vm.invoke(&getter, (self.to_owned(), name_str)).map(Some) } else { @@ -310,7 +314,7 @@ impl PyObject { pub fn repr(&self, vm: &VirtualMachine) -> PyResult { vm.with_recursion("while getting the repr of an object", || { - let repr = vm.call_special_method(self.to_owned(), "__repr__", ())?; + let repr = vm.call_special_method(self.to_owned(), identifier!(vm, __repr__), ())?; repr.try_into_value(vm) }) } @@ -326,7 +330,7 @@ impl PyObject { if self.class().is(&vm.ctx.types.str_type) { Ok(self.to_owned().downcast().unwrap()) } else { - let s = vm.call_special_method(self.to_owned(), "__str__", ())?; + let s = vm.call_special_method(self.to_owned(), identifier!(vm, __str__), ())?; s.try_into_value(vm) } } @@ -337,14 +341,16 @@ impl PyObject { where F: Fn() -> String, { - cls.to_owned().get_attr("__bases__", vm).map_err(|e| { - // Only mask AttributeErrors. - if e.class().is(&vm.ctx.exceptions.attribute_error) { - vm.new_type_error(msg()) - } else { - e - } - }) + cls.to_owned() + .get_attr(identifier!(vm, __bases__), vm) + .map_err(|e| { + // Only mask AttributeErrors. + if e.class().is(&vm.ctx.exceptions.attribute_error) { + vm.new_type_error(msg()) + } else { + e + } + }) } fn abstract_issubclass(&self, cls: &PyObject, vm: &VirtualMachine) -> PyResult { @@ -355,7 +361,9 @@ impl PyObject { return Ok(true); } - let bases = derived.to_owned().get_attr("__bases__", vm)?; + let bases = derived + .to_owned() + .get_attr(identifier!(vm, __bases__), vm)?; let tuple = PyTupleRef::try_from_object(vm, bases)?; let n = tuple.len(); @@ -420,7 +428,9 @@ impl PyObject { return Ok(false); } - if let Ok(meth) = vm.get_special_method(cls.to_owned(), "__subclasscheck__")? { + if let Ok(meth) = + vm.get_special_method(cls.to_owned(), identifier!(vm, __subclasscheck__))? + { let ret = vm.with_recursion("in __subclasscheck__", || { meth.invoke((self.to_owned(),), vm) })?; @@ -434,9 +444,10 @@ impl PyObject { if let Ok(typ) = PyTypeRef::try_from_object(vm, cls.to_owned()) { if self.class().fast_issubclass(&typ) { Ok(true) - } else if let Ok(icls) = - PyTypeRef::try_from_object(vm, self.to_owned().get_attr("__class__", vm)?) - { + } else if let Ok(icls) = PyTypeRef::try_from_object( + vm, + self.to_owned().get_attr(identifier!(vm, __class__), vm)?, + ) { if icls.is(&self.class()) { Ok(false) } else { @@ -453,7 +464,7 @@ impl PyObject { ) }) .and_then(|_| { - let icls: PyObjectRef = self.to_owned().get_attr("__class__", vm)?; + let icls: PyObjectRef = self.to_owned().get_attr(identifier!(vm, __class__), vm)?; if vm.is_none(&icls) { Ok(false) } else { @@ -485,7 +496,9 @@ impl PyObject { return Ok(false); } - if let Ok(meth) = vm.get_special_method(cls.to_owned(), "__instancecheck__")? { + if let Ok(meth) = + vm.get_special_method(cls.to_owned(), identifier!(vm, __instancecheck__))? + { let ret = vm.with_recursion("in __instancecheck__", || { meth.invoke((self.to_owned(),), vm) })?; @@ -538,7 +551,7 @@ impl PyObject { } if let Some(class_getitem) = - vm.get_attribute_opt(self.to_owned(), "__class_getitem__")? + vm.get_attribute_opt(self.to_owned(), identifier!(vm, __class_getitem__))? { return vm.invoke(&class_getitem, (needle,)); } diff --git a/vm/src/stdlib/ast/gen.rs b/vm/src/stdlib/ast/gen.rs index e094ee738d..2f50dee195 100644 --- a/vm/src/stdlib/ast/gen.rs +++ b/vm/src/stdlib/ast/gen.rs @@ -15,14 +15,15 @@ struct NodeModule; impl NodeModule { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("type_ignores")).into(), - ]), + ]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Interactive", base = "NodeKindMod")] @@ -31,11 +32,12 @@ struct NodeInteractive; impl NodeInteractive { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("body")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("body")).into()]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Expression", base = "NodeKindMod")] @@ -44,11 +46,12 @@ struct NodeExpression; impl NodeExpression { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("body")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("body")).into()]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "FunctionType", base = "NodeKindMod")] @@ -57,14 +60,15 @@ struct NodeFunctionType; impl NodeFunctionType { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("argtypes")).into(), ctx.new_str(ascii!("returns")).into(), - ]), + ]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "stmt", base = "AstNode")] @@ -77,8 +81,8 @@ struct NodeFunctionDef; impl NodeFunctionDef { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("name")).into(), ctx.new_str(ascii!("args")).into(), @@ -86,16 +90,18 @@ impl NodeFunctionDef { ctx.new_str(ascii!("decorator_list")).into(), ctx.new_str(ascii!("returns")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -105,8 +111,8 @@ struct NodeAsyncFunctionDef; impl NodeAsyncFunctionDef { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("name")).into(), ctx.new_str(ascii!("args")).into(), @@ -114,16 +120,18 @@ impl NodeAsyncFunctionDef { ctx.new_str(ascii!("decorator_list")).into(), ctx.new_str(ascii!("returns")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -133,24 +141,26 @@ struct NodeClassDef; impl NodeClassDef { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("name")).into(), ctx.new_str(ascii!("bases")).into(), ctx.new_str(ascii!("keywords")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("decorator_list")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -160,18 +170,20 @@ struct NodeReturn; impl NodeReturn { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -181,18 +193,20 @@ struct NodeDelete; impl NodeDelete { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("targets")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("targets")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -202,22 +216,24 @@ struct NodeAssign; impl NodeAssign { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("targets")).into(), ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -227,22 +243,24 @@ struct NodeAugAssign; impl NodeAugAssign { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("target")).into(), ctx.new_str(ascii!("op")).into(), ctx.new_str(ascii!("value")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -252,23 +270,25 @@ struct NodeAnnAssign; impl NodeAnnAssign { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("target")).into(), ctx.new_str(ascii!("annotation")).into(), ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("simple")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -278,24 +298,26 @@ struct NodeFor; impl NodeFor { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("target")).into(), ctx.new_str(ascii!("iter")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("orelse")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -305,24 +327,26 @@ struct NodeAsyncFor; impl NodeAsyncFor { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("target")).into(), ctx.new_str(ascii!("iter")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("orelse")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -332,22 +356,24 @@ struct NodeWhile; impl NodeWhile { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("test")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("orelse")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -357,22 +383,24 @@ struct NodeIf; impl NodeIf { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("test")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("orelse")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -382,22 +410,24 @@ struct NodeWith; impl NodeWith { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("items")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -407,22 +437,24 @@ struct NodeAsyncWith; impl NodeAsyncWith { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("items")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -432,21 +464,23 @@ struct NodeRaise; impl NodeRaise { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("exc")).into(), ctx.new_str(ascii!("cause")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -456,23 +490,25 @@ struct NodeTry; impl NodeTry { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("handlers")).into(), ctx.new_str(ascii!("orelse")).into(), ctx.new_str(ascii!("finalbody")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -482,21 +518,23 @@ struct NodeAssert; impl NodeAssert { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("test")).into(), ctx.new_str(ascii!("msg")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -506,18 +544,20 @@ struct NodeImport; impl NodeImport { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("names")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("names")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -527,22 +567,24 @@ struct NodeImportFrom; impl NodeImportFrom { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("module")).into(), ctx.new_str(ascii!("names")).into(), ctx.new_str(ascii!("level")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -552,18 +594,20 @@ struct NodeGlobal; impl NodeGlobal { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("names")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("names")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -573,18 +617,20 @@ struct NodeNonlocal; impl NodeNonlocal { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("names")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("names")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -594,18 +640,20 @@ struct NodeExpr; impl NodeExpr { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -615,15 +663,16 @@ struct NodePass; impl NodePass { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr( - "_attributes", + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -633,15 +682,16 @@ struct NodeBreak; impl NodeBreak { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr( - "_attributes", + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -651,15 +701,16 @@ struct NodeContinue; impl NodeContinue { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr( - "_attributes", + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -673,21 +724,23 @@ struct NodeBoolOp; impl NodeBoolOp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("op")).into(), ctx.new_str(ascii!("values")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -697,21 +750,23 @@ struct NodeNamedExpr; impl NodeNamedExpr { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("target")).into(), ctx.new_str(ascii!("value")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -721,22 +776,24 @@ struct NodeBinOp; impl NodeBinOp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("left")).into(), ctx.new_str(ascii!("op")).into(), ctx.new_str(ascii!("right")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -746,21 +803,23 @@ struct NodeUnaryOp; impl NodeUnaryOp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("op")).into(), ctx.new_str(ascii!("operand")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -770,21 +829,23 @@ struct NodeLambda; impl NodeLambda { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("args")).into(), ctx.new_str(ascii!("body")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -794,22 +855,24 @@ struct NodeIfExp; impl NodeIfExp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("test")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("orelse")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -819,21 +882,23 @@ struct NodeDict; impl NodeDict { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("keys")).into(), ctx.new_str(ascii!("values")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -843,18 +908,20 @@ struct NodeSet; impl NodeSet { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("elts")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("elts")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -864,21 +931,23 @@ struct NodeListComp; impl NodeListComp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("elt")).into(), ctx.new_str(ascii!("generators")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -888,21 +957,23 @@ struct NodeSetComp; impl NodeSetComp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("elt")).into(), ctx.new_str(ascii!("generators")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -912,22 +983,24 @@ struct NodeDictComp; impl NodeDictComp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("key")).into(), ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("generators")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -937,21 +1010,23 @@ struct NodeGeneratorExp; impl NodeGeneratorExp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("elt")).into(), ctx.new_str(ascii!("generators")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -961,18 +1036,20 @@ struct NodeAwait; impl NodeAwait { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -982,18 +1059,20 @@ struct NodeYield; impl NodeYield { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1003,18 +1082,20 @@ struct NodeYieldFrom; impl NodeYieldFrom { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1024,22 +1105,24 @@ struct NodeCompare; impl NodeCompare { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("left")).into(), ctx.new_str(ascii!("ops")).into(), ctx.new_str(ascii!("comparators")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1049,22 +1132,24 @@ struct NodeCall; impl NodeCall { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("func")).into(), ctx.new_str(ascii!("args")).into(), ctx.new_str(ascii!("keywords")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1074,22 +1159,24 @@ struct NodeFormattedValue; impl NodeFormattedValue { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("conversion")).into(), ctx.new_str(ascii!("format_spec")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1099,18 +1186,20 @@ struct NodeJoinedStr; impl NodeJoinedStr { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("values")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("values")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1120,21 +1209,23 @@ struct NodeConstant; impl NodeConstant { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("kind")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1144,22 +1235,24 @@ struct NodeAttribute; impl NodeAttribute { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("attr")).into(), ctx.new_str(ascii!("ctx")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1169,22 +1262,24 @@ struct NodeSubscript; impl NodeSubscript { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("slice")).into(), ctx.new_str(ascii!("ctx")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1194,21 +1289,23 @@ struct NodeStarred; impl NodeStarred { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("ctx")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1218,21 +1315,23 @@ struct NodeName; impl NodeName { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("id")).into(), ctx.new_str(ascii!("ctx")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1242,21 +1341,23 @@ struct NodeList; impl NodeList { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("elts")).into(), ctx.new_str(ascii!("ctx")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1266,21 +1367,23 @@ struct NodeTuple; impl NodeTuple { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("elts")).into(), ctx.new_str(ascii!("ctx")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1290,22 +1393,24 @@ struct NodeSlice; impl NodeSlice { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("lower")).into(), ctx.new_str(ascii!("upper")).into(), ctx.new_str(ascii!("step")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1319,8 +1424,8 @@ struct NodeLoad; impl NodeLoad { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Store", base = "NodeKindExprContext")] @@ -1329,8 +1434,8 @@ struct NodeStore; impl NodeStore { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Del", base = "NodeKindExprContext")] @@ -1339,8 +1444,8 @@ struct NodeDel; impl NodeDel { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "boolop", base = "AstNode")] @@ -1353,8 +1458,8 @@ struct NodeAnd; impl NodeAnd { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Or", base = "NodeKindBoolop")] @@ -1363,8 +1468,8 @@ struct NodeOr; impl NodeOr { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "operator", base = "AstNode")] @@ -1377,8 +1482,8 @@ struct NodeAdd; impl NodeAdd { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Sub", base = "NodeKindOperator")] @@ -1387,8 +1492,8 @@ struct NodeSub; impl NodeSub { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Mult", base = "NodeKindOperator")] @@ -1397,8 +1502,8 @@ struct NodeMult; impl NodeMult { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "MatMult", base = "NodeKindOperator")] @@ -1407,8 +1512,8 @@ struct NodeMatMult; impl NodeMatMult { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Div", base = "NodeKindOperator")] @@ -1417,8 +1522,8 @@ struct NodeDiv; impl NodeDiv { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Mod", base = "NodeKindOperator")] @@ -1427,8 +1532,8 @@ struct NodeMod; impl NodeMod { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Pow", base = "NodeKindOperator")] @@ -1437,8 +1542,8 @@ struct NodePow; impl NodePow { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "LShift", base = "NodeKindOperator")] @@ -1447,8 +1552,8 @@ struct NodeLShift; impl NodeLShift { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "RShift", base = "NodeKindOperator")] @@ -1457,8 +1562,8 @@ struct NodeRShift; impl NodeRShift { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "BitOr", base = "NodeKindOperator")] @@ -1467,8 +1572,8 @@ struct NodeBitOr; impl NodeBitOr { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "BitXor", base = "NodeKindOperator")] @@ -1477,8 +1582,8 @@ struct NodeBitXor; impl NodeBitXor { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "BitAnd", base = "NodeKindOperator")] @@ -1487,8 +1592,8 @@ struct NodeBitAnd; impl NodeBitAnd { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "FloorDiv", base = "NodeKindOperator")] @@ -1497,8 +1602,8 @@ struct NodeFloorDiv; impl NodeFloorDiv { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "unaryop", base = "AstNode")] @@ -1511,8 +1616,8 @@ struct NodeInvert; impl NodeInvert { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Not", base = "NodeKindUnaryop")] @@ -1521,8 +1626,8 @@ struct NodeNot; impl NodeNot { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "UAdd", base = "NodeKindUnaryop")] @@ -1531,8 +1636,8 @@ struct NodeUAdd; impl NodeUAdd { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "USub", base = "NodeKindUnaryop")] @@ -1541,8 +1646,8 @@ struct NodeUSub; impl NodeUSub { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "cmpop", base = "AstNode")] @@ -1555,8 +1660,8 @@ struct NodeEq; impl NodeEq { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "NotEq", base = "NodeKindCmpop")] @@ -1565,8 +1670,8 @@ struct NodeNotEq; impl NodeNotEq { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Lt", base = "NodeKindCmpop")] @@ -1575,8 +1680,8 @@ struct NodeLt; impl NodeLt { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "LtE", base = "NodeKindCmpop")] @@ -1585,8 +1690,8 @@ struct NodeLtE; impl NodeLtE { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Gt", base = "NodeKindCmpop")] @@ -1595,8 +1700,8 @@ struct NodeGt; impl NodeGt { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "GtE", base = "NodeKindCmpop")] @@ -1605,8 +1710,8 @@ struct NodeGtE; impl NodeGtE { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Is", base = "NodeKindCmpop")] @@ -1615,8 +1720,8 @@ struct NodeIs; impl NodeIs { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "IsNot", base = "NodeKindCmpop")] @@ -1625,8 +1730,8 @@ struct NodeIsNot; impl NodeIsNot { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "In", base = "NodeKindCmpop")] @@ -1635,8 +1740,8 @@ struct NodeIn; impl NodeIn { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "NotIn", base = "NodeKindCmpop")] @@ -1645,8 +1750,8 @@ struct NodeNotIn; impl NodeNotIn { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "comprehension", base = "AstNode")] @@ -1655,16 +1760,17 @@ struct Nodecomprehension; impl Nodecomprehension { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("target")).into(), ctx.new_str(ascii!("iter")).into(), ctx.new_str(ascii!("ifs")).into(), ctx.new_str(ascii!("is_async")).into(), - ]), + ]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "excepthandler", base = "AstNode")] @@ -1681,22 +1787,24 @@ struct NodeExceptHandler; impl NodeExceptHandler { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("type")).into(), ctx.new_str(ascii!("name")).into(), ctx.new_str(ascii!("body")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1706,8 +1814,8 @@ struct Nodearguments; impl Nodearguments { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("posonlyargs")).into(), ctx.new_str(ascii!("args")).into(), @@ -1716,9 +1824,10 @@ impl Nodearguments { ctx.new_str(ascii!("kw_defaults")).into(), ctx.new_str(ascii!("kwarg")).into(), ctx.new_str(ascii!("defaults")).into(), - ]), + ]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "arg", base = "AstNode")] @@ -1727,22 +1836,24 @@ struct Nodearg; impl Nodearg { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("arg")).into(), ctx.new_str(ascii!("annotation")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1752,21 +1863,23 @@ struct Nodekeyword; impl Nodekeyword { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("arg")).into(), ctx.new_str(ascii!("value")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1776,14 +1889,15 @@ struct Nodealias; impl Nodealias { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("name")).into(), ctx.new_str(ascii!("asname")).into(), - ]), + ]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "withitem", base = "AstNode")] @@ -1792,14 +1906,15 @@ struct Nodewithitem; impl Nodewithitem { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("context_expr")).into(), ctx.new_str(ascii!("optional_vars")).into(), - ]), + ]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "type_ignore", base = "AstNode")] @@ -1812,14 +1927,15 @@ struct NodeTypeIgnore; impl NodeTypeIgnore { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("tag")).into(), - ]), + ]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } diff --git a/vm/src/stdlib/builtins.rs b/vm/src/stdlib/builtins.rs index e1e785c73f..e32867ac8f 100644 --- a/vm/src/stdlib/builtins.rs +++ b/vm/src/stdlib/builtins.rs @@ -218,9 +218,9 @@ mod builtins { fn make_scope(self, vm: &VirtualMachine) -> PyResult { let (globals, locals) = match self.globals { Some(globals) => { - if !globals.contains_key("__builtins__", vm) { + if !globals.contains_key(identifier!(vm, __builtins__), vm) { let builtins_dict = vm.builtins.dict().into(); - globals.set_item("__builtins__", builtins_dict, vm)?; + globals.set_item(identifier!(vm, __builtins__), builtins_dict, vm)?; } ( globals.clone(), @@ -424,7 +424,7 @@ mod builtins { #[pyfunction] fn aiter(iter_target: PyObjectRef, vm: &VirtualMachine) -> PyResult { if iter_target.payload_is::() { - vm.call_special_method(iter_target, "__aiter__", ()) + vm.call_special_method(iter_target, identifier!(vm, __aiter__), ()) } else { Err(vm.new_type_error("wrong argument type".to_owned())) } @@ -591,14 +591,18 @@ mod builtins { modulus, } = args; match modulus { - None => vm.call_or_reflection(&x, &y, "__pow__", "__rpow__", |vm, x, y| { - Err(vm.new_unsupported_binop_error(x, y, "pow")) - }), + None => vm.call_or_reflection( + &x, + &y, + identifier!(vm, __pow__), + identifier!(vm, __rpow__), + |vm, x, y| Err(vm.new_unsupported_binop_error(x, y, "pow")), + ), Some(z) => { let try_pow_value = |obj: &PyObject, args: (PyObjectRef, PyObjectRef, PyObjectRef)| -> Option { - let method = obj.get_class_attr("__pow__")?; + let method = obj.get_class_attr(identifier!(vm, __pow__))?; let result = match vm.invoke(&method, args) { Ok(x) => x, Err(e) => return Some(Err(e)), @@ -685,10 +689,10 @@ mod builtins { #[pyfunction] fn reversed(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { - if let Some(reversed_method) = vm.get_method(obj.clone(), "__reversed__") { + if let Some(reversed_method) = vm.get_method(obj.clone(), identifier!(vm, __reversed__)) { vm.invoke(&reversed_method?, ()) } else { - vm.get_method_or_type_error(obj.clone(), "__getitem__", || { + vm.get_method_or_type_error(obj.clone(), identifier!(vm, __getitem__), || { "argument to reversed() must be a sequence".to_owned() })?; let len = obj.length(vm)?; @@ -707,7 +711,7 @@ mod builtins { #[pyfunction] fn round(RoundArgs { number, ndigits }: RoundArgs, vm: &VirtualMachine) -> PyResult { let meth = vm - .get_special_method(number, "__round__")? + .get_special_method(number, identifier!(vm, __round__))? .map_err(|number| { vm.new_type_error(format!( "type {} doesn't define __round__", @@ -792,9 +796,10 @@ mod builtins { #[pyfunction] fn vars(obj: OptionalArg, vm: &VirtualMachine) -> PyResult { if let OptionalArg::Present(obj) = obj { - obj.get_attr("__dict__", vm).map_err(|_| { - vm.new_type_error("vars() argument must have __dict__ attribute".to_owned()) - }) + obj.get_attr(identifier!(vm, __dict__).to_owned(), vm) + .map_err(|_| { + vm.new_type_error("vars() argument must have __dict__ attribute".to_owned()) + }) } else { Ok(vm.current_locals()?.into()) } @@ -821,7 +826,8 @@ mod builtins { } continue; } - let mro_entries = vm.get_attribute_opt(base.clone(), "__mro_entries__")?; + let mro_entries = + vm.get_attribute_opt(base.clone(), identifier!(vm, __mro_entries__))?; let entries = match mro_entries { Some(meth) => vm.invoke(&meth, (bases.clone(),))?, None => { @@ -874,7 +880,7 @@ mod builtins { // Prepare uses full __getattribute__ resolution chain. let namespace = vm - .get_attribute_opt(metaclass.clone(), "__prepare__")? + .get_attribute_opt(metaclass.clone(), identifier!(vm, __prepare__))? .map_or(Ok(vm.ctx.new_dict().into()), |prepare| { vm.invoke( &prepare, @@ -895,9 +901,11 @@ mod builtins { let classcell = >::try_from_object(vm, classcell)?; if let Some(orig_bases) = orig_bases { - namespace - .as_object() - .set_item("__orig_bases__", orig_bases.into(), vm)?; + namespace.as_object().set_item( + identifier!(vm, __orig_bases__), + orig_bases.into(), + vm, + )?; } let class = vm.invoke( diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 6233c27d65..2bcc314d31 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -1192,7 +1192,7 @@ mod _io { } let readall = vm - .get_method(self.raw.clone().unwrap(), "readall") + .get_str_method(self.raw.clone().unwrap(), "readall") .transpose()?; if let Some(readall) = readall { let res = vm.invoke(&readall, ())?; diff --git a/vm/src/stdlib/itertools.rs b/vm/src/stdlib/itertools.rs index bd4de3ce0a..c603ad8bef 100644 --- a/vm/src/stdlib/itertools.rs +++ b/vm/src/stdlib/itertools.rs @@ -10,6 +10,7 @@ mod decl { builtins::{int, PyGenericAlias, PyInt, PyIntRef, PyTuple, PyTupleRef, PyTypeRef}, convert::ToPyObject, function::{ArgCallable, FuncArgs, OptionalArg, OptionalOption, PosArgs}, + identifier, protocol::{PyIter, PyIterReturn}, stdlib::sys, types::{Constructor, IterNext, IterNextIterable}, @@ -1019,15 +1020,19 @@ mod decl { ) -> PyResult { let n = n.unwrap_or(2); - let copyable = if iterable.class().has_attr("__copy__") { - vm.call_method(&iterable, "__copy__", ())? + let copyable = if iterable.class().has_attr(identifier!(vm, __copy__)) { + vm.call_special_method(iterable.into(), identifier!(vm, __copy__), ())? } else { PyItertoolsTee::from_iter(iterable, vm)? }; let mut tee_vec: Vec = Vec::with_capacity(n); for _ in 0..n { - tee_vec.push(vm.call_method(©able, "__copy__", ())?); + tee_vec.push(vm.call_special_method( + copyable.clone(), + identifier!(vm, __copy__), + (), + )?); } Ok(PyTuple::new_ref(tee_vec, &vm.ctx).into()) @@ -1039,7 +1044,7 @@ mod decl { fn from_iter(iterator: PyIter, vm: &VirtualMachine) -> PyResult { let class = PyItertoolsTee::class(vm); if iterator.class().is(PyItertoolsTee::class(vm)) { - return vm.call_method(&iterator, "__copy__", ()); + return vm.call_special_method(iterator.into(), identifier!(vm, __copy__), ()); } Ok(PyItertoolsTee { tee_data: PyItertoolsTeeData::new(iterator, vm)?, diff --git a/vm/src/stdlib/operator.rs b/vm/src/stdlib/operator.rs index ac72893c30..d439006aa2 100644 --- a/vm/src/stdlib/operator.rs +++ b/vm/src/stdlib/operator.rs @@ -14,6 +14,7 @@ mod _operator { builtins::{PyInt, PyIntRef, PyStrRef, PyTupleRef, PyTypeRef}, function::Either, function::{ArgBytesLike, FuncArgs, KwArgs, OptionalArg}, + identifier, protocol::PyIter, recursion::ReprGuard, types::{Callable, Constructor, PyComparisonOp}, @@ -196,7 +197,9 @@ mod _operator { #[pyfunction] fn concat(a: PyObjectRef, b: PyObjectRef, vm: &VirtualMachine) -> PyResult { // Best attempt at checking that a is sequence-like. - if !a.class().has_attr("__getitem__") || a.fast_isinstance(&vm.ctx.types.dict_type) { + if !a.class().has_attr(identifier!(vm, __getitem__)) + || a.fast_isinstance(&vm.ctx.types.dict_type) + { return Err( vm.new_type_error(format!("{} object can't be concatenated", a.class().name())) ); @@ -299,7 +302,9 @@ mod _operator { #[pyfunction] fn iconcat(a: PyObjectRef, b: PyObjectRef, vm: &VirtualMachine) -> PyResult { // Best attempt at checking that a is sequence-like. - if !a.class().has_attr("__getitem__") || a.fast_isinstance(&vm.ctx.types.dict_type) { + if !a.class().has_attr(identifier!(vm, __getitem__)) + || a.fast_isinstance(&vm.ctx.types.dict_type) + { return Err( vm.new_type_error(format!("{} object can't be concatenated", a.class().name())) ); diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index a0ee7c509a..e96f3cfe8a 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -3,6 +3,7 @@ use crate::{ common::crt_fd::Fd, convert::{ToPyException, ToPyObject}, function::{ArgumentError, FromArgs, FuncArgs}, + identifier, protocol::PyBuffer, AsObject, PyObject, PyObjectRef, PyPayload, PyResult, TryFromBorrowedObject, TryFromObject, VirtualMachine, @@ -137,12 +138,13 @@ impl FsPath { Ok(pathlike) => return Ok(pathlike), Err(obj) => obj, }; - let method = vm.get_method_or_type_error(obj.clone(), "__fspath__", || { - format!( - "should be string, bytes, os.PathLike or integer, not {}", - obj.class().name() - ) - })?; + let method = + vm.get_method_or_type_error(obj.clone(), identifier!(vm, __fspath__), || { + format!( + "should be string, bytes, os.PathLike or integer, not {}", + obj.class().name() + ) + })?; let result = vm.invoke(&method, ())?; match1(result)?.map_err(|result| { vm.new_type_error(format!( diff --git a/vm/src/stdlib/sre.rs b/vm/src/stdlib/sre.rs index 9c0abd1c69..7ffbb35dca 100644 --- a/vm/src/stdlib/sre.rs +++ b/vm/src/stdlib/sre.rs @@ -282,7 +282,7 @@ mod _sre { must_advance: AtomicCell::new(false), } .into_ref(vm); - let search = vm.get_method(scanner.into(), "search").unwrap()?; + let search = vm.get_str_method(scanner.into(), "search").unwrap()?; let search = ArgCallable::try_from_object(vm, search)?; let iterator = PyCallableIterator::new(search, vm.ctx.none()); Ok(iterator) diff --git a/vm/src/stdlib/thread.rs b/vm/src/stdlib/thread.rs index 8e8fbb6121..ef00af875b 100644 --- a/vm/src/stdlib/thread.rs +++ b/vm/src/stdlib/thread.rs @@ -245,8 +245,9 @@ pub(crate) mod _thread { let args = FuncArgs::new( args.to_vec(), kwargs - .map_or_else(Default::default, |k| k.to_attributes()) + .map_or_else(Default::default, |k| k.to_attributes(vm)) .into_iter() + .map(|(k, v)| (k.as_str().to_owned(), v)) .collect::(), ); let mut thread_builder = thread::Builder::new(); diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 449b0fc52e..b626327e91 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -1,13 +1,15 @@ use crate::common::{hash::PyHash, lock::PyRwLock}; use crate::{ - builtins::{PyInt, PyStrRef, PyType, PyTypeRef}, + builtins::{PyInt, PyStrInterned, PyStrRef, PyType, PyTypeRef}, bytecode::ComparisonOperator, convert::{ToPyObject, ToPyResult}, function::Either, function::{FromArgs, FuncArgs, OptionalArg, PyComparisonValue}, + identifier, protocol::{ PyBuffer, PyIterReturn, PyMapping, PyMappingMethods, PySequence, PySequenceMethods, }, + vm::Context, AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; use crossbeam_utils::atomic::AtomicCell; @@ -173,7 +175,7 @@ macro_rules! then_some_closure { } fn length_wrapper(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { - let ret = vm.call_special_method(obj, "__len__", ())?; + let ret = vm.call_special_method(obj, identifier!(vm, __len__), ())?; let len = ret.payload::().ok_or_else(|| { vm.new_type_error(format!( "'{}' object cannot be interpreted as an integer", @@ -190,31 +192,37 @@ fn length_wrapper(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { Ok(len as usize) } -fn as_mapping_wrapper(zelf: &PyObject, _vm: &VirtualMachine) -> PyMappingMethods { +fn as_mapping_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyMappingMethods { PyMappingMethods { - length: then_some_closure!(zelf.class().has_attr("__len__"), |mapping, vm| { - length_wrapper(mapping.obj.to_owned(), vm) - }), + length: then_some_closure!( + zelf.class().has_attr(identifier!(vm, __len__)), + |mapping, vm| { length_wrapper(mapping.obj.to_owned(), vm) } + ), subscript: then_some_closure!( - zelf.class().has_attr("__getitem__"), + zelf.class().has_attr(identifier!(vm, __getitem__)), |mapping, needle, vm| { - vm.call_special_method(mapping.obj.to_owned(), "__getitem__", (needle.to_owned(),)) + vm.call_special_method( + mapping.obj.to_owned(), + identifier!(vm, __getitem__), + (needle.to_owned(),), + ) } ), ass_subscript: then_some_closure!( - zelf.class().has_attr("__setitem__") | zelf.class().has_attr("__delitem__"), + zelf.class().has_attr(identifier!(vm, __setitem__)) + | zelf.class().has_attr(identifier!(vm, __delitem__)), |mapping, needle, value, vm| match value { Some(value) => vm .call_special_method( mapping.obj.to_owned(), - "__setitem__", + identifier!(vm, __setitem__), (needle.to_owned(), value), ) .map(|_| Ok(()))?, None => vm .call_special_method( mapping.obj.to_owned(), - "__delitem__", + identifier!(vm, __delitem__), (needle.to_owned(),) ) .map(|_| Ok(()))?, @@ -223,30 +231,40 @@ fn as_mapping_wrapper(zelf: &PyObject, _vm: &VirtualMachine) -> PyMappingMethods } } -fn as_sequence_wrapper(zelf: &PyObject, _vm: &VirtualMachine) -> Cow<'static, PySequenceMethods> { - if !zelf.class().has_attr("__getitem__") { +fn as_sequence_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> Cow<'static, PySequenceMethods> { + if !zelf.class().has_attr(identifier!(vm, __getitem__)) { return Cow::Borrowed(PySequenceMethods::not_implemented()); } Cow::Owned(PySequenceMethods { - length: then_some_closure!(zelf.class().has_attr("__len__"), |seq, vm| { - length_wrapper(seq.obj.to_owned(), vm) - }), + length: then_some_closure!( + zelf.class().has_attr(identifier!(vm, __len__)), + |seq, vm| { length_wrapper(seq.obj.to_owned(), vm) } + ), item: Some(|seq, i, vm| { - vm.call_special_method(seq.obj.to_owned(), "__getitem__", (i.to_pyobject(vm),)) + vm.call_special_method( + seq.obj.to_owned(), + identifier!(vm, __getitem__), + (i.to_pyobject(vm),), + ) }), ass_item: then_some_closure!( - zelf.class().has_attr("__setitem__") | zelf.class().has_attr("__delitem__"), + zelf.class().has_attr(identifier!(vm, __setitem__)) + | zelf.class().has_attr(identifier!(vm, __delitem__)), |seq, i, value, vm| match value { Some(value) => vm .call_special_method( seq.obj.to_owned(), - "__setitem__", + identifier!(vm, __setitem__), (i.to_pyobject(vm), value), ) .map(|_| Ok(()))?, None => vm - .call_special_method(seq.obj.to_owned(), "__delitem__", (i.to_pyobject(vm),)) + .call_special_method( + seq.obj.to_owned(), + identifier!(vm, __delitem__), + (i.to_pyobject(vm),) + ) .map(|_| Ok(()))?, } ), @@ -255,7 +273,7 @@ fn as_sequence_wrapper(zelf: &PyObject, _vm: &VirtualMachine) -> Cow<'static, Py } fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { - let hash_obj = vm.call_special_method(zelf.to_owned(), "__hash__", ())?; + let hash_obj = vm.call_special_method(zelf.to_owned(), identifier!(vm, __hash__), ())?; match hash_obj.payload_if_subclass::(vm) { Some(py_int) => Ok(rustpython_common::hash::hash_bigint(py_int.as_bigint())), None => Err(vm.new_type_error("__hash__ method should return an integer".to_owned())), @@ -263,11 +281,11 @@ fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { } fn call_wrapper(zelf: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResult { - vm.call_special_method(zelf.to_owned(), "__call__", args) + vm.call_special_method(zelf.to_owned(), identifier!(vm, __call__), args) } fn getattro_wrapper(zelf: &PyObject, name: PyStrRef, vm: &VirtualMachine) -> PyResult { - vm.call_special_method(zelf.to_owned(), "__getattribute__", (name,)) + vm.call_special_method(zelf.to_owned(), identifier!(vm, __getattribute__), (name,)) } fn setattro_wrapper( @@ -279,10 +297,10 @@ fn setattro_wrapper( let zelf = zelf.to_owned(); match value { Some(value) => { - vm.call_special_method(zelf, "__setattr__", (name, value))?; + vm.call_special_method(zelf, identifier!(vm, __setattr__), (name, value))?; } None => { - vm.call_special_method(zelf, "__delattr__", (name,))?; + vm.call_special_method(zelf, identifier!(vm, __delattr__), (name,))?; } }; Ok(()) @@ -294,16 +312,23 @@ pub(crate) fn richcompare_wrapper( op: PyComparisonOp, vm: &VirtualMachine, ) -> PyResult> { - vm.call_special_method(zelf.to_owned(), op.method_name(), (other.to_owned(),)) - .map(Either::A) + vm.call_special_method( + zelf.to_owned(), + op.method_name(&vm.ctx), + (other.to_owned(),), + ) + .map(Either::A) } fn iter_wrapper(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult { - vm.call_special_method(zelf, "__iter__", ()) + vm.call_special_method(zelf, identifier!(vm, __iter__), ()) } fn iternext_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { - PyIterReturn::from_pyresult(vm.call_special_method(zelf.to_owned(), "__next__", ()), vm) + PyIterReturn::from_pyresult( + vm.call_special_method(zelf.to_owned(), identifier!(vm, __next__), ()), + vm, + ) } fn descr_get_wrapper( @@ -312,7 +337,7 @@ fn descr_get_wrapper( cls: Option, vm: &VirtualMachine, ) -> PyResult { - vm.call_special_method(zelf, "__get__", (obj, cls)) + vm.call_special_method(zelf, identifier!(vm, __get__), (obj, cls)) } fn descr_set_wrapper( @@ -322,14 +347,14 @@ fn descr_set_wrapper( vm: &VirtualMachine, ) -> PyResult<()> { match value { - Some(val) => vm.call_special_method(zelf, "__set__", (obj, val)), - None => vm.call_special_method(zelf, "__delete__", (obj,)), + Some(val) => vm.call_special_method(zelf, identifier!(vm, __set__), (obj, val)), + None => vm.call_special_method(zelf, identifier!(vm, __delete__), (obj,)), } .map(drop) } fn init_wrapper(obj: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> { - let res = vm.call_special_method(obj, "__init__", args)?; + let res = vm.call_special_method(obj, identifier!(vm, __init__), args)?; if !vm.is_none(&res) { return Err(vm.new_type_error("__init__ must return None".to_owned())); } @@ -337,29 +362,27 @@ fn init_wrapper(obj: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResu } fn new_wrapper(cls: PyTypeRef, mut args: FuncArgs, vm: &VirtualMachine) -> PyResult { - let new = vm - .get_attribute_opt(cls.as_object().to_owned(), "__new__")? - .unwrap(); + let new = cls.get_attr(identifier!(vm, __new__)).unwrap(); args.prepend_arg(cls.into()); vm.invoke(&new, args) } fn del_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> { - vm.call_special_method(zelf.to_owned(), "__del__", ())?; + vm.call_special_method(zelf.to_owned(), identifier!(vm, __del__), ())?; Ok(()) } impl PyType { - pub(crate) fn update_slot(&self, name: &str, add: bool) { - debug_assert!(name.starts_with("__")); - debug_assert!(name.ends_with("__")); + pub(crate) fn update_slot(&self, name: &'static PyStrInterned, add: bool) { + debug_assert!(name.as_str().starts_with("__")); + debug_assert!(name.as_str().ends_with("__")); macro_rules! update_slot { ($name:ident, $func:expr) => {{ self.slots.$name.store(if add { Some($func) } else { None }); }}; } - match name { + match name.as_str() { "__len__" | "__getitem__" | "__setitem__" | "__delitem__" => { update_slot!(as_mapping, as_mapping_wrapper); update_slot!(as_sequence, as_sequence_wrapper); @@ -623,7 +646,10 @@ pub trait Comparable: PyPayload { if let Some(zelf) = zelf.downcast_ref() { Self::cmp(zelf, other, op, vm).map(Either::B) } else { - Err(vm.new_type_error(format!("unexpected payload for {}", op.method_name()))) + Err(vm.new_type_error(format!( + "unexpected payload for {}", + op.method_name(&vm.ctx).as_str() + ))) } } @@ -741,14 +767,14 @@ impl PyComparisonOp { } } - pub fn method_name(self) -> &'static str { + pub fn method_name(self, ctx: &Context) -> &'static PyStrInterned { match self { - Self::Lt => "__lt__", - Self::Le => "__le__", - Self::Eq => "__eq__", - Self::Ne => "__ne__", - Self::Ge => "__ge__", - Self::Gt => "__gt__", + Self::Lt => identifier!(ctx, __lt__), + Self::Le => identifier!(ctx, __le__), + Self::Eq => identifier!(ctx, __eq__), + Self::Ne => identifier!(ctx, __ne__), + Self::Ge => identifier!(ctx, __ge__), + Self::Gt => identifier!(ctx, __gt__), } } diff --git a/vm/src/types/structseq.rs b/vm/src/types/structseq.rs index 01ab762eb1..d3b98a6630 100644 --- a/vm/src/types/structseq.rs +++ b/vm/src/types/structseq.rs @@ -78,11 +78,12 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static { // cast i to a u8 so there's less to store in the getter closure. // Hopefully there's not struct sequences with >=256 elements :P let i = i as u8; - class.set_str_attr( - name, + class.set_attr( + ctx.intern_str(name), ctx.new_readonly_getset(name, class.clone(), move |zelf: &PyTuple| { zelf.fast_getitem(i.into()) - }), + }) + .into(), ); } } diff --git a/vm/src/vm/context.rs b/vm/src/vm/context.rs index 708d621c36..6568578b02 100644 --- a/vm/src/vm/context.rs +++ b/vm/src/vm/context.rs @@ -32,15 +32,181 @@ pub struct Context { pub ellipsis: PyRef, pub not_implemented: PyRef, - pub(crate) true_str: &'static PyStrInterned, - pub(crate) false_str: &'static PyStrInterned, - pub types: TypeZoo, pub exceptions: exceptions::ExceptionZoo, pub int_cache_pool: Vec, // there should only be exact objects of str in here, no non-strs and no subclasses pub(crate) string_pool: StringPool, pub(crate) slot_new_wrapper: PyObjectRef, + pub names: ConstName, +} + +macro_rules! declare_const_name { + ($($name:ident,)*) => { + #[derive(Debug, Clone)] + #[allow(non_snake_case)] + pub struct ConstName { + $(pub $name: &'static PyStrInterned,)* + } + + impl ConstName { + unsafe fn new(pool: &StringPool, typ: &PyTypeRef) -> Self { + Self { + $($name: pool.intern(stringify!($name), typ.clone()),)* + } + } + } + } +} + +declare_const_name! { + True, + False, + + // magic methods + __abs__, + __abstractmethods__, + __add__, + __aenter__, + __aexit__, + __aiter__, + __all__, + __and__, + __anext__, + __annotations__, + __args__, + __await__, + __bases__, + __bool__, + __build_class__, + __builtins__, + __bytes__, + __call__, + __ceil__, + __cformat__, + __class__, + __class_getitem__, + __complex__, + __contains__, + __copy__, + __deepcopy__, + __del__, + __delattr__, + __delete__, + __delitem__, + __dict__, + __dir__, + __div__, + __divmod__, + __doc__, + __enter__, + __eq__, + __exit__, + __file__, + __float__, + __floor__, + __floordiv__, + __format__, + __fspath__, + __ge__, + __get__, + __getattr__, + __getattribute__, + __getitem__, + __gt__, + __hash__, + __iadd__, + __iand__, + __idiv__, + __ifloordiv__, + __ilshift__, + __imatmul__, + __imod__, + __import__, + __imul__, + __index__, + __init__, + __init_subclass__, + __instancecheck__, + __int__, + __invert__, + __ior__, + __ipow__, + __irshift__, + __isub__, + __iter__, + __itruediv__, + __ixor__, + __le__, + __len__, + __length_hint__, + __lshift__, + __lt__, + __main__, + __matmul__, + __missing__, + __mod__, + __module__, + __mro_entries__, + __mul__, + __name__, + __ne__, + __neg__, + __new__, + __next__, + __or__, + __orig_bases__, + __orig_class__, + __origin__, + __parameters__, + __pos__, + __pow__, + __prepare__, + __qualname__, + __radd__, + __rand__, + __rdiv__, + __rdivmod__, + __reduce__, + __reduce_ex__, + __repr__, + __reversed__, + __rfloordiv__, + __rlshift__, + __rmatmul__, + __rmod__, + __rmul__, + __ror__, + __round__, + __rpow__, + __rrshift__, + __rshift__, + __rsub__, + __rtruediv__, + __rxor__, + __set__, + __set_name__, + __setattr__, + __setitem__, + __str__, + __sub__, + __subclasscheck__, + __truediv__, + __trunc__, + __xor__, + + // common names + _attributes, + _fields, + decode, + encode, + keys, + items, + values, + update, + copy, + flush, + close, } // Basic objects: @@ -77,16 +243,15 @@ impl Context { PyRef::new_ref(PyFrozenSet::default(), types.frozenset_type.clone(), None); let string_pool = StringPool::default(); + let names = unsafe { ConstName::new(&string_pool, &types.str_type) }; - let new_str = unsafe { string_pool.intern("__new__", types.str_type.clone()) }; let slot_new_wrapper = create_object( - PyNativeFuncDef::new(PyType::__new__.into_func(), new_str.to_owned()).into_function(), + PyNativeFuncDef::new(PyType::__new__.into_func(), names.__new__.to_owned()) + .into_function(), &types.builtin_function_or_method_type, ) .into(); - let true_str = unsafe { string_pool.intern("True", types.str_type.clone()) }; - let false_str = unsafe { string_pool.intern("False", types.str_type.clone()) }; let empty_str = unsafe { string_pool.intern("", types.str_type.clone()) }.to_owned(); let context = Context { @@ -100,14 +265,12 @@ impl Context { ellipsis, not_implemented, - true_str, - false_str, - types, exceptions, int_cache_pool, string_pool, slot_new_wrapper, + names, }; TypeZoo::extend(&context); exceptions::ExceptionZoo::extend(&context); @@ -219,7 +382,7 @@ impl Context { ) -> PyTypeRef { let mut attrs = PyAttributes::default(); if let Some(module) = module { - attrs.insert("__module__".to_string(), self.new_str(module).into()); + attrs.insert(identifier!(self, __module__), self.new_str(module).into()); }; PyType::new_ref( name, @@ -243,7 +406,7 @@ impl Context { vec![self.exceptions.exception_type.clone()] }; let mut attrs = PyAttributes::default(); - attrs.insert("__module__".to_owned(), self.new_str(module).into()); + attrs.insert(identifier!(self, __module__), self.new_str(module).into()); PyType::new_ref( name, @@ -339,3 +502,9 @@ impl Default for Context { CONTEXT.get_or_init(Self::init).clone() } } + +impl AsRef for Context { + fn as_ref(&self) -> &Self { + self + } +} diff --git a/vm/src/vm/interpreter.rs b/vm/src/vm/interpreter.rs index d1955abc2b..4247a25c1c 100644 --- a/vm/src/vm/interpreter.rs +++ b/vm/src/vm/interpreter.rs @@ -82,10 +82,10 @@ impl Interpreter { fn flush_std(vm: &VirtualMachine) { if let Ok(stdout) = sys::get_stdout(vm) { - let _ = vm.call_method(&stdout, "flush", ()); + let _ = vm.call_method(&stdout, identifier!(vm, flush).as_str(), ()); } if let Ok(stderr) = sys::get_stderr(vm) { - let _ = vm.call_method(&stderr, "flush", ()); + let _ = vm.call_method(&stderr, identifier!(vm, flush).as_str(), ()); } } diff --git a/vm/src/vm/method.rs b/vm/src/vm/method.rs index de8e287472..529b0bcee1 100644 --- a/vm/src/vm/method.rs +++ b/vm/src/vm/method.rs @@ -3,7 +3,7 @@ use super::VirtualMachine; use crate::{ - builtins::{PyBaseObject, PyStrRef}, + builtins::{PyBaseObject, PyStrInterned, PyStrRef}, function::IntoFuncArgs, object::{AsObject, PyObjectRef, PyResult}, types::PyTypeFlags, @@ -27,9 +27,10 @@ impl PyMethod { return obj.get_attr(name, vm).map(Self::Attribute); } + let interned_name = vm.ctx.interned_str(&*name); let mut is_method = false; - let cls_attr = match cls.get_attr(name.as_str()) { + let cls_attr = match interned_name.and_then(|name| cls.get_attr(name)) { Some(descr) => { let descr_cls = descr.class(); let descr_get = if descr_cls.slots.flags.has_feature(PyTypeFlags::METHOD_DESCR) { @@ -76,7 +77,7 @@ impl PyMethod { } None => Ok(Self::Attribute(attr)), } - } else if let Some(getter) = cls.get_attr("__getattr__") { + } else if let Some(getter) = cls.get_attr(identifier!(vm, __getattr__)) { drop(cls); vm.invoke(&getter, (obj, name)).map(Self::Attribute) } else { @@ -92,7 +93,7 @@ impl PyMethod { pub(crate) fn get_special( obj: PyObjectRef, - name: &str, + name: &'static PyStrInterned, vm: &VirtualMachine, ) -> PyResult> { let obj_cls = obj.class(); diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index 87e4ac22d8..450fffa9c2 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -19,7 +19,7 @@ use crate::{ code::PyCode, pystr::IntoPyStrRef, tuple::{PyTuple, PyTupleTyped}, - PyBaseExceptionRef, PyDictRef, PyInt, PyList, PyModule, PyStrRef, PyTypeRef, + PyBaseExceptionRef, PyDictRef, PyInt, PyList, PyModule, PyStrInterned, PyStrRef, PyTypeRef, }, bytecode, codecs::CodecsRegistry, @@ -425,13 +425,13 @@ impl VirtualMachine { } } None => { - let import_func = - self.builtins - .clone() - .get_attr("__import__", self) - .map_err(|_| { - self.new_import_error("__import__ not found".to_owned(), module.clone()) - })?; + let import_func = self + .builtins + .clone() + .get_attr(identifier!(self, __import__), self) + .map_err(|_| { + self.new_import_error("__import__ not found".to_owned(), module.clone()) + })?; let (locals, globals) = if let Some(frame) = self.current_frame() { (Some(frame.locals.clone()), Some(frame.globals.clone())) @@ -559,7 +559,7 @@ impl VirtualMachine { pub fn get_method_or_type_error( &self, obj: PyObjectRef, - method_name: &str, + method_name: &'static PyStrInterned, err_msg: F, ) -> PyResult where @@ -573,11 +573,20 @@ impl VirtualMachine { } // TODO: remove + transfer over to get_special_method - pub(crate) fn get_method(&self, obj: PyObjectRef, method_name: &str) -> Option { + pub(crate) fn get_method( + &self, + obj: PyObjectRef, + method_name: &'static PyStrInterned, + ) -> Option { let method = obj.get_class_attr(method_name)?; Some(self.call_if_get_descriptor(method, obj)) } + pub(crate) fn get_str_method(&self, obj: PyObjectRef, method_name: &str) -> Option { + let method_name = self.ctx.interned_str(method_name)?; + self.get_method(obj, method_name) + } + pub fn is_callable(&self, obj: &PyObject) -> bool { obj.class() .mro_find_map(|cls| cls.slots.call.load()) @@ -706,7 +715,10 @@ impl VirtualMachine { self.insert_sys_path(self.new_pyobj(path))?; let runpy = self.import("runpy", None, 0)?; let run_module_as_main = runpy.get_attr("_run_module_as_main", self)?; - self.invoke(&run_module_as_main, (self.ctx.new_str("__main__"), false))?; + self.invoke( + &run_module_as_main, + (identifier!(self, __main__).to_owned(), false), + )?; return Ok(()); } @@ -734,9 +746,11 @@ impl VirtualMachine { .compile(source, crate::compile::Mode::Exec, source_path.clone()) .map_err(|err| self.new_syntax_error(&err))?; // trace!("Code object: {:?}", code_obj.borrow()); - scope - .globals - .set_item("__file__", self.new_pyobj(source_path), self)?; + scope.globals.set_item( + identifier!(self, __file__), + self.new_pyobj(source_path), + self, + )?; self.run_code_obj(code_obj, scope) } @@ -775,3 +789,9 @@ fn get_importer(path: &str, vm: &VirtualMachine) -> PyResult None }) } + +impl AsRef for VirtualMachine { + fn as_ref(&self) -> &Context { + &self.ctx + } +} diff --git a/vm/src/vm/vm_object.rs b/vm/src/vm/vm_object.rs index 4c98a4c08e..1aba5e4ad2 100644 --- a/vm/src/vm/vm_object.rs +++ b/vm/src/vm/vm_object.rs @@ -1,7 +1,8 @@ use super::PyMethod; use crate::{ - builtins::{PyBaseExceptionRef, PyList, PyStr}, + builtins::{PyBaseExceptionRef, PyList, PyStr, PyStrInterned}, function::{FuncArgs, IntoFuncArgs}, + identifier, object::{AsObject, PyObject, PyObjectRef, PyPayload, PyResult}, vm::VirtualMachine, }; @@ -118,21 +119,24 @@ impl VirtualMachine { { flame_guard!(format!("call_method({:?})", method_name)); - PyMethod::get( - obj.to_owned(), - PyStr::from(method_name).into_ref(self), - self, - )? - .invoke(args, self) + let name = self + .ctx + .interned_str(method_name) + .map_or_else(|| PyStr::from(method_name).into_ref(self), |s| s.to_owned()); + PyMethod::get(obj.to_owned(), name, self)?.invoke(args, self) } pub fn dir(&self, obj: Option) -> PyResult { let seq = match obj { Some(obj) => self - .get_special_method(obj, "__dir__")? + .get_special_method(obj, identifier!(self, __dir__))? .map_err(|_obj| self.new_type_error("object does not provide __dir__".to_owned()))? .invoke((), self)?, - None => self.call_method(self.current_locals()?.as_object(), "keys", ())?, + None => self.call_method( + self.current_locals()?.as_object(), + identifier!(self, keys).as_str(), + (), + )?, }; let items: Vec<_> = seq.try_to_value(self)?; let lst = PyList::from(items); @@ -144,7 +148,7 @@ impl VirtualMachine { pub(crate) fn get_special_method( &self, obj: PyObjectRef, - method: &str, + method: &'static PyStrInterned, ) -> PyResult> { PyMethod::get_special(obj, method, self) } @@ -154,11 +158,11 @@ impl VirtualMachine { pub fn call_special_method( &self, obj: PyObjectRef, - method: &str, + method: &'static PyStrInterned, args: impl IntoFuncArgs, ) -> PyResult { self.get_special_method(obj, method)? - .map_err(|_obj| self.new_attribute_error(method.to_owned()))? + .map_err(|_obj| self.new_attribute_error(method.as_str().to_owned()))? .invoke(args, self) } diff --git a/vm/src/vm/vm_ops.rs b/vm/src/vm/vm_ops.rs index dc10479a24..b509561bab 100644 --- a/vm/src/vm/vm_ops.rs +++ b/vm/src/vm/vm_ops.rs @@ -1,6 +1,6 @@ use super::{PyMethod, VirtualMachine}; use crate::{ - builtins::{PyInt, PyIntRef}, + builtins::{PyInt, PyIntRef, PyStrInterned}, function::PyArithmeticValue, object::{AsObject, PyObject, PyObjectRef, PyResult}, protocol::PyIterReturn, @@ -12,15 +12,17 @@ impl VirtualMachine { pub fn to_index_opt(&self, obj: PyObjectRef) -> Option> { match obj.downcast() { Ok(val) => Some(Ok(val)), - Err(obj) => self.get_method(obj, "__index__").map(|index| { - // TODO: returning strict subclasses of int in __index__ is deprecated - self.invoke(&index?, ())?.downcast().map_err(|bad| { - self.new_type_error(format!( - "__index__ returned non-int (type {})", - bad.class().name() - )) - }) - }), + Err(obj) => self + .get_method(obj, identifier!(self, __index__)) + .map(|index| { + // TODO: returning strict subclasses of int in __index__ is deprecated + self.invoke(&index?, ())?.downcast().map_err(|bad| { + self.new_type_error(format!( + "__index__ returned non-int (type {})", + bad.class().name() + )) + }) + }), } } @@ -77,7 +79,7 @@ impl VirtualMachine { } } } - let hint = match self.get_method(iter, "__length_hint__") { + let hint = match self.get_method(iter, identifier!(self, __length_hint__)) { Some(hint) => hint?, None => return Ok(None), }; @@ -135,7 +137,7 @@ impl VirtualMachine { &self, obj: &PyObject, arg: &PyObject, - method: &str, + method: &'static PyStrInterned, unsupported: F, ) -> PyResult where @@ -166,8 +168,8 @@ impl VirtualMachine { &self, lhs: &PyObject, rhs: &PyObject, - default: &str, - reflection: &str, + default: &'static PyStrInterned, + reflection: &'static PyStrInterned, unsupported: fn(&VirtualMachine, &PyObject, &PyObject) -> PyResult, ) -> PyResult { if rhs.fast_isinstance(&lhs.class()) { @@ -199,213 +201,321 @@ impl VirtualMachine { } pub fn _sub(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_reflection(a, b, "__sub__", "__rsub__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "-")) - }) + self.call_or_reflection( + a, + b, + identifier!(self, __sub__), + identifier!(self, __rsub__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "-")), + ) } pub fn _isub(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_unsupported(a, b, "__isub__", |vm, a, b| { - vm.call_or_reflection(a, b, "__sub__", "__rsub__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "-=")) - }) + self.call_or_unsupported(a, b, identifier!(self, __isub__), |vm, a, b| { + vm.call_or_reflection( + a, + b, + identifier!(self, __sub__), + identifier!(self, __rsub__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "-=")), + ) }) } pub fn _add(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_reflection(a, b, "__add__", "__radd__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "+")) - }) + self.call_or_reflection( + a, + b, + identifier!(self, __add__), + identifier!(self, __radd__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "+")), + ) } pub fn _iadd(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_unsupported(a, b, "__iadd__", |vm, a, b| { - vm.call_or_reflection(a, b, "__add__", "__radd__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "+=")) - }) + self.call_or_unsupported(a, b, identifier!(self, __iadd__), |vm, a, b| { + vm.call_or_reflection( + a, + b, + identifier!(self, __add__), + identifier!(self, __radd__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "+=")), + ) }) } pub fn _mul(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_reflection(a, b, "__mul__", "__rmul__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "*")) - }) + self.call_or_reflection( + a, + b, + identifier!(self, __mul__), + identifier!(self, __rmul__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "*")), + ) } pub fn _imul(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_unsupported(a, b, "__imul__", |vm, a, b| { - vm.call_or_reflection(a, b, "__mul__", "__rmul__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "*=")) - }) + self.call_or_unsupported(a, b, identifier!(self, __imul__), |vm, a, b| { + vm.call_or_reflection( + a, + b, + identifier!(self, __mul__), + identifier!(self, __rmul__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "*=")), + ) }) } pub fn _matmul(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_reflection(a, b, "__matmul__", "__rmatmul__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "@")) - }) + self.call_or_reflection( + a, + b, + identifier!(self, __matmul__), + identifier!(self, __rmatmul__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "@")), + ) } pub fn _imatmul(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_unsupported(a, b, "__imatmul__", |vm, a, b| { - vm.call_or_reflection(a, b, "__matmul__", "__rmatmul__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "@=")) - }) + self.call_or_unsupported(a, b, identifier!(self, __imatmul__), |vm, a, b| { + vm.call_or_reflection( + a, + b, + identifier!(self, __matmul__), + identifier!(self, __rmatmul__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "@=")), + ) }) } pub fn _truediv(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_reflection(a, b, "__truediv__", "__rtruediv__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "/")) - }) + self.call_or_reflection( + a, + b, + identifier!(self, __truediv__), + identifier!(self, __rtruediv__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "/")), + ) } pub fn _itruediv(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_unsupported(a, b, "__itruediv__", |vm, a, b| { - vm.call_or_reflection(a, b, "__truediv__", "__rtruediv__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "/=")) - }) + self.call_or_unsupported(a, b, identifier!(self, __itruediv__), |vm, a, b| { + vm.call_or_reflection( + a, + b, + identifier!(self, __truediv__), + identifier!(self, __rtruediv__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "/=")), + ) }) } pub fn _floordiv(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_reflection(a, b, "__floordiv__", "__rfloordiv__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "//")) - }) + self.call_or_reflection( + a, + b, + identifier!(self, __floordiv__), + identifier!(self, __rfloordiv__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "//")), + ) } pub fn _ifloordiv(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_unsupported(a, b, "__ifloordiv__", |vm, a, b| { - vm.call_or_reflection(a, b, "__floordiv__", "__rfloordiv__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "//=")) - }) + self.call_or_unsupported(a, b, identifier!(self, __ifloordiv__), |vm, a, b| { + vm.call_or_reflection( + a, + b, + identifier!(self, __floordiv__), + identifier!(self, __rfloordiv__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "//=")), + ) }) } pub fn _pow(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_reflection(a, b, "__pow__", "__rpow__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "**")) - }) + self.call_or_reflection( + a, + b, + identifier!(self, __pow__), + identifier!(self, __rpow__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "**")), + ) } pub fn _ipow(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_unsupported(a, b, "__ipow__", |vm, a, b| { - vm.call_or_reflection(a, b, "__pow__", "__rpow__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "**=")) - }) + self.call_or_unsupported(a, b, identifier!(self, __ipow__), |vm, a, b| { + vm.call_or_reflection( + a, + b, + identifier!(self, __pow__), + identifier!(self, __rpow__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "**=")), + ) }) } pub fn _mod(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_reflection(a, b, "__mod__", "__rmod__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "%")) - }) + self.call_or_reflection( + a, + b, + identifier!(self, __mod__), + identifier!(self, __rmod__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "%")), + ) } pub fn _imod(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_unsupported(a, b, "__imod__", |vm, a, b| { - vm.call_or_reflection(a, b, "__mod__", "__rmod__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "%=")) - }) + self.call_or_unsupported(a, b, identifier!(self, __imod__), |vm, a, b| { + vm.call_or_reflection( + a, + b, + identifier!(self, __mod__), + identifier!(self, __rmod__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "%=")), + ) }) } pub fn _divmod(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_reflection(a, b, "__divmod__", "__rdivmod__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "divmod")) - }) + self.call_or_reflection( + a, + b, + identifier!(self, __divmod__), + identifier!(self, __rdivmod__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "divmod")), + ) } pub fn _lshift(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_reflection(a, b, "__lshift__", "__rlshift__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "<<")) - }) + self.call_or_reflection( + a, + b, + identifier!(self, __lshift__), + identifier!(self, __rlshift__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "<<")), + ) } pub fn _ilshift(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_unsupported(a, b, "__ilshift__", |vm, a, b| { - vm.call_or_reflection(a, b, "__lshift__", "__rlshift__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "<<=")) - }) + self.call_or_unsupported(a, b, identifier!(self, __ilshift__), |vm, a, b| { + vm.call_or_reflection( + a, + b, + identifier!(self, __lshift__), + identifier!(self, __rlshift__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "<<=")), + ) }) } pub fn _rshift(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_reflection(a, b, "__rshift__", "__rrshift__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, ">>")) - }) + self.call_or_reflection( + a, + b, + identifier!(self, __rshift__), + identifier!(self, __rrshift__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, ">>")), + ) } pub fn _irshift(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_unsupported(a, b, "__irshift__", |vm, a, b| { - vm.call_or_reflection(a, b, "__rshift__", "__rrshift__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, ">>=")) - }) + self.call_or_unsupported(a, b, identifier!(self, __irshift__), |vm, a, b| { + vm.call_or_reflection( + a, + b, + identifier!(self, __rshift__), + identifier!(self, __rrshift__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, ">>=")), + ) }) } pub fn _xor(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_reflection(a, b, "__xor__", "__rxor__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "^")) - }) + self.call_or_reflection( + a, + b, + identifier!(self, __xor__), + identifier!(self, __rxor__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "^")), + ) } pub fn _ixor(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_unsupported(a, b, "__ixor__", |vm, a, b| { - vm.call_or_reflection(a, b, "__xor__", "__rxor__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "^=")) - }) + self.call_or_unsupported(a, b, identifier!(self, __ixor__), |vm, a, b| { + vm.call_or_reflection( + a, + b, + identifier!(self, __xor__), + identifier!(self, __rxor__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "^=")), + ) }) } pub fn _or(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_reflection(a, b, "__or__", "__ror__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "|")) - }) + self.call_or_reflection( + a, + b, + identifier!(self, __or__), + identifier!(self, __ror__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "|")), + ) } pub fn _ior(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_unsupported(a, b, "__ior__", |vm, a, b| { - vm.call_or_reflection(a, b, "__or__", "__ror__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "|=")) - }) + self.call_or_unsupported(a, b, identifier!(self, __ior__), |vm, a, b| { + vm.call_or_reflection( + a, + b, + identifier!(self, __or__), + identifier!(self, __ror__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "|=")), + ) }) } pub fn _and(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_reflection(a, b, "__and__", "__rand__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "&")) - }) + self.call_or_reflection( + a, + b, + identifier!(self, __and__), + identifier!(self, __rand__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "&")), + ) } pub fn _iand(&self, a: &PyObject, b: &PyObject) -> PyResult { - self.call_or_unsupported(a, b, "__iand__", |vm, a, b| { - vm.call_or_reflection(a, b, "__and__", "__rand__", |vm, a, b| { - Err(vm.new_unsupported_binop_error(a, b, "&=")) - }) + self.call_or_unsupported(a, b, identifier!(self, __iand__), |vm, a, b| { + vm.call_or_reflection( + a, + b, + identifier!(self, __and__), + identifier!(self, __rand__), + |vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "&=")), + ) }) } pub fn _abs(&self, a: &PyObject) -> PyResult { - self.get_special_method(a.to_owned(), "__abs__")? + self.get_special_method(a.to_owned(), identifier!(self, __abs__))? .map_err(|_| self.new_unsupported_unary_error(a, "abs()"))? .invoke((), self) } pub fn _pos(&self, a: &PyObject) -> PyResult { - self.get_special_method(a.to_owned(), "__pos__")? + self.get_special_method(a.to_owned(), identifier!(self, __pos__))? .map_err(|_| self.new_unsupported_unary_error(a, "unary +"))? .invoke((), self) } pub fn _neg(&self, a: &PyObject) -> PyResult { - self.get_special_method(a.to_owned(), "__neg__")? + self.get_special_method(a.to_owned(), identifier!(self, __neg__))? .map_err(|_| self.new_unsupported_unary_error(a, "unary -"))? .invoke((), self) } pub fn _invert(&self, a: &PyObject) -> PyResult { - self.get_special_method(a.to_owned(), "__invert__")? + self.get_special_method(a.to_owned(), identifier!(self, __invert__))? .map_err(|_| self.new_unsupported_unary_error(a, "unary ~"))? .invoke((), self) } @@ -431,7 +541,7 @@ impl VirtualMachine { } pub fn _contains(&self, haystack: PyObjectRef, needle: PyObjectRef) -> PyResult { - match PyMethod::get_special(haystack, "__contains__", self)? { + match PyMethod::get_special(haystack, identifier!(self, __contains__), self)? { Ok(method) => method.invoke((needle,), self), Err(haystack) => self ._membership_iter_search(haystack, needle) From 2a1c02b8e0b60ab80cba29145e86e87b165763cc Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Thu, 12 May 2022 11:46:29 +0900 Subject: [PATCH 5/9] module init --- vm/src/builtins/module.rs | 17 +++++++++++------ vm/src/builtins/object.rs | 12 ++++-------- vm/src/import.rs | 14 +++++++++++--- vm/src/vm/mod.rs | 11 ++++------- vm/src/vm/vm_new.rs | 2 +- 5 files changed, 31 insertions(+), 25 deletions(-) diff --git a/vm/src/builtins/module.rs b/vm/src/builtins/module.rs index 239a2107e7..7831ebe358 100644 --- a/vm/src/builtins/module.rs +++ b/vm/src/builtins/module.rs @@ -1,6 +1,7 @@ use super::pystr::IntoPyStrRef; use super::{PyDictRef, PyStr, PyStrRef, PyTypeRef}; use crate::{ + builtins::PyStrInterned, class::PyClassImpl, convert::ToPyObject, function::FuncArgs, @@ -48,7 +49,7 @@ impl PyModule { { return Ok(attr); } - if let Ok(getattr) = zelf.dict().get_item("__getattr__", vm) { + if let Ok(getattr) = zelf.dict().get_item(identifier!(vm, __getattr__), vm) { return vm.invoke(&getattr, (name,)); } let module_name = if let Some(name) = Self::name(zelf.to_owned(), vm) { @@ -61,7 +62,7 @@ impl PyModule { fn name(zelf: PyRef, vm: &VirtualMachine) -> Option { zelf.as_object() - .generic_getattr_opt(PyStr::from("__name__").into_ref(vm), None, vm) + .generic_getattr_opt(identifier!(vm, __name__).to_owned(), None, vm) .unwrap_or(None) .and_then(|obj| obj.downcast::().ok()) } @@ -92,14 +93,14 @@ impl Py { // TODO: should be on PyModule, not Py pub(crate) fn init_module_dict( &self, - name: PyObjectRef, + name: &'static PyStrInterned, doc: PyObjectRef, vm: &VirtualMachine, ) { let dict = self.dict(); - dict.set_item("__name__", name, vm) + dict.set_item(identifier!(vm, __name__), name.to_object(), vm) .expect("Failed to set __name__ on module"); - dict.set_item("__doc__", doc, vm) + dict.set_item(identifier!(vm, __doc__), doc, vm) .expect("Failed to set __doc__ on module"); dict.set_item("__package__", vm.ctx.none(), vm) .expect("Failed to set __package__ on module"); @@ -131,7 +132,11 @@ impl Initializer for PyModule { .slots .flags .has_feature(crate::types::PyTypeFlags::HAS_DICT)); - zelf.init_module_dict(args.name.into(), args.doc.to_pyobject(vm), vm); + zelf.init_module_dict( + vm.ctx.intern_str(args.name.as_str()), + args.doc.to_pyobject(vm), + vm, + ); Ok(()) } } diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index ad4fd7e5fc..d6ec8b22e3 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -309,15 +309,11 @@ impl PyBaseObject { #[pymethod(magic)] fn reduce_ex(obj: PyObjectRef, proto: usize, vm: &VirtualMachine) -> PyResult { - if let Some(reduce) = vm.get_attribute_opt(obj.clone(), identifier!(vm, __reduce__))? { - let object_reduce = vm - .ctx - .types - .object_type - .get_attr(identifier!(vm, __reduce__)) - .unwrap(); + let __reduce__ = identifier!(vm, __reduce__); + if let Some(reduce) = vm.get_attribute_opt(obj.clone(), __reduce__)? { + let object_reduce = vm.ctx.types.object_type.get_attr(__reduce__).unwrap(); let typ_obj: PyObjectRef = obj.class().clone().into(); - let class_reduce = typ_obj.get_attr(identifier!(vm, __reduce__), vm)?; + let class_reduce = typ_obj.get_attr(__reduce__, vm)?; if !class_reduce.is(&object_reduce) { return vm.invoke(&reduce, ()); } diff --git a/vm/src/import.rs b/vm/src/import.rs index da37c6517b..7b9075acde 100644 --- a/vm/src/import.rs +++ b/vm/src/import.rs @@ -40,7 +40,7 @@ pub(crate) fn init_importlib_base(vm: &mut VirtualMachine) -> PyResult PyResult { let attrs = vm.ctx.new_dict(); - attrs.set_item("__name__", vm.ctx.new_str(module_name).into(), vm)?; + attrs.set_item( + identifier!(vm, __name__), + vm.ctx.new_str(module_name).into(), + vm, + )?; if set_file_attr { - attrs.set_item("__file__", code_obj.source_path.clone().into(), vm)?; + attrs.set_item( + identifier!(vm, __file__), + code_obj.source_path.clone().into(), + vm, + )?; } let module = vm.new_module(module_name, attrs.clone(), None); diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index 450fffa9c2..47c97adbd9 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -23,7 +23,7 @@ use crate::{ }, bytecode, codecs::CodecsRegistry, - common::{ascii, hash::HashSecret, lock::PyMutex, rc::PyRc}, + common::{hash::HashSecret, lock::PyMutex, rc::PyRc}, convert::{ToPyObject, TryFromObject}, frame::{ExecutionResult, Frame, FrameRef}, frozen, @@ -160,13 +160,10 @@ impl VirtualMachine { let frozen = frozen::get_module_inits().collect(); PyRc::get_mut(&mut vm.state).unwrap().frozen = frozen; - vm.builtins.init_module_dict( - vm.ctx.new_str(ascii!("builtins")).into(), - vm.ctx.none(), - &vm, - ); + vm.builtins + .init_module_dict(vm.ctx.intern_str("builtins"), vm.ctx.none(), &vm); vm.sys_module - .init_module_dict(vm.ctx.new_str(ascii!("sys")).into(), vm.ctx.none(), &vm); + .init_module_dict(vm.ctx.intern_str("sys"), vm.ctx.none(), &vm); vm } diff --git a/vm/src/vm/vm_new.rs b/vm/src/vm/vm_new.rs index 5d4c7d1059..6bd7105762 100644 --- a/vm/src/vm/vm_new.rs +++ b/vm/src/vm/vm_new.rs @@ -34,7 +34,7 @@ impl VirtualMachine { pub fn new_module(&self, name: &str, dict: PyDictRef, doc: Option<&str>) -> PyObjectRef { let module = PyRef::new_ref(PyModule {}, self.ctx.types.module_type.clone(), Some(dict)); module.init_module_dict( - self.new_pyobj(name.to_owned()), + self.ctx.intern_str(name), doc.map(|doc| self.new_pyobj(doc.to_owned())) .unwrap_or_else(|| self.ctx.none()), self, From 42c7c79031151fe966bdbf43257069a8342a6b50 Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Sat, 14 May 2022 11:42:40 +0900 Subject: [PATCH 6/9] Rename Context::deault to genesis to clarify it has root --- vm/src/builtins/type.rs | 2 +- vm/src/object/core.rs | 2 +- vm/src/vm/context.rs | 23 +++++++++++------------ vm/src/vm/interpreter.rs | 5 +++-- vm/src/vm/mod.rs | 5 ++--- 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 777a9f5932..dce8a5874f 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -964,7 +964,7 @@ mod tests { #[test] fn test_linearise() { - let context = Context::default(); + let context = Context::genesis(); let object = &context.types.object_type; let type_type = &context.types.type_type; diff --git a/vm/src/object/core.rs b/vm/src/object/core.rs index 1fedb708cb..9e251d5e14 100644 --- a/vm/src/object/core.rs +++ b/vm/src/object/core.rs @@ -1196,7 +1196,7 @@ mod tests { #[test] fn miri_test_drop() { - let ctx = crate::Context::default(); + let ctx = crate::Context::genesis(); let obj = ctx.new_bytes(b"dfghjkl".to_vec()); drop(obj); } diff --git a/vm/src/vm/context.rs b/vm/src/vm/context.rs index 6568578b02..501f7549cc 100644 --- a/vm/src/vm/context.rs +++ b/vm/src/vm/context.rs @@ -11,6 +11,7 @@ use crate::{ PyTupleRef, PyType, PyTypeRef, }, class::{PyClassImpl, StaticType}, + common::rc::PyRc, exceptions, function::IntoPyNativeFunc, intern::{Internable, MaybeInterned, StringPool}, @@ -21,7 +22,7 @@ use num_bigint::BigInt; use num_complex::Complex64; use num_traits::ToPrimitive; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Context { pub true_value: PyIntRef, pub false_value: PyIntRef, @@ -43,7 +44,7 @@ pub struct Context { macro_rules! declare_const_name { ($($name:ident,)*) => { - #[derive(Debug, Clone)] + #[derive(Debug, Clone, Copy)] #[allow(non_snake_case)] pub struct ConstName { $(pub $name: &'static PyStrInterned,)* @@ -214,7 +215,14 @@ impl Context { pub const INT_CACHE_POOL_MIN: i32 = -5; pub const INT_CACHE_POOL_MAX: i32 = 256; - fn init() -> Self { + pub fn genesis() -> &'static PyRc { + rustpython_common::static_cell! { + static CONTEXT: PyRc; + } + CONTEXT.get_or_init(|| PyRc::new(Self::init_genesis())) + } + + fn init_genesis() -> Self { flame_guard!("init Context"); let types = TypeZoo::init(); let exceptions = exceptions::ExceptionZoo::init(); @@ -494,15 +502,6 @@ impl Context { } } -impl Default for Context { - fn default() -> Self { - rustpython_common::static_cell! { - static CONTEXT: Context; - } - CONTEXT.get_or_init(Self::init).clone() - } -} - impl AsRef for Context { fn as_ref(&self) -> &Self { self diff --git a/vm/src/vm/interpreter.rs b/vm/src/vm/interpreter.rs index 4247a25c1c..2f70ec6aa7 100644 --- a/vm/src/vm/interpreter.rs +++ b/vm/src/vm/interpreter.rs @@ -1,4 +1,4 @@ -use super::{setting::Settings, thread, VirtualMachine}; +use super::{setting::Settings, thread, Context, VirtualMachine}; use crate::{ stdlib::{atexit, sys}, PyResult, @@ -44,7 +44,8 @@ impl Interpreter { where F: FnOnce(&mut VirtualMachine), { - let mut vm = VirtualMachine::new(settings); + let ctx = Context::genesis(); + let mut vm = VirtualMachine::new(settings, ctx.clone()); init(&mut vm); vm.initialize(); Self { vm } diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index 47c97adbd9..c3e0723ceb 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -90,9 +90,8 @@ pub struct PyGlobalState { impl VirtualMachine { /// Create a new `VirtualMachine` structure. - fn new(settings: Settings) -> VirtualMachine { + fn new(settings: Settings, ctx: PyRc) -> VirtualMachine { flame_guard!("new VirtualMachine"); - let ctx = Context::default(); // make a new module without access to the vm; doesn't // set __spec__, __loader__, etc. attributes @@ -131,7 +130,7 @@ impl VirtualMachine { let mut vm = VirtualMachine { builtins, sys_module, - ctx: PyRc::new(ctx), + ctx, frames: RefCell::new(vec![]), wasm_id: None, exceptions: RefCell::default(), From 7105073c91f2a4f876119b4d716c72eabbd0934f Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Tue, 17 May 2022 05:44:34 +0900 Subject: [PATCH 7/9] shared hash seed in process --- common/src/hash.rs | 5 +++-- vm/src/vm/mod.rs | 13 ++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/common/src/hash.rs b/common/src/hash.rs index c3f13e74d5..ba3d6048a5 100644 --- a/common/src/hash.rs +++ b/common/src/hash.rs @@ -54,8 +54,9 @@ impl HashSecret { pub fn new(seed: u32) -> Self { let mut buf = [0u8; 16]; lcg_urandom(seed, &mut buf); - let k0 = u64::from_le_bytes(buf[..8].try_into().unwrap()); - let k1 = u64::from_le_bytes(buf[8..].try_into().unwrap()); + let (left, right) = buf.split_at(8); + let k0 = u64::from_le_bytes(left.try_into().unwrap()); + let k1 = u64::from_le_bytes(right.try_into().unwrap()); Self { k0, k1 } } } diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index c3e0723ceb..f96ad7f449 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -88,6 +88,12 @@ pub struct PyGlobalState { pub codec_registry: CodecsRegistry, } +pub fn process_hash_secret_seed() -> u32 { + use once_cell::sync::OnceCell; + static SEED: OnceCell = OnceCell::new(); + *SEED.get_or_init(rand::random) +} + impl VirtualMachine { /// Create a new `VirtualMachine` structure. fn new(settings: Settings, ctx: PyRc) -> VirtualMachine { @@ -120,10 +126,11 @@ impl VirtualMachine { let module_inits = stdlib::get_module_inits(); - let hash_secret = match settings.hash_seed { - Some(seed) => HashSecret::new(seed), - None => rand::random(), + let seed = match settings.hash_seed { + Some(seed) => seed, + None => process_hash_secret_seed(), }; + let hash_secret = HashSecret::new(seed); let codec_registry = CodecsRegistry::new(&ctx); From 0f2e879d69cc6236d78f62820dcbc40327c82abe Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Tue, 17 May 2022 06:03:20 +0900 Subject: [PATCH 8/9] panic for not process-unique hash seed --- vm/src/vm/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index f96ad7f449..b3f125bc74 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -163,6 +163,16 @@ impl VirtualMachine { recursion_depth: Cell::new(0), }; + if vm.state.hash_secret.hash_str("") + != vm + .ctx + .interned_str("") + .expect("empty str must be interned") + .hash(&vm) + { + panic!("Interpreters in same process must share the hash seed"); + } + let frozen = frozen::get_module_inits().collect(); PyRc::get_mut(&mut vm.state).unwrap().frozen = frozen; From 14e4aee7b7a78d931c5365ca791de018ac5786dc Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Tue, 17 May 2022 08:10:28 +0900 Subject: [PATCH 9/9] Turn contants to PyStrInterned --- vm/src/builtins/code.rs | 18 ++++---- vm/src/builtins/function.rs | 2 +- vm/src/builtins/function/jitfunc.rs | 4 +- vm/src/frame.rs | 64 +++++++++++++++-------------- vm/src/import.rs | 2 +- vm/src/vm/vm_new.rs | 7 +--- 6 files changed, 46 insertions(+), 51 deletions(-) diff --git a/vm/src/builtins/code.rs b/vm/src/builtins/code.rs index d9205982e7..84945069f3 100644 --- a/vm/src/builtins/code.rs +++ b/vm/src/builtins/code.rs @@ -4,6 +4,7 @@ use super::{PyStrRef, PyTupleRef, PyTypeRef}; use crate::{ + builtins::PyStrInterned, bytecode::{self, BorrowedConstant, Constant, ConstantBag}, class::{PyClassImpl, StaticType}, convert::ToPyObject, @@ -63,7 +64,7 @@ fn borrow_obj_constant(obj: &PyObject) -> BorrowedConstant { } impl Constant for Literal { - type Name = PyStrRef; + type Name = &'static PyStrInterned; fn borrow_constant(&self) -> BorrowedConstant { borrow_obj_constant(&self.0) } @@ -103,8 +104,8 @@ impl ConstantBag for PyObjBag<'_> { Literal(obj) } - fn make_name(&self, name: &str) -> PyStrRef { - self.0.intern_str(name).to_owned() + fn make_name(&self, name: &str) -> &'static PyStrInterned { + self.0.intern_str(name) } } @@ -190,7 +191,7 @@ impl PyRef { #[pyproperty] fn co_filename(self) -> PyStrRef { - self.code.source_path.clone() + self.code.source_path.to_owned() } #[pyproperty] @@ -211,7 +212,7 @@ impl PyRef { #[pyproperty] fn co_name(self) -> PyStrRef { - self.code.obj_name.clone() + self.code.obj_name.to_owned() } #[pyproperty] @@ -221,12 +222,7 @@ impl PyRef { #[pyproperty] pub fn co_varnames(self, vm: &VirtualMachine) -> PyTupleRef { - let varnames = self - .code - .varnames - .iter() - .map(|s| s.clone().into()) - .collect(); + let varnames = self.code.varnames.iter().map(|s| s.to_object()).collect(); vm.ctx.new_tuple(varnames) } } diff --git a/vm/src/builtins/function.rs b/vm/src/builtins/function.rs index de0ae96f93..17cc898940 100644 --- a/vm/src/builtins/function.rs +++ b/vm/src/builtins/function.rs @@ -42,7 +42,7 @@ impl PyFunction { defaults: Option, kw_only_defaults: Option, ) -> Self { - let name = PyMutex::new(code.obj_name.clone()); + let name = PyMutex::new(code.obj_name.to_owned()); PyFunction { code, globals, diff --git a/vm/src/builtins/function/jitfunc.rs b/vm/src/builtins/function/jitfunc.rs index 6d7f4ddb08..7e5d34c3c4 100644 --- a/vm/src/builtins/function/jitfunc.rs +++ b/vm/src/builtins/function/jitfunc.rs @@ -1,5 +1,5 @@ use crate::{ - builtins::{bool_, float, int, PyBaseExceptionRef, PyDictRef, PyFunction, PyStrRef}, + builtins::{bool_, float, int, PyBaseExceptionRef, PyDictRef, PyFunction, PyStrInterned}, bytecode::CodeFlags, convert::ToPyObject, function::FuncArgs, @@ -153,7 +153,7 @@ pub(crate) fn get_jit_args<'a>( // Handle keyword arguments for (name, value) in &func_args.kwargs { let arg_pos = - |args: &[PyStrRef], name: &str| args.iter().position(|arg| arg.as_str() == name); + |args: &[&PyStrInterned], name: &str| args.iter().position(|arg| arg.as_str() == name); if let Some(arg_idx) = arg_pos(arg_names.args, name) { if jit_args.is_set(arg_idx) { return Err(ArgsError::ArgPassedMultipleTimes); diff --git a/vm/src/frame.rs b/vm/src/frame.rs index ee95475471..614db82661 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -5,7 +5,7 @@ use crate::{ function::{PyCell, PyCellRef, PyFunction}, tuple::{PyTuple, PyTupleTyped}, PyBaseExceptionRef, PyCode, PyCoroutine, PyDict, PyDictRef, PyGenerator, PyList, PySet, - PySlice, PyStr, PyStrRef, PyTraceback, PyTypeRef, + PySlice, PyStr, PyStrInterned, PyStrRef, PyTraceback, PyTypeRef, }, bytecode, convert::{IntoObject, ToPyResult}, @@ -187,7 +187,7 @@ impl FrameRef { let j = std::cmp::min(map.len(), code.varnames.len()); if !code.varnames.is_empty() { let fastlocals = self.fastlocals.lock(); - for (k, v) in itertools::zip(&map[..j], &**fastlocals) { + for (&k, v) in itertools::zip(&map[..j], &**fastlocals) { match locals.mapping().ass_subscript(k, v.clone(), vm) { Ok(()) => {} Err(e) if e.fast_isinstance(&vm.ctx.exceptions.key_error) => {} @@ -196,8 +196,8 @@ impl FrameRef { } } if !code.cellvars.is_empty() || !code.freevars.is_empty() { - let map_to_dict = |keys: &[PyStrRef], values: &[PyCellRef]| { - for (k, v) in itertools::zip(keys, values) { + let map_to_dict = |keys: &[&PyStrInterned], values: &[PyCellRef]| { + for (&k, v) in itertools::zip(keys, values) { if let Some(value) = v.get() { locals.mapping().ass_subscript(k, Some(value), vm)?; } else { @@ -424,19 +424,19 @@ impl ExecutingFrame<'_> { } fn unbound_cell_exception(&self, i: usize, vm: &VirtualMachine) -> PyBaseExceptionRef { - if let Some(name) = self.code.cellvars.get(i) { + if let Some(&name) = self.code.cellvars.get(i) { vm.new_exception_msg( vm.ctx.exceptions.unbound_local_error.clone(), format!("local variable '{}' referenced before assignment", name), ) } else { - let name = &self.code.freevars[i - self.code.cellvars.len()]; + let name = self.code.freevars[i - self.code.cellvars.len()]; vm.new_name_error( format!( "free variable '{}' referenced before assignment in enclosing scope", name ), - name, + name.to_owned(), ) } } @@ -471,7 +471,7 @@ impl ExecutingFrame<'_> { Ok(None) } bytecode::Instruction::ImportName { idx } => { - self.import(vm, Some(self.code.names[*idx as usize].clone())) + self.import(vm, Some(self.code.names[*idx as usize].to_owned())) } bytecode::Instruction::ImportNameless => self.import(vm, None), bytecode::Instruction::ImportStar => self.import_star(vm), @@ -495,7 +495,7 @@ impl ExecutingFrame<'_> { Ok(None) } bytecode::Instruction::LoadNameAny(idx) => { - let name = &self.code.names[*idx as usize]; + let name = self.code.names[*idx as usize]; let value = self.locals.mapping().subscript(name, vm).ok(); self.push_value(match value { Some(x) => x, @@ -519,8 +519,8 @@ impl ExecutingFrame<'_> { } bytecode::Instruction::LoadClassDeref(i) => { let i = *i as usize; - let name = self.code.freevars[i - self.code.cellvars.len()].clone(); - let value = self.locals.mapping().subscript(&name, vm).ok(); + let name = self.code.freevars[i - self.code.cellvars.len()]; + let value = self.locals.mapping().subscript(name, vm).ok(); self.push_value(match value { Some(v) => v, None => self.cells_frees[i] @@ -535,7 +535,7 @@ impl ExecutingFrame<'_> { Ok(None) } bytecode::Instruction::StoreLocal(idx) => { - let name = &self.code.names[*idx as usize]; + let name = self.code.names[*idx as usize]; let value = self.pop_value(); self.locals.mapping().ass_subscript(name, Some(value), vm)?; Ok(None) @@ -543,7 +543,7 @@ impl ExecutingFrame<'_> { bytecode::Instruction::StoreGlobal(idx) => { let value = self.pop_value(); self.globals - .set_item(&*self.code.names[*idx as usize].clone(), value, vm)?; + .set_item(self.code.names[*idx as usize], value, vm)?; Ok(None) } bytecode::Instruction::StoreDeref(i) => { @@ -556,28 +556,30 @@ impl ExecutingFrame<'_> { Ok(None) } bytecode::Instruction::DeleteLocal(idx) => { - let name = &self.code.names[*idx as usize]; + let name = self.code.names[*idx as usize]; let res = self.locals.mapping().ass_subscript(name, None, vm); match res { Ok(()) => {} Err(e) if e.fast_isinstance(&vm.ctx.exceptions.key_error) => { - return Err( - vm.new_name_error(format!("name '{}' is not defined", name), name) - ) + return Err(vm.new_name_error( + format!("name '{}' is not defined", name), + name.to_owned(), + )) } Err(e) => return Err(e), } Ok(None) } bytecode::Instruction::DeleteGlobal(idx) => { - let name = &self.code.names[*idx as usize]; - match self.globals.del_item(&**name, vm) { + let name = self.code.names[*idx as usize]; + match self.globals.del_item(name, vm) { Ok(()) => {} Err(e) if e.fast_isinstance(&vm.ctx.exceptions.key_error) => { - return Err( - vm.new_name_error(format!("name '{}' is not defined", name), name) - ) + return Err(vm.new_name_error( + format!("name '{}' is not defined", name), + name.to_owned(), + )) } Err(e) => return Err(e), } @@ -926,8 +928,8 @@ impl ExecutingFrame<'_> { } bytecode::Instruction::LoadMethod { idx } => { let obj = self.pop_value(); - let method_name = self.code.names[*idx as usize].clone(); - let method = PyMethod::get(obj, method_name, vm)?; + let method_name = self.code.names[*idx as usize]; + let method = PyMethod::get(obj, method_name.to_owned(), vm)?; let (target, is_method, func) = match method { PyMethod::Function { target, func } => (target, true, func), PyMethod::Attribute(val) => (vm.ctx.none(), false, val), @@ -1094,7 +1096,7 @@ impl ExecutingFrame<'_> { self.globals .get_chain(self.builtins, name, vm)? .ok_or_else(|| { - vm.new_name_error(format!("name '{}' is not defined", name), &name.to_owned()) + vm.new_name_error(format!("name '{}' is not defined", name), name.to_owned()) }) } @@ -1133,10 +1135,10 @@ impl ExecutingFrame<'_> { #[cfg_attr(feature = "flame-it", flame("Frame"))] fn import_from(&mut self, vm: &VirtualMachine, idx: bytecode::NameIdx) -> PyResult { let module = self.last_value(); - let name = &self.code.names[idx as usize]; - let err = || vm.new_import_error(format!("cannot import name '{}'", name), name.clone()); + let name = self.code.names[idx as usize]; + let err = || vm.new_import_error(format!("cannot import name '{}'", name), name); // Load attribute, and transform any error into import error. - if let Some(obj) = vm.get_attribute_opt(module.clone(), name.clone())? { + if let Some(obj) = vm.get_attribute_opt(module.clone(), name)? { return Ok(obj); } // fallback to importing '{module.__name__}.{name}' from sys.modules @@ -1731,7 +1733,7 @@ impl ExecutingFrame<'_> { } fn load_attr(&mut self, vm: &VirtualMachine, attr: bytecode::NameIdx) -> FrameResult { - let attr_name = self.code.names[attr as usize].clone(); + let attr_name = self.code.names[attr as usize]; let parent = self.pop_value(); let obj = parent.get_attr(attr_name, vm)?; self.push_value(obj); @@ -1739,7 +1741,7 @@ impl ExecutingFrame<'_> { } fn store_attr(&mut self, vm: &VirtualMachine, attr: bytecode::NameIdx) -> FrameResult { - let attr_name = self.code.names[attr as usize].clone(); + let attr_name = self.code.names[attr as usize]; let parent = self.pop_value(); let value = self.pop_value(); parent.set_attr(attr_name, value, vm)?; @@ -1747,7 +1749,7 @@ impl ExecutingFrame<'_> { } fn delete_attr(&mut self, vm: &VirtualMachine, attr: bytecode::NameIdx) -> FrameResult { - let attr_name = self.code.names[attr as usize].clone(); + let attr_name = self.code.names[attr as usize]; let parent = self.pop_value(); parent.del_attr(attr_name, vm)?; Ok(None) diff --git a/vm/src/import.rs b/vm/src/import.rs index 7b9075acde..0f823e0cc9 100644 --- a/vm/src/import.rs +++ b/vm/src/import.rs @@ -142,7 +142,7 @@ pub fn import_codeobj( if set_file_attr { attrs.set_item( identifier!(vm, __file__), - code_obj.source_path.clone().into(), + code_obj.source_path.to_object(), vm, )?; } diff --git a/vm/src/vm/vm_new.rs b/vm/src/vm/vm_new.rs index 6bd7105762..efab515f48 100644 --- a/vm/src/vm/vm_new.rs +++ b/vm/src/vm/vm_new.rs @@ -97,13 +97,10 @@ impl VirtualMachine { self.new_exception_msg(type_error, msg) } - pub fn new_name_error(&self, msg: String, name: &PyStrRef) -> PyBaseExceptionRef { + pub fn new_name_error(&self, msg: String, name: PyStrRef) -> PyBaseExceptionRef { let name_error_type = self.ctx.exceptions.name_error.clone(); let name_error = self.new_exception_msg(name_error_type, msg); - name_error - .as_object() - .set_attr("name", name.clone(), self) - .unwrap(); + name_error.as_object().set_attr("name", name, self).unwrap(); name_error }