Skip to content

[ty] Validate free type variables in ClassVar annotations - #29132

Draft
charliermarsh wants to merge 8 commits into
charlie/codex-explicit-type-visitorsfrom
charlie/codex-classvar-typevars
Draft

charliermarsh wants to merge 8 commits into
charlie/codex-explicit-type-visitorsfrom
charlie/codex-classvar-typevars

Conversation

@charliermarsh

@charliermarsh charliermarsh commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Summary

We now reject ClassVar annotations whose types contain free type variables hidden by aliases or captured in protocol members and TypedDict fields. We also allow Self in generic classes and type variables bound by a nested callable's own signature.

from typing import ClassVar

type Items[T] = list[T]

class Container[T]:
    values: ClassVar[Items[T]]  # Error: ClassVar cannot contain type variables

The traversal expands alias values so unused arguments and arguments erased by specialization do not cause errors. It tracks callable bindings and treats type-variable bounds and defaults as metadata.

We follow finite recursive specializations, including cases where a protocol member or TypedDict field exposes a variable only after the first specialization. The shared recursion analysis distinguishes fixed outer variables from captures whose binding definitions also participate in the recursion. Occurrences beyond growing or unresolved recursive references can still remain undiagnosed; an incomplete search does not produce an error.

We reuse completed searches under the same callable bindings to avoid repeatedly traversing shared types, such as those in Pydantic's CoreSchema. An incomplete recursive search cannot supply a cached result.

Builds on #29155.

@charliermarsh
charliermarsh requested a review from a team as a code owner October 6, 2026 14:14
@charliermarsh charliermarsh added bug An issue describing something that isn't working, or a PR that fixes a bug ty The ty type checker labels Oct 6, 2026
@astral-sh-bot
astral-sh-bot Bot requested a review from carljm October 6, 2026 14:15
@charliermarsh
charliermarsh added this pull request to stack #29134 October 6, 2026 14:16
@charliermarsh
charliermarsh marked this pull request as draft October 6, 2026 14:17
@astral-sh-bot

astral-sh-bot Bot commented Oct 6, 2026

Copy link
Copy Markdown

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 98.24%. The percentage of expected errors that received a diagnostic held steady at 98.24%. The number of fully passing files held steady at 134/146.

@astral-sh-bot

astral-sh-bot Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Memory usage report

Summary

Project Old New Diff Outcome
prefect 475.10MB 475.11MB +0.00% (14.84kB) ⏫
sphinx 172.45MB 172.45MB +0.00% (1.09kB) ⏫
flake8 38.28MB 38.28MB - ✅
trio 92.58MB 92.58MB - ✅

Significant changes

Click to expand detailed breakdown

prefect

Name Old New Diff Outcome
infer_definition_types 37.83MB 37.83MB +0.01% (5.44kB) ⏫
ProtocolInterface 909.11kB 910.94kB +0.20% (1.84kB) ⏫
place_by_id 4.11MB 4.11MB +0.03% (1.28kB) ⏫
code_generator_of_static_class 392.98kB 393.98kB +0.26% (1.01kB) ⏫
model_config 113.21kB 114.22kB +0.89% (1.01kB) ⏫
cached_protocol_interface 304.07kB 304.96kB +0.29% (912.00B) ⏫
CallableType 8.94MB 8.94MB +0.01% (696.00B) ⏫
PropertyInstanceType 177.44kB 177.84kB +0.22% (408.00B) ⏫
function_known_decorators 1.82MB 1.82MB +0.01% (244.00B) ⏫
infer_deferred_types 4.81MB 4.81MB +0.00% (236.00B) ⏫
remove_self_inner::interned_arguments 256.57kB 256.78kB +0.08% (216.00B) ⏫
place_by_id::interned_arguments 2.94MB 2.94MB +0.01% (216.00B) ⏫
GenericAlias<'db>::try_mro_ 4.54MB 4.54MB +0.00% (216.00B) ⏫
Type<'db>::apply_specialization_inner_ 2.96MB 2.96MB -0.01% (192.00B) ⬇️
GenericContext 2.27MB 2.27MB +0.01% (156.00B) ⏫
... 22 more

