Repository navigation
Defer custom-MRO subclass publication until initialization succeeds #9527
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 all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1152,16 +1152,16 @@ impl PyType { | |
| if !defer_mro { | ||
| new_type.mro.write().insert(0, new_type.clone()); | ||
| new_type.init_slots(ctx); | ||
| } | ||
|
|
||
| let weakref_type = super::PyWeak::static_type(); | ||
| for base in new_type.bases.read().as_slice() { | ||
| base.subclasses.write().push( | ||
| new_type | ||
| .as_object() | ||
| .downgrade_with_weakref_typ_opt(None, weakref_type.to_owned()) | ||
| .unwrap(), | ||
| ); | ||
| let weakref_type = super::PyWeak::static_type(); | ||
| for base in new_type.bases.read().as_slice() { | ||
| base.subclasses.write().push( | ||
| new_type | ||
| .as_object() | ||
| .downgrade_with_weakref_typ_opt(None, weakref_type.to_owned()) | ||
| .unwrap(), | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| Ok(new_type) | ||
|
|
@@ -2423,6 +2423,26 @@ impl Constructor for PyType { | |
| } | ||
| } | ||
|
|
||
| if custom_mro { | ||
| // Like CPython's type_ready_publish, expose the type only after | ||
| // its MRO and slots are initialized. A failed custom mro() may | ||
| // leave the incomplete type alive through a user reference. | ||
| Self::with_type_lock(vm, || { | ||
| let weak = typ | ||
| .as_object() | ||
| .downgrade_with_weakref_typ_opt(None, super::PyWeak::static_type().to_owned()) | ||
| .unwrap(); | ||
| for base in typ.bases.read().as_slice() { | ||
| let mut subclasses = base.subclasses.write(); | ||
| // A reentrant __bases__ assignment may have registered | ||
| // this type already. Callback-free weakrefs are cached. | ||
| if !subclasses.iter().any(|existing| existing.is(&weak)) { | ||
|
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.
When many dynamic classes are created with a custom metaclass—for example repeated Useful? React with 👍 / 👎. |
||
| subclasses.push(weak.clone()); | ||
| } | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| // avoid deadlock | ||
| let attributes = typ | ||
| .attributes | ||
|
|
||
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.
If a custom
mro()callscollections.abc.Sequence.register(Base)(orMapping.register(Base)) while constructingChild(Base), deferring this link means_abc_register()'sset_abc_collection_flags_recursive()no longer reachesChild.new_heap_inner()copied the collection flags before the callback, and neitherinit_slots()norupdate_subclass_flags_recursive()refreshesPyTypeFlags::COLLECTION, so the completed child keeps stale flags and sequence/mapping patterns silently fail to match its instances. The old early link propagated the registration correctly. Refresh the inherited collection flags after the callback and before publishing the type.Useful? React with 👍 / 👎.