## 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>
## 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.
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.
## 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
## 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.
## 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.
## Summary
Since we've already filtered the union in these locations, it seems like
needless overhead to then intersect the previous union with the filtered
union. We know what that intersection will simplify to: it will simplify
to the filtered union. So rather than using a regular intersection-based
constraint, we can use a "typeguard constraint", which will just
directly replace the previous type with the new type instead of creating
an intersection.
## Test Plan
- Existing tests all pass
- The primer report should be clean
This fixes issue #2470 where recursive type aliases like `type
RecursiveT = int | tuple[RecursiveT, ...]` caused a stack overflow when
used in return type checking with constructors like `list()`.
The fix moves all type mapping processing for `UniqueSpecialization`
(and other non-EagerExpansion mappings) inside the `visitor.visit()`
closure. This ensures that if we encounter the same TypeAlias
recursively during type mapping, the cycle detector will properly detect
it and return the fallback value instead of recursing infinitely.
The key insight is that the previous code called
`apply_function_specialization` followed by another
`apply_type_mapping_impl` AFTER the visitor closure returned. At that
point, the TypeAlias was no longer in the visitor's `seen` set, so
recursive references would not be detected as cycles.
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:
- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
requests.)
- Does this pull request include references to any relevant issues?
-->
## Summary
The test I've added illustrates the fix. Copying it here too:
```python
from contextlib import contextmanager
from typing import Iterator
from typing_extensions import Self
class Base:
@classmethod
@contextmanager
def create(cls) -> Iterator[Self]:
yield cls()
class Child(Base): ...
with Base.create() as base:
reveal_type(base) # revealed: Base (after the fix, None before)
with Child.create() as child:
reveal_type(child) # revealed: Child (after the fix, None before)
```
Full disclosure: I've used LLMs for this PR, but the result is
thoroughly reviewed by me before submitting. I'm excited about my first
Rust contribution to Astral tools and will address feedback quickly.
Related to https://github.com/astral-sh/ty/issues/2030, I am working on
a fix for the TypeVar case also reported in that issue (by me)
<!-- What's the purpose of the change? What does it do, and why? -->
## Test Plan
<!-- How was it tested? -->
Updated mdtests
---------
Co-authored-by: Douglas Creager <dcreager@dcreager.net>