sphinx

Name Old New Diff Outcome
infer_definition_types 11.71MB 11.72MB +0.01% (1.06kB) ⏫
infer_scope_types_impl 6.20MB 6.20MB +0.00% (32.00B) ⏫

@astral-sh-bot

astral-sh-bot Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-type-form 0 2 0
Total 0 2 0

Flaky changes detected. This PR summary excludes flaky changes; see the HTML report for details.

Raw diff:

discord.py (https://github.com/Rapptz/discord.py)
- discord/ui/action_row.py:122:36 error[invalid-type-form] `ClassVar` cannot contain type variables
- discord/ui/container.py:109:35 error[invalid-type-form] `ClassVar` cannot contain type variables

Full report with detailed diff (timing results)

@charliermarsh
charliermarsh force-pushed the charlie/codex-classvar-typevars branch from f8aba03 to 152f881 Compare October 6, 2026 15:08
@charliermarsh
charliermarsh force-pushed the charlie/codex-classvar-typevars branch 3 times, most recently from 7bc0e4a to c1eaaf1 Compare October 6, 2026 16:53
@charliermarsh
charliermarsh force-pushed the charlie/codex-classvar-typevars branch from ac5d888 to b5875ea Compare October 6, 2026 18:00
@charliermarsh
charliermarsh force-pushed the charlie/codex-classvar-typevars branch from b5875ea to bfa4db6 Compare October 6, 2026 18:36
charliermarsh and others added 3 commits October 6, 2026 15:55
Reject instance arguments even when their members or type arguments contain TypeVarTuple objects. Avoid searching those members, which can recurse through changing specializations.

Co-authored-by: Ibraheem Ahmed <ibraheem@ibraheem.ca>
Co-authored-by: Ibraheem Ahmed <ibraheem@ibraheem.ca>
Inspect dependencies on the setter signature explicitly, including recursive aliases, protocols, and TypedDicts. Recursive specializations that are independent of the setter parameters retain their writable-member checks.

Co-authored-by: Ibraheem Ahmed <ibraheem@ibraheem.ca>
@charliermarsh
charliermarsh force-pushed the charlie/codex-classvar-typevars branch from bfa4db6 to de8a824 Compare October 6, 2026 20:03
@charliermarsh
charliermarsh removed this pull request from stack #29134 October 6, 2026 20:05
@charliermarsh
charliermarsh added this pull request to stack #29150 October 6, 2026 20:05
Co-authored-by: Ibraheem Ahmed <ibraheem@ibraheem.ca>
@charliermarsh
charliermarsh force-pushed the charlie/codex-classvar-typevars branch from de8a824 to aea36f4 Compare October 6, 2026 23:27
charliermarsh and others added 2 commits October 6, 2026 19:44
Co-authored-by: Ibraheem Ahmed <ibraheem@ibraheem.ca>
Co-authored-by: Ibraheem Ahmed <ibraheem@ibraheem.ca>
@charliermarsh
charliermarsh force-pushed the charlie/codex-classvar-typevars branch from aea36f4 to 2b68aa1 Compare October 6, 2026 23:47
@charliermarsh
charliermarsh removed this pull request from stack #29150 October 6, 2026 23:50
@charliermarsh
charliermarsh changed the base branch from charlie/lazy-type-traversal to charlie/codex-explicit-type-visitors October 6, 2026 23:50
@charliermarsh
charliermarsh added this pull request to stack #29156 October 6, 2026 23:50
@charliermarsh
charliermarsh force-pushed the charlie/codex-classvar-typevars branch from 2b68aa1 to b8fdf4a Compare October 7, 2026 01:00

This branch was successfully deployed

1 active deployment
automations — b8fdf4ad Deployed Oct 7, 2026 by charliermarsh via security-review / security review #90894
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug An issue describing something that isn't working, or a PR that fixes a bug ty The ty type checker

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant