-
Notifications
You must be signed in to change notification settings - Fork 0
A class-level __qualname__ binding that CPython rejects at class creation is accepted #982
Description
Summary
pycc accepts two class bodies that CPython rejects at class-creation time, both
involving a class-level binding named __qualname__. This is a D-198 false
acceptance in both shapes.
Split out of #980 (which fixes @property def __slots__ only). #980's guard is
value-independent by construction (D-236), and the attribute half of
__qualname__ is value-typed — so it cannot live in that guard and needs its
own generating rule plus its own ADR.
Reproductions (CPython 3.13.9, v3.13.9:8183fa5e3f7)
1. Property route
class C: @property def __qualname__(self) -> int: return 1
CPython: TypeError: type __qualname__ must be a str, not property, raised while
the class statement executes. pycc: accepted, runs, prints 1.
2. Attribute route, non-str value
class D: __qualname__: int = 1
CPython: TypeError: type __qualname__ must be a str, not int, raised while the
class statement executes. pycc: accepted, runs.
3. Attribute route, str value — agrees, must stay accepted
class D: __qualname__: str = "D"
CPython: exit 0. pycc: exit 0. This is the negative case: any fix must not
over-reject it.
Why this is not folded into #980
type.__new__ validates the type of __qualname__ rather than merely
consuming it, so the correct rule is value-typed ("__qualname__ must be bound
to a str"), not name-based. D-236's reject_reserved_class_attr_name runs
before any value extraction precisely so every class-body route can call it at
the same cheap, value-independent point; adding a value-typed name there would
break that invariant. Closing only the property half would leave the name
half-closed under a rule that does not describe it.
Acceptance criteria
-
@property def __qualname__is rejected with a message whose account is
type.__new__'s__qualname__type check at class creation. -
__qualname__: int = 1(and other non-strbindings) is rejected on the
attribute route. -
__qualname__: str = "D"stays accepted (negative test). - Unit + e2e coverage for each shape, 100% line/region coverage (D-014).
- Either a new ADR for the value-typed generating rule, or a recorded
amendment to D-236 explaining why one is not needed. - Replace the deferral pin
a_property_getter_named_qualname_is_left_to_issue_<this>
incrates/pycc_hir/src/tests/reserved_dunder_class_attrs.rs.
Pointers
crates/pycc_hir/src/class/reserved_names.rscrates/pycc_hir/src/class/body.rs(MethodKind::PropertyGetterarm)docs/decisions/D-236-reject-a-class-attribute-named-after-the-instantiation.md