Skip to content

Commit 504a08b

Browse files
youknowdotcodex
andauthored
Defer custom-MRO subclass publication until initialization succeeds (#9527)
* Publish custom-MRO subclasses only after initialization Keep a type whose custom MRO failed out of its bases subclass lists until its MRO and slots are initialized. Register current bases under the type lock and reuse the cached callback-free weak reference to avoid duplicate registration after reentrant __bases__ assignment. Assisted-by: OpenAI Codex: model version unavailable * Use Self for the deferred publication type lock Address clippy::use_self without changing initialization or locking behavior. Assisted-by: OpenAI Codex: model version unavailable --------- Co-authored-by: Codex <codex@openai.com>
1 parent ef023bc commit 504a08b

1 file changed

Lines changed: 29 additions & 9 deletions

File tree

‎crates/vm/src/builtins/type.rs‎

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,16 +1152,16 @@ impl PyType {
11521152
if !defer_mro {
11531153
new_type.mro.write().insert(0, new_type.clone());
11541154
new_type.init_slots(ctx);
1155-
}
11561155

1157-
let weakref_type = super::PyWeak::static_type();
1158-
for base in new_type.bases.read().as_slice() {
1159-
base.subclasses.write().push(
1160-
new_type
1161-
.as_object()
1162-
.downgrade_with_weakref_typ_opt(None, weakref_type.to_owned())
1163-
.unwrap(),
1164-
);
1156+
let weakref_type = super::PyWeak::static_type();
1157+
for base in new_type.bases.read().as_slice() {
1158+
base.subclasses.write().push(
1159+
new_type
1160+
.as_object()
1161+
.downgrade_with_weakref_typ_opt(None, weakref_type.to_owned())
1162+
.unwrap(),
1163+
);
1164+
}
11651165
}
11661166

11671167
Ok(new_type)
@@ -2423,6 +2423,26 @@ impl Constructor for PyType {
24232423
}
24242424
}
24252425

2426+
if custom_mro {
2427+
// Like CPython's type_ready_publish, expose the type only after
2428+
// its MRO and slots are initialized. A failed custom mro() may
2429+
// leave the incomplete type alive through a user reference.
2430+
Self::with_type_lock(vm, || {
2431+
let weak = typ
2432+
.as_object()
2433+
.downgrade_with_weakref_typ_opt(None, super::PyWeak::static_type().to_owned())
2434+
.unwrap();
2435+
for base in typ.bases.read().as_slice() {
2436+
let mut subclasses = base.subclasses.write();
2437+
// A reentrant __bases__ assignment may have registered
2438+
// this type already. Callback-free weakrefs are cached.
2439+
if !subclasses.iter().any(|existing| existing.is(&weak)) {
2440+
subclasses.push(weak.clone());
2441+
}
2442+
}
2443+
});
2444+
}
2445+
24262446
// avoid deadlock
24272447
let attributes = typ
24282448
.attributes

0 commit comments

Comments
 (0)