Skip to content

Commit 5781fa4

Browse files
authored
Merge pull request RustPython#2336 from RustPython/coolreader18/pyobjectref-custom-vtable
Manually implement a vtable for PyObjectRef
2 parents 749e6af + 31f4999 commit 5781fa4

File tree

18 files changed

+555
-675
lines changed

18 files changed

+555
-675
lines changed

.github/workflows/ci.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,21 @@ jobs:
161161
run: python -m pip install flake8
162162
- name: run lint
163163
run: flake8 . --count --exclude=./.*,./Lib,./vm/Lib --select=E9,F63,F7,F82 --show-source --statistics
164+
miri:
165+
name: Run tests under miri
166+
runs-on: ubuntu-latest
167+
steps:
168+
- uses: actions/checkout@master
169+
- uses: actions-rs/toolchain@v1
170+
with:
171+
profile: minimal
172+
toolchain: nightly
173+
components: miri
174+
override: true
175+
- name: Run tests under miri
176+
# miri-ignore-leaks because the type-object circular reference means that there will always be
177+
# a memory leak, at least until we have proper cyclic gc
178+
run: MIRIFLAGS='-Zmiri-ignore-leaks' cargo +nightly miri test -p rustpython-vm -- miri_test
164179

165180
wasm:
166181
name: Check the WASM package and demo

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ cfg-if = "0.1.10"
7979
timsort = "0.1"
8080
thiserror = "1.0"
8181
atty = "0.2"
82+
static_assertions = "1.1"
8283

8384
## unicode stuff
8485
unicode_names2 = "0.4"

