Fix defaultdict

This commit is contained in:
Jeong YunWon
2025-08-26 17:18:05 +09:00
parent be54bc0dfd
commit f4543f5f51
2 changed files with 40 additions and 10 deletions

View File

@@ -1337,7 +1337,6 @@ class TestPatma(unittest.TestCase):
self.assertEqual(x, [0, 1, 2])
self.assertEqual(y, 0)
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_patma_133(self):
x = collections.defaultdict(int, {0: 1})
match x:
@@ -1350,7 +1349,6 @@ class TestPatma(unittest.TestCase):
self.assertEqual(x, {0: 1})
self.assertEqual(y, 2)
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_patma_134(self):
x = collections.defaultdict(int, {0: 1})
match x:
@@ -1364,7 +1362,6 @@ class TestPatma(unittest.TestCase):
self.assertEqual(y, 2)
self.assertEqual(z, {0: 1})
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_patma_135(self):
x = collections.defaultdict(int, {0: 1})
match x:

View File

@@ -1332,14 +1332,47 @@ impl ExecutingFrame<'_> {
let mut values = Vec::new();
let mut all_match = true;
for key in keys {
match subject.get_item(key.as_object(), vm) {
Ok(value) => values.push(value),
Err(e) if e.fast_isinstance(vm.ctx.exceptions.key_error) => {
all_match = false;
break;
// We use the two argument form of map.get(key, default) for two reasons:
// - Atomically check for a key and get its value without error handling.
// - Don't cause key creation or resizing in dict subclasses like
// collections.defaultdict that define __missing__ (or similar).
// See CPython's _PyEval_MatchKeys
if let Some(get_method) = vm
.get_method(subject.to_owned(), vm.ctx.intern_str("get"))
.transpose()?
{
// dummy = object()
// CPython: dummy = _PyObject_CallNoArgs((PyObject *)&PyBaseObject_Type);
let dummy = vm
.ctx
.new_base_object(vm.ctx.types.object_type.to_owned(), None);
for key in keys {
// value = map.get(key, dummy)
match get_method.call((key.as_object(), dummy.clone()), vm) {
Ok(value) => {
// if value == dummy: key not in map!
if value.is(&dummy) {
all_match = false;
break;
}
values.push(value);
}
Err(e) => return Err(e),
}
}
} else {
// Fallback if .get() method is not available (shouldn't happen for mappings)
for key in keys {
match subject.get_item(key.as_object(), vm) {
Ok(value) => values.push(value),
Err(e) if e.fast_isinstance(vm.ctx.exceptions.key_error) => {
all_match = false;
break;
}
Err(e) => return Err(e),
}
Err(e) => return Err(e),
}
}