## 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.
## 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.