Commit Graph

1360 Commits

Author SHA1 Message Date
Andrew Gallant
2784461741 [ty] Get rid of high-level completion deduplication
It turns out this wasn't actually doing much and was just papering over
the possibility of duplicates being returned from `SemanticModel`. So
this was doing a fair bit of work for no good reason.

Instead, we push deduplication down into semantic completions directly.
This will run over a (typically) much smaller number of completions.

With that said, this doesn't seem to lead to improvement in ad hoc
benchmarking. However, perf wasn't really the main motivation here: this
change is primarily to prep for switching to a max-heap. This
deduplication was problematic because it was being done *after* sorting,
which meant it dependend on having the entire set of completions in
memory. But with a max-heap, we'll only keep around the top-K
completions, so deduplication has to be done "earlier" (if at all).
2026-01-20 09:37:39 -05:00
Charlie Marsh
0a1dddbf73 [ty] Emit invalid type form for stringified annotations (#22752)
## Summary

Closes https://github.com/astral-sh/ty/issues/2553.
2026-01-20 08:37:55 +00:00
Alex Waygood
af886b06c9 [ty] Allow if type(x) is Y narrowing for types other than class-literal types (#22729)
## Summary

Fixes https://github.com/astral-sh/ty/issues/2565.

This PR adds support for `if type(x) is Y` narrowing where `Y` is a
subclass-of type, type-alias type, or typevar type.

## Test Plan

mdtests
2026-01-20 08:23:00 +00:00
Dhruv Manilawala
0cbe2af18b [ty] Add basic support for overloads in ParamSpec (#21946)
## Summary

fixes: https://github.com/astral-sh/ty/issues/1838

This PR adds basic support for overloaded function when used to
specialize a `ParamSpec` type variable.

Following cases are still remaining:
1. Updating the specialization with the matching overload after the
paramspec sub-call logic
2. Updating the specialization with the matching overload using the
return type

Both of these cases are present in the mdtest file.

## Test Plan

Update mdtest with new cases.
2026-01-20 04:14:05 +00:00
Charlie Marsh
7f9b10a193 [ty] Narrow on bool and byte subscripts (#22684)
## Summary

Low-hanging fruit...
2026-01-19 14:31:38 +00:00
Alex Waygood
5949fa0b93 [ty] Improve readability of some NamedTuple code (#22723) 2026-01-19 14:10:22 +00:00
Charlie Marsh
2abaff046e [ty] Narrow on negative subscript indexing (#22682)
## Summary

Negative subscripts are also indicative of a thing being subcriptable:

```python
class Subscriptable:
    def __getitem__(self, key: int) -> int:
        return 42

class NotSubscriptable: ...

def _(x: list[Subscriptable | NotSubscriptable]):
    if not isinstance(x[-1], NotSubscriptable):
        # After narrowing, x[-1] excludes NotSubscriptable, which means subscripting works
        reveal_type(x[-1])  # revealed: Subscriptable & ~NotSubscriptable
        reveal_type(x[-1][0])  # revealed: int
```
2026-01-19 09:04:08 -05:00
Charlie Marsh
0793bfdb16 [ty] Avoid overload errors when detecting dataclass-on-tuple (#22687)
## Summary

Fixes some TODOs introduced in #22672 around cases like the following:


```python
from collections import namedtuple
from dataclasses import dataclass

NT = namedtuple("NT", "x y")

# error: [invalid-dataclass] "Cannot use `dataclass()` on a `NamedTuple` class"
dataclass(NT)
```

On main, `dataclass(NT)` emits `# error: [no-matching-overload]`
instead, which is wrong -- the overload does match! On main, the logic
proceeds as follows:

1. `dataclass` has two overloads:
  - `dataclass(cls: type[_T], ...) -> type[_T]`
  - `dataclass(cls: None = None, ...) -> Callable[[type[_T]], type[_T]]`
2. When `dataclass(NT)` is called:
- Arity check: Both overloads accept one positional argument, so both
pass.
- Type checking on first overload: `NT` matches `type[_T]`... but then
`invalid_dataclass_target()` runs and adds `InvalidDataclassApplication`
error
- Type checking on second overload: `NT` doesn't match `None`, so we
have a type error.
3. After type checking, both overloads have errors.
4. `matching_overload_index()` filters by
`overload.as_result().is_ok()`, which checks if `errors.is_empty()`.
Since both overloads have errors, neither matches...
5. We emit the "No overload matches arguments" error.

Instead, we now differentiate between non-matching errors, and errors
that occur when we _do_ match, but the call has some other semantic
failure.
2026-01-19 13:55:11 +00:00
Alex Waygood
aac0562c28 [ty] Fix the inferred MRO of functional namedtuple classes (#22722) 2026-01-19 13:48:51 +00:00
Charlie Marsh
52ce26bd41 [ty] Avoid reporting overload errors for successful union variants (#22688)
## Summary

Consider `x: str | bytes` and then `x.split(" ")`. Because we have a
union, and at least one variant errors (`bytes` expects a `Buffer`, not
a `str`), we call `binding.report_diagnostics` for each variant. For the
`str` variant, it has two overloads that both match arity, but only one
actually matches the signature... So
`matching_overload_before_type_checking` is `None` (because they both
match arity), but we don't actually have an error, and we fall through
to `NO_MATCHING_OVERLOAD`.

If one variant succeeds, we should avoid reporting errors for it, even
if not _all_ variants matched.
2026-01-19 08:40:31 -05:00
Alex Waygood
9eff10c79f [ty] Use smallvec_inline! more consistently (#22720) 2026-01-19 13:29:01 +00:00
Alex Waygood
d19c962d5e [ty] Use fluent style more, and reduce allocations, when constructing Parameters instances (#22719) 2026-01-19 13:23:28 +00:00
Micha Reiser
55a174ed95 [ty] Update 'added-in' version of some rules (#22713) 2026-01-19 09:39:35 +01:00
Zanie Blue
bc05cc3c6f [ty] Cache ClassType::nearest_disjoint_base (#22065) 2026-01-19 09:22:53 +01:00
Micha Reiser
65b7fc9e73 [ty] Support overriding respect-type-ignore-comments (#22615) 2026-01-19 08:09:42 +00:00
Alex Waygood
7c9803310e [ty] Set None as the definition of Self type variables (#22648) 2026-01-18 19:04:40 +00:00
Alexandr
bab571c12c [ty] Recognize string-literal types as subtypes of Sequence[Literal[chars]] (#22415)
Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
2026-01-18 17:43:44 +00:00
Charlie Marsh
57c98a1f07 [ty] Emit diagnostic for NamedTuple and TypedDict decorated with dataclass (#22672)
## Summary

Closes https://github.com/astral-sh/ty/issues/2515.

Closes https://github.com/astral-sh/ty/issues/2527.
2026-01-18 17:20:09 +00:00
Charlie Marsh
ac8c85eb8c [ty] Support passing typename and field_names by keyword argument (#22660)
## Summary

Closes https://github.com/astral-sh/ty/issues/2549.
2026-01-17 19:02:34 -05:00
Alex Waygood
3608c620ac [ty] Right-hand side narrowing for if Foo is type(x) expressions (#22608) 2026-01-17 15:49:51 +00:00
Charlie Marsh
df58d67974 [ty] Validate constructor arguments when a class is used as a decorator (#22377)
## Summary

If a class is used as a decorator, we now use the class constructor.

Closes https://github.com/astral-sh/ty/issues/2232.
2026-01-17 10:48:59 -05:00
Alex Waygood
6b16931169 [ty] Simple syntactic validation for PEP-613 type aliases (#22652) 2026-01-17 15:43:50 +00:00
Alex Waygood
2e4774623c [ty] Ban NewTypes with generic bases (#22653) 2026-01-17 15:23:53 +00:00
Matthew Mckee
ebf7d0cd2f [ty] Don't add a subdiagnostic pointing to the TypeVar definition if the TypeVar is Self (#22646) 2026-01-17 12:41:37 +00:00
justin
938c1c5e12 [ty] diagnostic on overridden __setattr__ and __delattr__ in frozen dataclasses (#21430)
## Summary
https://github.com/astral-sh/ty/issues/111

this pr adds an `invalid-dataclass-override` diagnostic when a custom
`__setattr__` or `__delattr__` is defined on a dataclass where
`frozen=True`
([docs](https://docs.python.org/3/library/dataclasses.html#frozen-instances))

### Runtime exception
```
Traceback (most recent call last):
  File "/Users/justinchapman/src/ty-playground/main.py", line 4, in <module>
    @dataclass(frozen=True)
     ~~~~~~~~~^^^^^^^^^^^^^
  File "/Users/justinchapman/.local/share/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/dataclasses.py", line 1295, in wrap
    return _process_class(cls, init, repr, eq, order, unsafe_hash,
                          frozen, match_args, kw_only, slots,
                          weakref_slot)
  File "/Users/justinchapman/.local/share/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/dataclasses.py", line 1157, in _process_class
    func_builder.add_fns_to_class(cls)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
  File "/Users/justinchapman/.local/share/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/dataclasses.py", line 516, in add_fns_to_class
    raise TypeError(error_msg)
TypeError: Cannot overwrite attribute __setattr__ in class A
```

### Diagnostic
```
error[invalid-dataclass-override]: Cannot overwrite attribute __setattr__ in class A
 --> /Users/justinchapman/src/ty-playground/main.py:6:5
  |
4 | @dataclass(frozen=True)
5 | class A:
6 |     def __setattr__(self, name: str, value: object) -> None: ...
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
info: __setattr__
info: rule `invalid-dataclass-override` is enabled by default

Found 1 diagnostic
```

## Test Plan
- new mdtests
- e2e
- the `attrs` mypy primer diff looks to be a [true
positive](https://github.com/python-attrs/attrs/blob/main/tests/test_setattr.py#L373)
- the other results have been unpredictable and have changed every time
i pushed new code, even if the diagnostic logic didn't change...

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2026-01-17 02:24:39 +00:00
Alex Waygood
717d024ea9 [ty] Generalize union-type subtyping fast path (#22495) 2026-01-16 22:09:06 +00:00
Dex Devlon
5c97b6ef40 [ty] Correct return type for synthesized NamedTuple.__new__ methods (#22625) 2026-01-16 18:56:56 +00:00
Alex Waygood
ed355b6173 [ty] Rename some narrowing-related machinery (#22618) 2026-01-16 17:10:33 +00:00
Alex Waygood
a2b383842a [ty] Allow ... as a default value for any parameter if the function is in an if TYPE_CHECKING block (#22624) 2026-01-16 16:32:38 +00:00
Micha Reiser
eb99f80a02 [ty] Extract ty_site_packages crate (#22622) 2026-01-16 15:02:47 +01:00
Alex Waygood
28bfcf82b8 [ty] Make ModuleType and object attributes available on namespace packages (#22606)
## Summary

Currently we don't think that namespace packages (e.g. `google` after
you've pip-installed `google-cloud-ndb`) have attributes such as
`__file__`, `__name__`, etc. This PR fixes that.

## Test Plan

Mdtests and snapshots.
2026-01-16 08:42:58 +00:00
Ibraheem Ahmed
78d1343583 [ty] Infer implicit type of cls in __new__ methods (#22584)
## Summary

Resolves https://github.com/astral-sh/ty/issues/2489.
2026-01-15 15:42:16 -05:00
Charlie Marsh
b4b8299d6c [ty] Make NamedTuple(...) and namedtuple(...) calls stricter (#22601)
## Summary

Closes https://github.com/astral-sh/ty/issues/2513.
2026-01-15 18:24:25 +00:00
Rob Hand
eca58ca1d3 [ty] Override __file__ to str when applicable on imported modules (#22333) 2026-01-15 17:08:50 +00:00
Bhuminjay Soni
b2d57ddaa5 [ty]: consolidate type[] types in a union when displaying them in diagnostics (#22592) 2026-01-15 15:20:58 +00:00
Charlie Marsh
de954b6fa4 [ty] Support starred unpacking in class bases (#22591)
## Summary

Closes https://github.com/astral-sh/ty/issues/2492.
2026-01-15 10:17:11 -05:00
Charlie Marsh
fd7cc1f9c9 [ty] Validate field names for typing.NamedTuple(...) (#22599)
## Summary

Closes https://github.com/astral-sh/ty/issues/2511.
2026-01-15 09:15:45 -05:00
github-actions[bot]
1f9b44f7ce [ty] Sync vendored typeshed stubs (#22590)
Co-authored-by: typeshedbot <>
Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
2026-01-15 12:37:30 +00:00
Carl Meyer
87110c2892 [ty] Fix PEP 695 type aliases not expanding in overload resolution (#22589)
Fixes https://github.com/astral-sh/ty/issues/2488

When a type alias is defined using PEP 695's `type` statement syntax
(e.g., `type Array = Eager | Lazy`), overload resolution was failing
because the type alias was not being expanded into its underlying union
type.

This fix updates both `expand_type` and `is_expandable_type` in
`arguments.rs` to handle `Type::TypeAlias` by recursively checking and
expanding the alias's value type.
2026-01-15 06:25:08 +00:00
Alex Waygood
5a18e93d65 [ty] Make special cases for subscript inference exhaustive (#22035)
## Summary

Fixes https://github.com/astral-sh/ty/issues/2015. We weren't recursing
into the value of a type alias when we should have been.

There are situations where we should also be recursing into the
bounds/constraints of a typevar. I initially tried to do that as well in
this PR, but that seems... trickier. For now I'm cutting scope; this PR
does, however, add several failing tests for those cases.

## Test Plan

added mdtests
2026-01-15 00:18:54 +00:00
Alex Waygood
b79e9bac14 [ty] Use let-chains more (#22580)
## Summary

just a little refactor.

Edit: okay, I removed a period at the end of a diagnostic message, which
I guess changes a _lot_ of diagnostic messages.
2026-01-14 19:56:07 +00:00
Charlie Marsh
b07a53ab68 [ty] Emit diagnostics for invalid dynamic namedtuple fields (#22575)
## Summary

Removes some TODOs from the dynamic namedtuple implementation.
2026-01-14 18:42:35 +00:00
Charlie Marsh
87eec9bb51 [ty] Show dynamic NamedTuple defaults in signature (#22574)
## Summary

Follow-up from https://github.com/astral-sh/ruff/pull/22327.
2026-01-14 18:28:23 +00:00
Charlie Marsh
eb96456e1e [ty] Synthesize an empty __slots__ for named tuples (#22573)
## Summary

Closes https://github.com/astral-sh/ty/issues/2490.
2026-01-14 18:22:27 +00:00
Charlie Marsh
3e0299488e [ty] Add support for functional namedtuple creation (#22327)
## Summary

This PR is intended to demonstrate how the pattern established in
https://github.com/astral-sh/ruff/pull/22291 generalizes to other class
"kinds".

Closes https://github.com/astral-sh/ty/issues/1049.

---------

Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
2026-01-14 17:41:04 +00:00
Alex Waygood
7f0ce3e88d [ty] Infer type[Unknown] for calls to type() when overload evaluation is ambiguous (#22569)
Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2026-01-14 14:23:07 +00:00
Charlie Marsh
ba0736385d [ty] Add a diagnostic for non-decorator uses of final (#22555)
## Summary

See:
https://github.com/astral-sh/ruff/pull/22499#discussion_r2687263390.
2026-01-14 09:14:59 -05:00
Charlie Marsh
e41f045ec5 [ty] Emit diagnostics for invalid base classes in type(...) (#22499)
## Summary

Tackles a few TODOs from https://github.com/astral-sh/ruff/pull/22291.
2026-01-14 08:56:04 -05:00
Charlie Marsh
b24afb643c [ty] Support 'dangling' type(...) constructors (#22537)
## Summary

This PR adds support for 'dangling' `type(...)` constructors, e.g.:

```python
class Foo(type("Bar", ...)):
   ...
```

As opposed to:

```python
Bar = type("Bar", ...)
```

The former doesn't have a `Definition` since it doesn't get bound to a
place, so we instead need to store the `NodeIndex`. Per @MichaReiser's
suggestion, we can use a Salsa tracked struct for this.
2026-01-14 08:48:53 -05:00
Charlie Marsh
b5814b91c1 [ty] Add diagnostics to validate TypeIs and TypeGuard definitions (#22300)
## Summary

Closes https://github.com/astral-sh/ty/issues/2267.
2026-01-13 20:24:05 -05:00