Merge pull request #2715 from DimitrisJim/frozenset_singleton

Make `frozenset(empty_iterable)` return a singleton.
This commit is contained in:
Jeong YunWon
2021-07-12 16:07:26 +09:00
committed by GitHub
3 changed files with 20 additions and 17 deletions

View File

@@ -715,8 +715,6 @@ class TestFrozenSet(TestJointOps, unittest.TestCase):
s.__init__(self.otherword)
self.assertEqual(s, set(self.word))
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_singleton_empty_frozenset(self):
f = frozenset()
efs = [frozenset(), frozenset([]), frozenset(()), frozenset(''),

View File

@@ -5,7 +5,6 @@ use super::pytype::PyTypeRef;
use crate::common::hash::PyHash;
use crate::common::rc::PyRc;
use crate::dictdatatype;
use crate::function::OptionalArg::{Missing, Present};
use crate::function::{Args, OptionalArg};
use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter, Unhashable};
use crate::vm::{ReprGuard, VirtualMachine};
@@ -554,8 +553,7 @@ macro_rules! multi_args_frozenset {
#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, Iterable))]
impl PyFrozenSet {
// used by ssl.rs windows
#[allow(dead_code)]
// Also used by ssl.rs windows.
pub(crate) fn from_iter(
vm: &VirtualMachine,
it: impl IntoIterator<Item = PyObjectRef>,
@@ -573,23 +571,26 @@ impl PyFrozenSet {
iterable: OptionalArg<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<PyRef<Self>> {
let iterable = if let Present(iterable) = iterable {
if cls.is(&vm.ctx.types.frozenset_type) {
match iterable.downcast_exact::<PyFrozenSet>(vm) {
Ok(iter) => return Ok(iter),
Err(iterable) => Present(PyIterable::try_from_object(vm, iterable)?),
let elements = if let OptionalArg::Present(iterable) = iterable {
let iterable = if cls.is(&vm.ctx.types.frozenset_type) {
match iterable.downcast_exact::<Self>(vm) {
Ok(fs) => return Ok(fs),
Err(iterable) => iterable,
}
} else {
Present(PyIterable::try_from_object(vm, iterable)?)
}
iterable
};
vm.extract_elements(&iterable)?
} else {
Missing
vec![]
};
Self {
inner: PySetInner::from_arg(iterable, vm)?,
// Return empty fs if iterable passed is emtpy and only for exact fs types.
if elements.is_empty() && cls.is(&vm.ctx.types.frozenset_type) {
Ok(vm.ctx.empty_frozenset.clone())
} else {
Self::from_iter(vm, elements).and_then(|o| o.into_ref_with_type(vm, cls))
}
.into_ref_with_type(vm, cls)
}
#[pymethod(name = "__len__")]

View File

@@ -24,7 +24,7 @@ use crate::builtins::namespace::PyNamespace;
use crate::builtins::object;
use crate::builtins::pystr;
use crate::builtins::pytype::{self, PyType, PyTypeRef};
use crate::builtins::set;
use crate::builtins::set::{self, PyFrozenSet};
use crate::builtins::singletons::{PyNone, PyNoneRef, PyNotImplemented, PyNotImplementedRef};
use crate::builtins::slice::PyEllipsis;
use crate::builtins::staticmethod::PyStaticMethod;
@@ -89,6 +89,7 @@ pub struct PyContext {
pub false_value: PyIntRef,
pub none: PyNoneRef,
pub empty_tuple: PyTupleRef,
pub empty_frozenset: PyRef<PyFrozenSet>,
pub ellipsis: PyRef<PyEllipsis>,
pub not_implemented: PyNotImplementedRef,
@@ -129,6 +130,8 @@ impl PyContext {
PyTuple::_new(Vec::new().into_boxed_slice()),
&types.tuple_type,
);
let empty_frozenset =
PyRef::new_ref(PyFrozenSet::default(), types.frozenset_type.clone(), None);
let string_cache = Dict::default();
@@ -144,6 +147,7 @@ impl PyContext {
false_value,
none,
empty_tuple,
empty_frozenset,
ellipsis,
not_implemented,