Summary
Non-terminating (non-regular / polymorphic) recursive type aliases are reported under generics_syntax_scoping with the message "Circular type alias definition". Rejecting them is a defensible engineering decision, but the code and the wording are both wrong, and neither is backed by the typing spec.
This is filed as a house-rule / diagnostic-quality issue, explicitly not a conformance issue.
Found via the "type torture" puzzle on X: https://x.com/charliermarsh/status/2082885991686090885
Current behaviour
type R[T] = set[R[T | R[T]]]
error[generics_syntax_scoping]: Circular type alias definition: `R` references itself with different type arguments
--> t.py:2:6
= help: Recursive type aliases must reference themselves with the same type parameters
= see: https://www.basilisk-python.dev/errors/generics_syntax_scoping
Three problems
1. It is not a scoping error. generics_syntax_scoping is the bucket for PEP 695 scoping rules. Nothing here is out of scope — the alias resolves fine, it just does not have a finite normal form. Sharing a code with an unrelated rule makes the diagnostic un-configurable and un-searchable, and it distorts the meaning of the generics_syntax_scoping code for users who suppress or route it.
2. "Circular" is the wrong word. Plain circularity is legal and widely supported — PEP 695 formally mandates that recursive type aliases work, and every major checker supports them. Telling a user their recursive alias is "circular" implies recursion itself is the problem. The actual property is that expansion does not terminate: each expansion of R[T] grows its own type argument, so there is no fixed point.
3. The help text states a rule that is stricter than what is enforced. "Recursive type aliases must reference themselves with the same type parameters" is not a spec rule, and it is not even what the checker does — it is a description of the workaround.
Proposal
Give it its own opt-in house rule, separate from the PEP conformance set:
- Code: something like
non-regular-recursive-alias (BSK-xxxx), registered as an opinionated rule per [CHKARCH-CONFIGURATION-ONLY], since no PEP requires it.
- Message: "type alias
R expands infinitely: each expansion of R[T] grows its type argument, so the alias has no finite form".
- Help: point at the fix — introduce a named intermediate alias, or drop the growing argument — rather than restating a rule that does not exist.
- Docs page: a real
/errors/BSK-xxxx entry explaining non-regular recursion, so the see: link answers the question the diagnostic raises.
Spec position
The typing spec's aliases chapter says nothing about recursive aliases at all, let alone banning non-regular ones; its only explicit type-statement errors are non-annotation expression forms and use of legacy TypeVars. So this diagnostic is Basilisk policy, and it should be labelled and configured as policy.
Related
The inverse defect — legal recursive aliases being rejected by the same rule — is #371, and is a genuine conformance-grade false positive. That one must be fixed regardless of what happens to this one. Splitting the codes makes both tractable: one rule for "this recursion does not terminate" (opt-in policy), and no diagnostic at all for ordinary recursion.
Summary
Non-terminating (non-regular / polymorphic) recursive type aliases are reported under
generics_syntax_scopingwith the message "Circular type alias definition". Rejecting them is a defensible engineering decision, but the code and the wording are both wrong, and neither is backed by the typing spec.This is filed as a house-rule / diagnostic-quality issue, explicitly not a conformance issue.
Found via the "type torture" puzzle on X: https://x.com/charliermarsh/status/2082885991686090885
Current behaviour
Three problems
1. It is not a scoping error.
generics_syntax_scopingis the bucket for PEP 695 scoping rules. Nothing here is out of scope — the alias resolves fine, it just does not have a finite normal form. Sharing a code with an unrelated rule makes the diagnostic un-configurable and un-searchable, and it distorts the meaning of thegenerics_syntax_scopingcode for users who suppress or route it.2. "Circular" is the wrong word. Plain circularity is legal and widely supported — PEP 695 formally mandates that recursive type aliases work, and every major checker supports them. Telling a user their recursive alias is "circular" implies recursion itself is the problem. The actual property is that expansion does not terminate: each expansion of
R[T]grows its own type argument, so there is no fixed point.3. The
helptext states a rule that is stricter than what is enforced. "Recursive type aliases must reference themselves with the same type parameters" is not a spec rule, and it is not even what the checker does — it is a description of the workaround.Proposal
Give it its own opt-in house rule, separate from the PEP conformance set:
non-regular-recursive-alias(BSK-xxxx), registered as an opinionated rule per [CHKARCH-CONFIGURATION-ONLY], since no PEP requires it.Rexpands infinitely: each expansion ofR[T]grows its type argument, so the alias has no finite form"./errors/BSK-xxxxentry explaining non-regular recursion, so thesee:link answers the question the diagnostic raises.Spec position
The typing spec's aliases chapter says nothing about recursive aliases at all, let alone banning non-regular ones; its only explicit
type-statement errors are non-annotation expression forms and use of legacy TypeVars. So this diagnostic is Basilisk policy, and it should be labelled and configured as policy.Related
The inverse defect — legal recursive aliases being rejected by the same rule — is #371, and is a genuine conformance-grade false positive. That one must be fixed regardless of what happens to this one. Splitting the codes makes both tractable: one rule for "this recursion does not terminate" (opt-in policy), and no diagnostic at all for ordinary recursion.