vm/src/builtins/code.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ impl PyCode {}
198198
#[pyimpl]
199199
impl PyCodeRef {
200200
#[pyslot]
201-
fn tp_new(_cls: PyTypeRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
201+
fn tp_new(_cls: PyTypeRef, vm: &VirtualMachine) -> PyResult<Self> {
202202
Err(vm.new_type_error("Cannot directly create code object".to_owned()))
203203
}
204204

vm/src/builtins/dict.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ macro_rules! dict_iterator {
597597
let s = if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) {
598598
let mut str_parts = vec![];
599599
for (key, value) in zelf.dict.clone() {
600-
let s = vm.to_repr(&$result_fn(vm, key, value))?;
600+
let s = vm.to_repr(&($result_fn)(vm, key, value))?;
601601
str_parts.push(s.borrow_value().to_owned());
602602
}
603603
format!("{}([{}])", $class_name, str_parts.join(", "))
@@ -694,7 +694,7 @@ macro_rules! dict_iterator {
694694
match zelf.dict.entries.next_entry(&mut position) {
695695
Some((key, value)) => {
696696
zelf.position.store(position);
697-
Ok($result_fn(vm, key, value))
697+
Ok(($result_fn)(vm, key, value))
698698
}
699699
None => Err(vm.new_stop_iteration()),
700700
}
@@ -743,7 +743,7 @@ macro_rules! dict_iterator {
743743
match zelf.dict.len().checked_sub(count) {
744744
Some(mut pos) => {
745745
let (key, value) = zelf.dict.entries.next_entry(&mut pos).unwrap();
746-
Ok($result_fn(vm, key, value))
746+
Ok(($result_fn)(vm, key, value))
747747
}
748748
None => {
749749
zelf.position.store(std::isize::MAX as usize);

vm/src/builtins/object.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,10 @@ impl PyBaseObject {
217217
#[pyproperty(name = "__class__", setter)]
218218
fn set_class(instance: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
219219
if instance.payload_is::<PyBaseObject>() {
220-
match value.downcast_generic::<PyType>() {
220+
match value.downcast::<PyType>() {
221221
Ok(cls) => {
222222
// FIXME(#1979) cls instances might have a payload
223-
*instance.typ.write() = cls;
223+
*instance.class_lock().write() = cls;
224224
Ok(())
225225
}
226226
Err(value) => {

vm/src/builtins/pystr.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,10 @@ impl PyStr {
240240
if other.isinstance(&vm.ctx.types.str_type) {
241241
Ok(self.value.py_add(borrow_value(&other)))
242242
} else {
243-
Err(vm.new_type_error(format!("Cannot add {} and {}", self, other)))
243+
Err(vm.new_type_error(format!(
244+
"can only concatenate str (not \"{}\") to str",
245+
other.class().name
246+
)))
244247
}
245248
}
246249

vm/src/builtins/pytype.rs

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -727,24 +727,22 @@ pub fn tp_new_wrapper(
727727
call_tp_new(zelf, cls, args, vm)
728728
}
729729

730-
fn take_next_base(mut bases: Vec<Vec<PyTypeRef>>) -> (Option<PyTypeRef>, Vec<Vec<PyTypeRef>>) {
731-
bases = bases.into_iter().filter(|x| !x.is_empty()).collect();
732-
733-
for base in &bases {
730+
fn take_next_base(bases: &mut Vec<Vec<PyTypeRef>>) -> Option<PyTypeRef> {
731+
for base in bases.iter() {
734732
let head = base[0].clone();
735-
if !(&bases).iter().any(|x| x[1..].iter().any(|x| x.is(&head))) {
733+
if !bases.iter().any(|x| x[1..].iter().any(|x| x.is(&head))) {
736734
// Remove from other heads.
737-
for item in &mut bases {
735+
for item in bases.iter_mut() {
738736
if item[0].is(&head) {
739737
item.remove(0);
740738
}
741739
}
742740

743-
return (Some(head), bases);
741+
return Some(head);
744742
}
745743
}
746744

747-
(None, bases)
745+
None
748746
}
749747

750748
fn linearise_mro(mut bases: Vec<Vec<PyTypeRef>>) -> Result<Vec<PyTypeRef>, String> {
@@ -768,22 +766,19 @@ fn linearise_mro(mut bases: Vec<Vec<PyTypeRef>>) -> Result<Vec<PyTypeRef>, Strin
768766
}
769767

770768
let mut result = vec![];
771-
loop {
772-
if (&bases).iter().all(Vec::is_empty) {
773-
break;
774-
}
775-
let (head, new_bases) = take_next_base(bases);
776-
let head = head.ok_or_else(|| {
769+
while !bases.is_empty() {
770+
let head = take_next_base(&mut bases).ok_or_else(|| {
777771
// Take the head class of each class here. Now that we have reached the problematic bases.
778772
// Because this failed, we assume the lists cannot be empty.
779773
format!(
780774
"Cannot create a consistent method resolution order (MRO) for bases {}",
781-
new_bases.iter().map(|x| x.first().unwrap()).join(", ")
775+
bases.iter().map(|x| x.first().unwrap()).format(", ")
782776
)
783-
});
777+
})?;
778+
779+
result.push(head);
784780

785-
result.push(head.unwrap());
786-
bases = new_bases;
781+
bases.retain(|x| !x.is_empty());
787782
}
788783
Ok(result)
789784
}

vm/src/builtins/weakref.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use super::pytype::PyTypeRef;
22
use crate::common::hash::PyHash;
33
use crate::function::{FuncArgs, OptionalArg};
44
use crate::pyobject::{
5-
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
5+
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyObjectWeak, PyRef, PyResult, PyValue,
6+
TypeProtocol,
67
};
7-
use crate::pyobjectrc::{PyObjectRc, PyObjectWeak};
88
use crate::slots::{Callable, Comparable, Hashable, PyComparisonOp};
99
use crate::vm::VirtualMachine;
1010

@@ -20,7 +20,7 @@ pub struct PyWeak {
2020
impl PyWeak {
2121
pub fn downgrade(obj: &PyObjectRef) -> PyWeak {
2222
PyWeak {
23-
referent: PyObjectRc::downgrade(obj),
23+
referent: PyObjectRef::downgrade(obj),
2424
hash: AtomicCell::new(None),
2525
}
2626
}

vm/src/bytesinner.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use crate::byteslike::try_bytes_like;
1414
use crate::cformat::CFormatBytes;
1515
use crate::function::{OptionalArg, OptionalOption};
1616
use crate::pyobject::{
17-
BorrowValue, Either, IdProtocol, PyComparisonValue, PyIterable, PyObjectRef, PyRef, PyResult,
18-
PyValue, TryFromObject, TypeProtocol,
17+
BorrowValue, Either, IdProtocol, PyComparisonValue, PyIterable, PyObjectRef, PyResult, PyValue,
18+
TryFromObject, TypeProtocol,
1919
};
2020
use crate::sliceable::PySliceableSequence;
2121
use crate::slots::PyComparisonOp;
@@ -91,10 +91,10 @@ impl ByteInnerNewOptions {
9191

9292
pub fn get_bytes(mut self, cls: PyTypeRef, vm: &VirtualMachine) -> PyResult<PyBytesRef> {
9393
let inner = if let OptionalArg::Present(source) = self.source.take() {
94-
if source.class().is(&PyBytes::class(vm)) && cls.is(&PyBytes::class(vm)) {
95-
return self
96-
.check_args(vm)
97-
.map(|_| unsafe { PyRef::from_obj_unchecked(source) });
94+
if cls.is(&PyBytes::class(vm)) {
95+
if let Ok(source) = source.clone().downcast_exact(vm) {
96+
return self.check_args(vm).map(|()| source);
97+
}
9898
}
9999

100100
match_class!(match source {

0 commit comments

Comments
 (0)