Skip to content

Navigation Menu

Sign in
Sign up

A class-level __qualname__ binding that CPython rejects at class creation is accepted #982

Open
Milestone

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-str bindings) 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>
    in crates/pycc_hir/src/tests/reserved_dunder_class_attrs.rs.

Pointers

  • crates/pycc_hir/src/class/reserved_names.rs
  • crates/pycc_hir/src/class/body.rs (MethodKind::PropertyGetter arm)
  • docs/decisions/D-236-reject-a-class-attribute-named-after-the-instantiation.md

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    AltStyle によって変換されたページ (->オリジナル) /