Skip to content

Commit a52fc91

Browse files
committed
PyTupleTyped as alias of PyTuple
1 parent 26d54f7 commit a52fc91

File tree

5 files changed

+81
-65
lines changed

5 files changed

+81
-65
lines changed

vm/src/builtins/function.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ use super::{
88
#[cfg(feature = "jit")]
99
use crate::common::lock::OnceCell;
1010
use crate::common::lock::PyMutex;
11-
use crate::convert::{ToPyObject, TryFromObject};
1211
use crate::function::ArgMapping;
1312
use crate::object::{Traverse, TraverseFn};
1413
use crate::{
15-
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
16-
bytecode,
14+
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
15+
VirtualMachine, bytecode,
1716
class::PyClassImpl,
17+
convert::ToPyObject,
1818
frame::Frame,
1919
function::{FuncArgs, OptionalArg, PyComparisonValue, PySetterValue},
2020
scope::Scope,
@@ -32,7 +32,7 @@ pub struct PyFunction {
3232
code: PyRef<PyCode>,
3333
globals: PyDictRef,
3434
builtins: PyObjectRef,
35-
closure: Option<PyTupleTyped<PyCellRef>>,
35+
closure: Option<PyRef<PyTupleTyped<PyCellRef>>>,
3636
defaults_and_kwdefaults: PyMutex<(Option<PyTupleRef>, Option<PyDictRef>)>,
3737
name: PyMutex<PyStrRef>,
3838
qualname: PyMutex<PyStrRef>,
@@ -58,7 +58,7 @@ impl PyFunction {
5858
pub(crate) fn new(
5959
code: PyRef<PyCode>,
6060
globals: PyDictRef,
61-
closure: Option<PyTupleTyped<PyCellRef>>,
61+
closure: Option<PyRef<PyTupleTyped<PyCellRef>>>,
6262
defaults: Option<PyTupleRef>,
6363
kw_only_defaults: Option<PyDictRef>,
6464
qualname: PyStrRef,
@@ -613,7 +613,7 @@ impl Constructor for PyFunction {
613613

614614
// Validate that all items are cells and create typed tuple
615615
let typed_closure =
616-
PyTupleTyped::<PyCellRef>::try_from_object(vm, closure_tuple.into())?;
616+
PyRef::<PyTupleTyped<PyCellRef>>::try_from_object(vm, closure_tuple.into())?;
617617
Some(typed_closure)
618618
} else if !args.code.freevars.is_empty() {
619619
return Err(vm.new_type_error("arg 5 (closure) must be tuple"));

vm/src/builtins/tuple.rs

Lines changed: 59 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::common::{
33
hash::{PyHash, PyUHash},
44
lock::PyMutex,
55
};
6-
use crate::object::{Traverse, TraverseFn};
6+
use crate::object::{MaybeTraverse, Traverse, TraverseFn};
77
use crate::{
88
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
99
atomic_func,
@@ -500,53 +500,81 @@ pub(crate) fn init(context: &Context) {
500500
PyTupleIterator::extend_class(context, context.types.tuple_iterator_type);
501501
}
502502

503-
pub struct PyTupleTyped<T: TransmuteFromObject> {
503+
pub struct PyTupleTyped<R> {
504504
// SAFETY INVARIANT: T must be repr(transparent) over PyObjectRef, and the
505505
// elements must be logically valid when transmuted to T
506-
tuple: PyTupleRef,
507-
_marker: PhantomData<Vec<T>>,
506+
tuple: PyTuple,
507+
_marker: PhantomData<R>,
508508
}
509509

510-
unsafe impl<T> Traverse for PyTupleTyped<T>
510+
impl<T: PyPayload> PyPayload for PyTupleTyped<PyRef<T>>
511511
where
512-
T: TransmuteFromObject + Traverse,
512+
PyRef<T>: TransmuteFromObject,
513+
{
514+
#[inline]
515+
fn payload_type_id() -> std::any::TypeId {
516+
std::any::TypeId::of::<PyTuple>()
517+
}
518+
#[inline]
519+
fn class(ctx: &Context) -> &'static Py<PyType> {
520+
ctx.types.tuple_type
521+
}
522+
}
523+
524+
unsafe impl<R> Traverse for PyTupleTyped<R>
525+
where
526+
R: TransmuteFromObject,
513527
{
514528
fn traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
515529
self.tuple.traverse(tracer_fn);
516530
}
517531
}
518532

519-
impl<T: TransmuteFromObject> TryFromObject for PyTupleTyped<T> {
520-
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
521-
let tuple = PyTupleRef::try_from_object(vm, obj)?;
522-
for elem in &*tuple {
523-
T::check(vm, elem)?
524-
}
525-
// SAFETY: the contract of TransmuteFromObject upholds the variant on `tuple`
526-
Ok(Self {
527-
tuple,
528-
_marker: PhantomData,
529-
})
533+
impl<R: TransmuteFromObject + Traverse> MaybeTraverse for PyTupleTyped<R> {
534+
const IS_TRACE: bool = true;
535+
fn try_traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
536+
self.traverse(tracer_fn);
537+
}
538+
}
539+
540+
impl<T: PyPayload> PyRef<PyTupleTyped<PyRef<T>>> {
541+
pub fn into_untyped(self) -> PyRef<PyTuple> {
542+
// SAFETY: PyTupleTyped is transparent over PyTuple
543+
unsafe { std::mem::transmute(self) }
530544
}
531545
}
532546

533-
impl<T: TransmuteFromObject> AsRef<[T]> for PyTupleTyped<T> {
534-
fn as_ref(&self) -> &[T] {
547+
impl<T: PyPayload> Py<PyTupleTyped<PyRef<T>>> {
548+
pub fn as_untyped(&self) -> &Py<PyTuple> {
549+
// SAFETY: PyTupleTyped is transparent over PyTuple
550+
unsafe { std::mem::transmute(self) }
551+
}
552+
}
553+
554+
impl<T: PyPayload> AsRef<[PyRef<T>]> for PyTupleTyped<PyRef<T>> {
555+
fn as_ref(&self) -> &[PyRef<T>] {
535556
self.as_slice()
536557
}
537558
}
538559

539-
impl<T: TransmuteFromObject> PyTupleTyped<T> {
540-
pub fn empty(vm: &VirtualMachine) -> Self {
541-
Self {
542-
tuple: vm.ctx.empty_tuple.clone(),
543-
_marker: PhantomData,
560+
impl<T: PyPayload> PyTupleTyped<PyRef<T>> {
561+
/// Returns a reference to the empty tuple
562+
pub fn empty(ctx: &Context) -> &Py<Self>
563+
where
564+
T: fmt::Debug + Send + Sync + 'static,
565+
{
566+
// SAFETY: empty_tuple is always a valid tuple with 0 elements,
567+
// and 0 elements trivially satisfy any T::check
568+
unsafe {
569+
ctx.empty_tuple
570+
.as_object()
571+
.downcast_unchecked_ref::<PyTupleTyped<PyRef<T>>>()
544572
}
545573
}
546574

547575
#[inline]
548-
pub fn as_slice(&self) -> &[T] {
549-
unsafe { &*(self.tuple.as_slice() as *const [PyObjectRef] as *const [T]) }
576+
pub fn as_slice(&self) -> &[PyRef<T>] {
577+
unsafe { &*(self.tuple.as_slice() as *const [PyObjectRef] as *const [PyRef<T>]) }
550578
}
551579

552580
#[inline]
@@ -560,32 +588,16 @@ impl<T: TransmuteFromObject> PyTupleTyped<T> {
560588
}
561589
}
562590

563-
impl<T: TransmuteFromObject> Clone for PyTupleTyped<T> {
564-
fn clone(&self) -> Self {
565-
Self {
566-
tuple: self.tuple.clone(),
567-
_marker: PhantomData,
568-
}
569-
}
570-
}
571-
572-
impl<T: TransmuteFromObject + fmt::Debug> fmt::Debug for PyTupleTyped<T> {
591+
impl<R: fmt::Debug> fmt::Debug for PyTupleTyped<R> {
573592
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
574-
self.as_slice().fmt(f)
575-
}
576-
}
577-
578-
impl<T: TransmuteFromObject> From<PyTupleTyped<T>> for PyTupleRef {
579-
#[inline]
580-
fn from(tup: PyTupleTyped<T>) -> Self {
581-
tup.tuple
593+
self.tuple.as_slice().fmt(f)
582594
}
583595
}
584596

585-
impl<T: TransmuteFromObject> ToPyObject for PyTupleTyped<T> {
597+
impl<T: PyPayload> From<PyRef<PyTupleTyped<PyRef<T>>>> for PyTupleRef {
586598
#[inline]
587-
fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef {
588-
self.tuple.into()
599+
fn from(tup: PyRef<PyTupleTyped<PyRef<T>>>) -> Self {
600+
tup.into_untyped()
589601
}
590602
}
591603

vm/src/builtins/type.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ unsafe impl crate::object::Traverse for PyType {
6262
pub struct HeapTypeExt {
6363
pub name: PyRwLock<PyStrRef>,
6464
pub qualname: PyRwLock<PyStrRef>,
65-
pub slots: Option<PyTupleTyped<PyStrRef>>,
65+
pub slots: Option<PyRef<PyTupleTyped<PyStrRef>>>,
6666
pub sequence_methods: PySequenceMethods,
6767
pub mapping_methods: PyMappingMethods,
6868
}
@@ -1036,10 +1036,10 @@ impl Constructor for PyType {
10361036
// TODO: Flags is currently initialized with HAS_DICT. Should be
10371037
// updated when __slots__ are supported (toggling the flag off if
10381038
// a class has __slots__ defined).
1039-
let heaptype_slots: Option<PyTupleTyped<PyStrRef>> =
1039+
let heaptype_slots: Option<PyRef<PyTupleTyped<PyStrRef>>> =
10401040
if let Some(x) = attributes.get(identifier!(vm, __slots__)) {
10411041
Some(if x.to_owned().class().is(vm.ctx.types.str_type) {
1042-
PyTupleTyped::<PyStrRef>::try_from_object(
1042+
PyRef::<PyTupleTyped<PyStrRef>>::try_from_object(
10431043
vm,
10441044
vec![x.to_owned()].into_pytuple(vm).into(),
10451045
)?
@@ -1052,7 +1052,10 @@ impl Constructor for PyType {
10521052
}
10531053
elements
10541054
};
1055-
PyTupleTyped::<PyStrRef>::try_from_object(vm, elements.into_pytuple(vm).into())?
1055+
PyRef::<PyTupleTyped<PyStrRef>>::try_from_object(
1056+
vm,
1057+
elements.into_pytuple(vm).into(),
1058+
)?
10561059
})
10571060
} else {
10581061
None

vm/src/frame.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,11 +1346,12 @@ impl ExecutingFrame<'_> {
13461346
#[cfg_attr(feature = "flame-it", flame("Frame"))]
13471347
fn import(&mut self, vm: &VirtualMachine, module_name: Option<&Py<PyStr>>) -> PyResult<()> {
13481348
let module_name = module_name.unwrap_or(vm.ctx.empty_str);
1349-
let from_list = <Option<PyTupleTyped<PyStrRef>>>::try_from_object(vm, self.pop_value())?
1350-
.unwrap_or_else(|| PyTupleTyped::empty(vm));
1349+
let top = self.pop_value();
1350+
let from_list = <Option<PyRef<PyTupleTyped<PyStrRef>>>>::try_from_object(vm, top)?
1351+
.unwrap_or_else(|| PyTupleTyped::<PyStrRef>::empty(&vm.ctx).to_owned());
13511352
let level = usize::try_from_object(vm, self.pop_value())?;
13521353

1353-
let module = vm.import_from(module_name, from_list, level)?;
1354+
let module = vm.import_from(module_name, &from_list, level)?;
13541355

13551356
self.push_value(module);
13561357
Ok(())
@@ -1839,7 +1840,7 @@ impl ExecutingFrame<'_> {
18391840
.expect("Second to top value on the stack must be a code object");
18401841

18411842
let closure = if flags.contains(bytecode::MakeFunctionFlags::CLOSURE) {
1842-
Some(PyTupleTyped::try_from_object(vm, self.pop_value()).unwrap())
1843+
Some(PyRef::<PyTupleTyped<PyCellRef>>::try_from_object(vm, self.pop_value()).unwrap())
18431844
} else {
18441845
None
18451846
};

vm/src/vm/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,7 @@ impl VirtualMachine {
599599
#[inline]
600600
pub fn import<'a>(&self, module_name: impl AsPyStr<'a>, level: usize) -> PyResult {
601601
let module_name = module_name.as_pystr(&self.ctx);
602-
let from_list = PyTupleTyped::empty(self);
602+
let from_list = PyTupleTyped::<PyStrRef>::empty(&self.ctx);
603603
self.import_inner(module_name, from_list, level)
604604
}
605605

@@ -609,7 +609,7 @@ impl VirtualMachine {
609609
pub fn import_from<'a>(
610610
&self,
611611
module_name: impl AsPyStr<'a>,
612-
from_list: PyTupleTyped<PyStrRef>,
612+
from_list: &Py<PyTupleTyped<PyStrRef>>,
613613
level: usize,
614614
) -> PyResult {
615615
let module_name = module_name.as_pystr(&self.ctx);
@@ -619,7 +619,7 @@ impl VirtualMachine {
619619
fn import_inner(
620620
&self,
621621
module: &Py<PyStr>,
622-
from_list: PyTupleTyped<PyStrRef>,
622+
from_list: &Py<PyTupleTyped<PyStrRef>>,
623623
level: usize,
624624
) -> PyResult {
625625
// if the import inputs seem weird, e.g a package import or something, rather than just
@@ -657,7 +657,7 @@ impl VirtualMachine {
657657
} else {
658658
(None, None)
659659
};
660-
let from_list = from_list.to_pyobject(self);
660+
let from_list = from_list.to_owned().to_pyobject(self);
661661
import_func
662662
.call((module.to_owned(), globals, locals, from_list, level), self)
663663
.inspect_err(|exc| import::remove_importlib_frames(self, exc))

0 commit comments

Comments
 (0)