mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-22 00:01:56 +00:00
![]() ## Summary This allows us to handle self-referential bounds/constraints/defaults without panicking. Handles more cases from https://github.com/astral-sh/ty/issues/256 This also changes the way we infer the types of legacy TypeVars. Rather than understanding a constructor call to `typing[_extension].TypeVar` inside of any (arbitrarily nested) expression, and having to use a special `assigned_to` field of the semantic index to try to best-effort figure out what name the typevar was assigned to, we instead understand the creation of a legacy `TypeVar` only in the supported syntactic position (RHS of a simple un-annotated assignment with one target). In any other position, we just infer it as creating an opaque instance of `typing.TypeVar`. (This behavior matches all other type checkers.) So we now special-case TypeVar creation in `TypeInferenceBuilder`, as a special case of an assignment definition, rather than deeper inside call binding. This does mean we re-implement slightly more of argument-parsing, but in practice this is minimal and easy to handle correctly. This is easier to implement if we also make the RHS of a simple (no unpacking) one-target assignment statement no longer a standalone expression. Which is fine to do, because simple one-target assignments don't need to infer the RHS more than once. This is a bonus performance (0-3% across various projects) and significant memory-usage win, since most assignment statements are simple one-target assignment statements, meaning we now create many fewer standalone-expression salsa ingredients. This change does mean that inference of manually-constructed `TypeAliasType` instances can no longer find its Definition in `assigned_to`, which regresses go-to-definition for these aliases. In a future PR, `TypeAliasType` will receive the same treatment that `TypeVar` did in this PR (moving its special-case inference into `TypeInferenceBuilder` and supporting it only in the correct syntactic position, and lazily inferring its value type to support recursion), which will also fix the go-to-definition regression. (I decided a temporary edge-case regression is better in this case than doubling the size of this PR.) This PR also tightens up and fixes various aspects of the validation of `TypeVar` creation, as seen in the tests. We still (for now) treat all typevars as instances of `typing.TypeVar`, even if they were created using `typing_extensions.TypeVar`. This means we'll wrongly error on e.g. `T.__default__` on Python 3.11, even if `T` is a `typing_extensions.TypeVar` instance at runtime. We share this wrong behavior with both mypy and pyrefly. It will be easier to fix after we pull in https://github.com/python/typeshed/pull/14840. There are some issues that showed up here with typevar identity and `MarkTypeVarsInferable`; the fix here (using the new `original` field and `is_identical_to` methods on `BoundTypeVarInstance` and `TypeVarInstance`) is a bit kludgy, but it can go away when we eliminate `MarkTypeVarsInferable`. ## Test Plan Added and updated mdtests. ### Conformance suite impact The impact here is all positive: * We now correctly error on a legacy TypeVar with exactly one constraint type given. * We now correctly error on a legacy TypeVar with both an upper bound and constraints specified. ### Ecosystem impact Basically none; in the setuptools case we just issue slightly different errors on an invalid TypeVar definition, due to the modified validation code. --------- Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com> |
||
---|---|---|
.. | ||
annotations | ||
assignment | ||
binary | ||
boolean | ||
boundness_declaredness | ||
call | ||
class | ||
comparison | ||
comprehensions | ||
conditional | ||
dataclasses | ||
declaration | ||
diagnostics | ||
directives | ||
doc | ||
exception | ||
expression | ||
function | ||
generics | ||
ide_support | ||
import | ||
literal | ||
loops | ||
narrow | ||
regression | ||
scopes | ||
shadowing | ||
snapshots | ||
stubs | ||
subscript | ||
suppressions | ||
type_compendium | ||
type_of | ||
type_properties | ||
type_qualifiers | ||
unary | ||
with | ||
.mdformat.toml | ||
async.md | ||
attributes.md | ||
classes.md | ||
cycle.md | ||
decorators.md | ||
del.md | ||
deprecated.md | ||
descriptor_protocol.md | ||
enums.md | ||
exhaustiveness_checking.md | ||
final.md | ||
implicit_type_aliases.md | ||
instance_layout_conflict.md | ||
intersection_types.md | ||
invalid_syntax.md | ||
known_constants.md | ||
mdtest_config.md | ||
mdtest_custom_typeshed.md | ||
metaclass.md | ||
mro.md | ||
named_tuple.md | ||
overloads.md | ||
pep695_type_aliases.md | ||
properties.md | ||
protocols.md | ||
public_types.md | ||
statically_known_branches.md | ||
sys_platform.md | ||
sys_version_info.md | ||
t_strings.md | ||
terminal_statements.md | ||
ty_extensions.md | ||
typed_dict.md | ||
union_types.md | ||
unpacking.md | ||
unreachable.md |