Uh oh!
There was an error while loading. Please reload this page.
Detect metaclass conflicts, refs #13563 - #13598
Conversation
sobolevn
commented
Sep 3, 2022
@AlexWaygood do you have any suggestions about the error message? 🤔 |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
1 similar comment
According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉 |
| metaclasses = [ | ||
| entry.metaclass_type | ||
| for entry in typ.mro[1:-1] | ||
| if entry.metaclass_type | ||
| and not is_named_instance(entry.metaclass_type, "builtins.type") | ||
| ] | ||
| if not metaclasses: | ||
| return | ||
| if typ.metaclass_type is not None and all( | ||
| is_subtype(typ.metaclass_type, meta) for meta in metaclasses | ||
| ): | ||
| return | ||
| self.fail( | ||
| "Metaclass conflict: the metaclass of a derived class must be " | ||
| "a (non-strict) subclass of the metaclasses of all its bases", | ||
| typ, | ||
| ) |
There was a problem hiding this comment.
Maybe you could do something like this, to improve the error message:
| metaclasses= [ | |
| entry.metaclass_type | |
| forentryintyp.mro[1:-1] | |
| ifentry.metaclass_type | |
| andnotis_named_instance(entry.metaclass_type, "builtins.type") | |
| ] | |
| ifnotmetaclasses: | |
| return | |
| iftyp.metaclass_typeisnotNoneandall( | |
| is_subtype(typ.metaclass_type, meta) formetainmetaclasses | |
| ): | |
| return | |
| self.fail( | |
| "Metaclass conflict: the metaclass of a derived class must be " | |
| "a (non-strict) subclass of the metaclasses of all its bases", | |
| typ, | |
| ) | |
| subclass_metaclass=typ.metaclass_type | |
| ifsubclass_metaclassisNone: | |
| return | |
| forsuperclassintyp.mro[1:-1]: | |
| superclass_metaclass=superclass.metaclass_type | |
| ifsuperclass_metaclassisNoneoris_named_instance( | |
| superclass_metaclass, "builtins.type" | |
| ): | |
| continue | |
| ifnotis_subtype(subclass_metaclass, superclass_metaclass): | |
| self.fail( | |
| ( | |
| f"Metaclass conflict: metaclass {subclass_metaclass.fullname!r} " | |
| f"is not a subclass of {superclass_metaclass.fullname!r}, " | |
| f"the metaclass of base class {superclass.fullname!r}" | |
| ), | |
| typ | |
| ) |
There was a problem hiding this comment.
I've tried it and I didn't like it. Why?
Because it either reports several errors for several bases with incompatible metaclasses or reports just one (if break is added) which is potentially confusing or we need even more complex code to accumulate all problematic base types and then raise a single one.
Let's keep it as-is for now?
If someone complains, then we can easily make this more readable and more complex.
(This is why I love coping CPython's error messages 😆 )
There was a problem hiding this comment.
Let's keep it as-is for now?
Sure, the PR looks pretty good right now! It was just an idea :)
sobolevn
commented
Sep 4, 2022
Thanks everyone! 👏 |
Recreate of #13565