[ty] Add unbound type variable detection in annotations#23641
[ty] Add unbound type variable detection in annotations#23641AlexWaygood merged 6 commits intomainfrom
Conversation
Typing conformance results improved 🎉The percentage of diagnostics emitted that were expected errors increased from 85.80% to 85.90%. The percentage of expected errors that received a diagnostic increased from 77.40% to 78.04%. Summary
True positives addedDetails
|
Memory usage reportSummary
Significant changesClick to expand detailed breakdowntrio
|
|
|
| Lint rule | Added | Removed | Changed |
|---|---|---|---|
unbound-type-variable |
9 | 0 | 0 |
unused-type-ignore-comment |
0 | 6 | 0 |
invalid-argument-type |
0 | 2 | 0 |
invalid-assignment |
0 | 1 | 0 |
invalid-type-arguments |
0 | 1 | 0 |
| Total | 9 | 10 | 0 |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
|
Claude managed to minimize the new diagnostics on pytest and streamlit. The root cause of the false positives appear to be dependencies that aren't installed during runs of mypy_primer and ecosystem-analyzer. Claude analysisClaude analysisHere are the minimized reproductions for the new pytestOriginal file: Root cause: Minimal reproduction: from typing import TypeVar
T = TypeVar("T")
class Child(UndefinedName[T]):
x: T # error: [unbound-type-variable]When the base class name is undefined/unresolvable, the class never gets a generic context, so streamlitOriginal file: Root cause: The method Minimal reproduction: from __future__ import annotations
from typing import TypeVar
T = TypeVar("T")
class Mixin:
def method(self, x: UndefinedType[T]) -> UndefinedType[T]:
y: T # error: [unbound-type-variable]When Shared root causeBoth cases share the same underlying issue: when a TypeVar The fix would likely involve suppressing the |
crates/ty_python_semantic/src/types/infer/builder/annotation_expression.rs
Outdated
Show resolved
Hide resolved
crates/ty_python_semantic/src/types/infer/builder/type_expression.rs
Outdated
Show resolved
Hide resolved
… their bound scope This adds validation for three missing checks around correct use of type variables: 1. Reject unbound type variables in module-scope annotations (e.g., `x: T`) 2. Reject unbound type variables in function/class bodies where they aren't part of the enclosing generic context (e.g., `S` inside `def f(x: T)`) 3. Reject type variables from outer class scopes used in inner class bodies (e.g., `class C[T]: class Bad: x: T`) The implementation: - Adds a new `UNBOUND_TYPE_VARIABLE` lint rule in diagnostic.rs - Modifies `bind_typevar` in generics.rs to track class scope boundaries, preventing inner classes from accessing outer class type parameters - Adds `check_for_unbound_type_variable` method in type_expression.rs that detects when a TypeVar remains unbound after `in_type_expression` processing - Uses a `check_unbound_typevars` flag on the builder, enabled only during annotation expression processing, to avoid false positives in TypeVar defaults, explicit class specialization, and other internal contexts - Updates existing TODO test comments in scoping.md to proper error assertions https://claude.ai/code/session_01FUqdwkfw72xwPnuhqqpvp6
4d7a411 to
0ff1a04
Compare
Co-authored-by: Douglas Creager <dcreager@dcreager.net>
* main: (30 commits) [ty] Introduce `types::bool`, `types::context_manager` and `types::iteration` (#23681) [ty] Move `KnownInstanceType`, and related types, to a new `known_instance.rs` submodule (#23680) [ty] Add `invalid-enum-member-annotation` lint rule (#23648) [`ruff`] Fix false positive for `re.split` with empty string pattern (`RUF055`) (#23634) [ty] Move `UnionType` and `IntersectionType` to a new `types::set_theoretic` submodule (#23678) [ty] Add unbound type variable detection in annotations (#23641) [ty] Remove `specialize_constrained` from constraint set module (#23677) [ty] Add partial support and validation for `Unpack` when used with tuple types (#23651) Update prek dependencies (#23661) [ty] make `StaticClassLiteral::explicit_bases` converge better in cycles (#23601) Improvements to CLAUDE.md (#23633) [ty] Move subscript logic out of `builder.rs` (#23653) Update Artifact GitHub Actions dependencies (#23676) Update actions/attest-build-provenance to 4.1.0 (#23654) Update Rust crate clearscreen to v4.0.5 (#23664) fix renovate `actions/*-artifact` updates (#23675) Update Rust crate clap to v4.5.60 (#23663) Update Rust crate unicode-ident to v1.0.24 (#23668) Update Rust crate anyhow to v1.0.102 (#23662) Update Rust crate pyproject-toml to v0.13.7 (#23666) ...
Summary
This PR adds detection and reporting of unbound type variables used in type annotations. Type variables that are not bound to any enclosing generic context now produce an
unbound-type-variableerror.The ecosystem results on a first version of this PR revealed that there is no consensus among type checkers about how to handle apparently unbound type variables appearing inside
Callableannotations, e.g.Multiplay gist: a1739f1cca18857e3cec946d00ef1449.
I didn't want to tackle that question here, so for now I've added special casing so that we avoid flagging any unbound type variables inside
Callabletypes. This isn't a long-term solution; see the mdtests I've added for more details.Test Plan
mdtests updated and extended