Skip to content

Commit e5678da

Browse files
authored
Merge pull request RustPython#2715 from DimitrisJim/frozenset_singleton
Make `frozenset(empty_iterable)` return a singleton.
2 parents 3576801 + 712f950 commit e5678da

3 files changed

Lines changed: 20 additions & 17 deletions

File tree

Lib/test/test_set.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -715,8 +715,6 @@ def test_init(self):
715715
s.__init__(self.otherword)
716716
self.assertEqual(s, set(self.word))
717717

718-
# TODO: RUSTPYTHON
719-
@unittest.expectedFailure
720718
def test_singleton_empty_frozenset(self):
721719
f = frozenset()
722720
efs = [frozenset(), frozenset([]), frozenset(()), frozenset(''),

vm/src/builtins/set.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use super::pytype::PyTypeRef;
55
use crate::common::hash::PyHash;
66
use crate::common::rc::PyRc;
77
use crate::dictdatatype;
8-
use crate::function::OptionalArg::{Missing, Present};
98
use crate::function::{Args, OptionalArg};
109
use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter, Unhashable};
1110
use crate::vm::{ReprGuard, VirtualMachine};
@@ -554,8 +553,7 @@ macro_rules! multi_args_frozenset {
554553

555554
#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, Iterable))]
556555
impl PyFrozenSet {
557-
// used by ssl.rs windows
558-
#[allow(dead_code)]
556+
// Also used by ssl.rs windows.
559557
pub(crate) fn from_iter(
560558
vm: &VirtualMachine,
561559
it: impl IntoIterator<Item = PyObjectRef>,
@@ -573,23 +571,26 @@ impl PyFrozenSet {
573571
iterable: OptionalArg<PyObjectRef>,
574572
vm: &VirtualMachine,
575573
) -> PyResult<PyRef<Self>> {
576-
let iterable = if let Present(iterable) = iterable {
577-
if cls.is(&vm.ctx.types.frozenset_type) {
578-
match iterable.downcast_exact::<PyFrozenSet>(vm) {
579-
Ok(iter) => return Ok(iter),
580-
Err(iterable) => Present(PyIterable::try_from_object(vm, iterable)?),
574+
let elements = if let OptionalArg::Present(iterable) = iterable {
575+
let iterable = if cls.is(&vm.ctx.types.frozenset_type) {
576+
match iterable.downcast_exact::<Self>(vm) {
577+
Ok(fs) => return Ok(fs),
578+
Err(iterable) => iterable,
581579
}
582580
} else {
583-
Present(PyIterable::try_from_object(vm, iterable)?)
584-
}
581+
iterable
582+
};
583+
vm.extract_elements(&iterable)?
585584
} else {
586-
Missing
585+
vec![]
587586
};
588587

589-
Self {
590-
inner: PySetInner::from_arg(iterable, vm)?,
588+
// Return empty fs if iterable passed is emtpy and only for exact fs types.
589+
if elements.is_empty() && cls.is(&vm.ctx.types.frozenset_type) {
590+
Ok(vm.ctx.empty_frozenset.clone())
591+
} else {
592+
Self::from_iter(vm, elements).and_then(|o| o.into_ref_with_type(vm, cls))
591593
}
592-
.into_ref_with_type(vm, cls)
593594
}
594595

595596
#[pymethod(name = "__len__")]

vm/src/pyobject.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::builtins::namespace::PyNamespace;
2424
use crate::builtins::object;
2525
use crate::builtins::pystr;
2626
use crate::builtins::pytype::{self, PyType, PyTypeRef};
27-
use crate::builtins::set;
27+
use crate::builtins::set::{self, PyFrozenSet};
2828
use crate::builtins::singletons::{PyNone, PyNoneRef, PyNotImplemented, PyNotImplementedRef};
2929
use crate::builtins::slice::PyEllipsis;
3030
use crate::builtins::staticmethod::PyStaticMethod;
@@ -89,6 +89,7 @@ pub struct PyContext {
8989
pub false_value: PyIntRef,
9090
pub none: PyNoneRef,
9191
pub empty_tuple: PyTupleRef,
92+
pub empty_frozenset: PyRef<PyFrozenSet>,
9293
pub ellipsis: PyRef<PyEllipsis>,
9394
pub not_implemented: PyNotImplementedRef,
9495

@@ -129,6 +130,8 @@ impl PyContext {
129130
PyTuple::_new(Vec::new().into_boxed_slice()),
130131
&types.tuple_type,
131132
);
133+
let empty_frozenset =
134+
PyRef::new_ref(PyFrozenSet::default(), types.frozenset_type.clone(), None);
132135

133136
let string_cache = Dict::default();
134137

@@ -144,6 +147,7 @@ impl PyContext {
144147
false_value,
145148
none,
146149
empty_tuple,
150+
empty_frozenset,
147151
ellipsis,
148152
not_implemented,
149153

0 commit comments

Comments
 (0)