Repository navigation
Update to pass test for unhashable collections #4640
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
eb0f2f3
2e12da2
92526b5
725060c
5588a63
297179e
95fd1e8
6d4e7c9
e5b338e
07274f3
ea7c4f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,8 +13,8 @@ use crate::{ | |
| sequence::{MutObjectSequenceOp, OptionalRangeArgs, SequenceExt, SequenceMutExt}, | ||
| sliceable::{SequenceIndex, SliceableSequenceMutOp, SliceableSequenceOp}, | ||
| types::{ | ||
| AsMapping, AsSequence, Comparable, Constructor, Hashable, Initializer, IterNext, | ||
| IterNextIterable, Iterable, PyComparisonOp, Unconstructible, Unhashable, | ||
| unhashable_wrapper, AsMapping, AsSequence, Comparable, Constructor, Initializer, IterNext, | ||
| IterNextIterable, Iterable, PyComparisonOp, Unconstructible, | ||
| }, | ||
| utils::collection_repr, | ||
| vm::VirtualMachine, | ||
|
|
@@ -86,15 +86,7 @@ pub(crate) struct SortOptions { | |
| pub type PyListRef = PyRef<PyList>; | ||
|
|
||
| #[pyclass( | ||
| with( | ||
| Constructor, | ||
| Initializer, | ||
| AsMapping, | ||
| Iterable, | ||
| Hashable, | ||
| Comparable, | ||
| AsSequence | ||
| ), | ||
| with(Constructor, Initializer, AsMapping, Iterable, Comparable, AsSequence), | ||
| flags(BASETYPE) | ||
| )] | ||
| impl PyList { | ||
|
|
@@ -492,8 +484,6 @@ impl Comparable for PyList { | |
| } | ||
| } | ||
|
|
||
| impl Unhashable for PyList {} | ||
|
|
||
| fn do_sort( | ||
| vm: &VirtualMachine, | ||
| values: &mut Vec<PyObjectRef>, | ||
|
|
@@ -612,6 +602,13 @@ impl IterNext for PyListReverseIterator { | |
| } | ||
|
|
||
| pub fn init(context: &Context) { | ||
| context | ||
| .types | ||
| .list_type | ||
| .slots | ||
| .hash | ||
| .store(Some(unhashable_wrapper)); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe there is a more elegant way to do this...?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And I missed adding unhashable_wrapper thing for deque, so test_deque fails. Deque implementation resides in collections.rs, but there is no type initialization function similar to this |
||
|
|
||
| let list_type = &context.types.list_type; | ||
| PyList::extend_class(context, list_type); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,7 @@ use crate::{ | |
| builtins::{PyBaseObject, PyBoundMethod, PyType, PyTypeRef}, | ||
| identifier, | ||
| object::{Py, PyObjectPayload, PyObjectRef, PyRef}, | ||
| types::{PyTypeFlags, PyTypeSlots}, | ||
| types::{unhashable_wrapper, PyTypeFlags, PyTypeSlots}, | ||
| vm::Context, | ||
| }; | ||
| use rustpython_common::{lock::PyRwLock, static_cell}; | ||
|
|
@@ -112,6 +112,16 @@ pub trait PyClassImpl: PyClassDef { | |
| .into(); | ||
| class.set_attr(identifier!(ctx, __new__), bound); | ||
| } | ||
|
|
||
| if class | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to check if this is related to #3460 later |
||
| .slots | ||
| .hash | ||
| .load() | ||
| .map(|h| h as u64 == unhashable_wrapper as u64) | ||
| .unwrap_or(false) | ||
| { | ||
| class.set_attr(ctx.names.__hash__, ctx.none.clone().into()); | ||
|
youknowone marked this conversation as resolved.
|
||
| } | ||
| } | ||
|
|
||
| fn make_class(ctx: &Context) -> PyTypeRef | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -243,6 +243,11 @@ fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> { | |||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| /// Marks a type as unhashable. Similar to PyObject_HashNotImplemented in CPython | ||||||||||||||||||||||||
| pub fn unhashable_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> { | ||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Other functions are called wrapper because they are wrapping a python call.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, probably |
||||||||||||||||||||||||
| Err(vm.new_type_error(format!("unhashable type: {}", zelf.class().name()))) | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| fn call_wrapper(zelf: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResult { | ||||||||||||||||||||||||
| vm.call_special_method(zelf.to_owned(), identifier!(vm, __call__), args) | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
@@ -414,7 +419,17 @@ impl PyType { | |||||||||||||||||||||||
| update_pointer_slot!(as_mapping, mapping_methods); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| _ if name == identifier!(ctx, __hash__) => { | ||||||||||||||||||||||||
| toggle_slot!(hash, hash_wrapper); | ||||||||||||||||||||||||
| let is_unhashable = self | ||||||||||||||||||||||||
| .attributes | ||||||||||||||||||||||||
| .read() | ||||||||||||||||||||||||
| .get(identifier!(ctx, __hash__)) | ||||||||||||||||||||||||
| .map(|a| a.is(&ctx.none())) | ||||||||||||||||||||||||
| .unwrap_or(false); | ||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||
| if is_unhashable { | ||||||||||||||||||||||||
| toggle_slot!(hash, unhashable_wrapper); | ||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||
| toggle_slot!(hash, hash_wrapper); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| _ if name == identifier!(ctx, __call__) => { | ||||||||||||||||||||||||
| toggle_slot!(call, call_wrapper); | ||||||||||||||||||||||||
|
|
@@ -663,22 +678,6 @@ pub trait Hashable: PyPayload { | |||||||||||||||||||||||
| fn hash(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyHash>; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| pub trait Unhashable: PyPayload {} | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| impl<T> Hashable for T | ||||||||||||||||||||||||
| where | ||||||||||||||||||||||||
| T: Unhashable, | ||||||||||||||||||||||||
| { | ||||||||||||||||||||||||
| fn slot_hash(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> { | ||||||||||||||||||||||||
| Err(vm.new_type_error(format!("unhashable type: '{}'", zelf.class().name()))) | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| #[cold] | ||||||||||||||||||||||||
| fn hash(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<PyHash> { | ||||||||||||||||||||||||
| unreachable!("slot_hash is implemented for unhashable types"); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| #[pyclass] | ||||||||||||||||||||||||
| pub trait Comparable: PyPayload { | ||||||||||||||||||||||||
| #[inline] | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a suggestion about the location of this initialization.
We put these information to
PyClassDeffor builtin types.adding
HASHABLEconst with default value false will be good.Then we use the information during making class. that's
PyClassImpl::make_slots.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I'll try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe default value is false, not true. hashable is common in builtin type world, but not outside.