513 Commits

Author SHA1 Message Date
Charlie Marsh 35228e5a84 [ty] Respect commented-out lines in the conformance test suite (#24932)
## Summary

We were treating this line from the conformance tests as a false
negative:


https://github.com/python/typing/blob/5a701a037b5243df1f39622b642893d865f06205/conformance/tests/generics_syntax_infer_variance.py#L72
2026-04-29 12:56:26 -04:00
renovate[bot] cb11ec4ba4 Update dependency pyright to v1.1.409 (#24856)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-27 10:40:23 +02:00
Dylan 66f93cf7ed Bump 0.15.12 (#24815) 2026-04-24 12:36:40 -05:00
Amethyst Reese 53554b1cfe Bump 0.15.11 (#24678) 2026-04-16 11:17:46 -07:00
Charlie Marsh a1bd94d0f6 [ty] Check inherited NamedTuple field conflicts (#24542)
## Summary

Per the spec:

> A named tuple class can be subclassed, but any fields added by the
subclass are not considered part of the named tuple type. Type checkers
should enforce that these newly-added fields do not conflict with the
named tuple fields in the base class.

The spec then provides this example:

```python
class Point(NamedTuple):
    x: int
    y: int
    units: str = "meters"

class PointWithName(Point):
    name: str  # OK
    x: int  # Type error (invalid override of named tuple field)
```

We take a slightly more expansive view here, rejecting any attributes
(with or without an annotation, with or without a default) and
properties in a `NamedTuple` subclass. This seems to match Pyright and
Pyrefly, though Mypy doesn't flag these.

Shadowing an attribute in this way leads to odd behavior that is
probably never what you want, e.g.:

```python
from typing import NamedTuple

class A(NamedTuple):
    x: int

class B(A):
    x: int = 42

b = B(1)

print(b.x)  # 42
print(b[0])  # 1
print(repr(b))  # B(x=1)

b.x = 99

print(b.x)  # 99
print(b[0])  # 1
print(repr(b))  # B(x=1)
```
2026-04-14 11:30:54 -04:00
renovate[bot] 3127232161 Update dependency pytest to v9.0.3 (#24629)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-14 08:34:15 +02:00
Charlie Marsh 08b0218b3e [ty] Improve consistency of pedantic lints complaining about badly named types (#24575)
## Summary

We now use the same error code for all of these, with the same range,
and it's a warning by default:
```python
N = NamedTuple("O", [])
TD = TypedDict("TE", {})
T = TypeVar("U")
P = ParamSpec("Q")
NT = NewType("N", int)
```

It also implements more graceful recovery for `TypeVar`,
`TypeAliasType`, `ParamSpec`, and `NewType`.

Closes https://github.com/astral-sh/ty/issues/3255.
2026-04-12 13:42:16 -04:00
Brent Westbrook 252f76102a Bump 0.15.10 (#24519) 2026-04-09 09:48:41 -04:00
Carl Meyer 2f839db9e4 [ty] respect __new__ and metaclass __call__ return types (#24357)
Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
Co-authored-by: Denys Zhak <denyszhak@gmail.com>
2026-04-03 09:10:34 -07:00
Dylan 724ccc1ae8 Bump 0.15.9 (#24369) 2026-04-02 12:59:00 -05:00
Amethyst Reese c2a8815842 Release 0.15.8 (#24217)
- **changelog**
- **everything else**
2026-03-26 11:20:09 -07:00
Micha Reiser 84ff94b42e [ty] Support type:ignore[ty:code] suppressions (#24096) 2026-03-24 09:33:41 +01:00
Brent Westbrook 0ef39de46c Bump 0.15.7 (#24049) 2026-03-19 12:09:44 -04:00
David Peter 7f275f431b [ty] Pin mypy_primer in setup_primer_project.py (#24020)
## Summary

Pin mypy_primer (reference:
https://github.com/astral-sh/ruff/pull/24016#discussion_r2947047615)
2026-03-17 21:26:10 +01:00
David Peter dc59ffa9c6 [ty] Remove the mypy_primer CI workflow (#24016)
## Summary

Remove the mypy_primer CI workflow and several files/scripts associated
with it.

## Test Plan

Successful CI run on this PR
2026-03-17 15:49:55 +01:00
David Peter 65d5edc319 [ty] Include CPython projects in ecosystem-analyzer runs (#23995)
## Summary

There are three special projects in mypy_primer's list: they are all
part of the cpython repository, but in different subfolders. Previously,
`good.txt` only included the pattern "cpython" to include all of them
for mypy_primer runs. However, ecosystem-analyzer expects an exact
match. I don't really want to change that behavior in
ecosystem-analyzer, so instead, we now include the full project names,
and map those back to "cpython" for mypy_primer (which matches the regex
against the projects URL, not the name).

## Test Plan

- Made sure that mypy_primer still runs as expected, with the new
selector (regex-escaping leads to a slightly different project selector)
- Made sure that CPython projects are now included in ecosystem-analyzer
runs
2026-03-16 11:33:37 +01:00
Vlad Apostol f854f4fb7f Fix shell injection via shell=True in subprocess calls (#23894)
## Summary

Enable Ruff's own `S602` rule (`subprocess-popen-with-shell-equals-true`
from flake8-bandit) in `pyproject.toml` to enforce no-shell subprocess
calls going forward, and fix the two existing violations it catches.

**`pyproject.toml`** - adds `S602` to the lint `select` list so any
future `shell=True` usage in the scripts is caught automatically by the
linter.

**`scripts/setup_primer_project.py`** - `project.install_cmd` and
`project.deps` come from the mypy-primer project registry (an
externally-fetched third-party config). Both were joined into shell
strings and executed with `shell=True`, making them a supply-chain
injection vector. Fixed by tokenising with `shlex.split()` and dropping
`shell=True`.

**`scripts/ty_benchmark/src/benchmark/snapshot.py`** - `command.prepare`
was passed to `subprocess.run(..., shell=True)`. While no current caller
sets this field, it is a latent injection point. Fixed by tokenising
with `shlex.split()` and dropping `shell=True`; adds the missing `import
shlex`.

## Test Plan

Both scripts are developer-only utilities. The changes are semantically
equivalent for well-formed inputs - `shlex.split()` produces the same
argument list the shell would have constructed, while refusing to pass
metacharacters through to a shell process.

Verified no other `shell=True` uses remain in `scripts/` or `python/`
that would be newly flagged by S602.
2026-03-13 08:13:14 -06:00
Dylan e4c7f35777 Bump 0.15.6 (#23919) 2026-03-12 17:48:57 -05:00
Shunsuke Shibayama ce2cb82b0f Run end-of-file-fixer pre-commit hook on ty corpus test files (#23908) 2026-03-12 11:41:56 +00:00
Charlie Marsh e46e458eae Allow users to ban lazy imports (#23847)
## Summary

This PR renames TID254 to `lazy-import-mismatch` and expands it into a
single rule with two complementary settings: `require-lazy` and
`ban-lazy`. Both settings accept `"all"`, `list[str]`, or `{ include =
..., exclude = [...] }`, and we validate that the two selectors don’t
overlap.

This covers the two main use-cases users asked for:

- Require lazy imports by default, except for known side-effectful
modules. Example:

  ```toml
  require-lazy = { include = "all", exclude = ["sitecustomize"] }
  ```
This enforces lazy imports everywhere Ruff can rewrite them, while
leaving sitecustomize eager.

- Forbid lazy imports for modules that must stay eager, or even forbid
lazy imports by default with a small allowlist.

  ```toml
  # Require `sitecustomize` to stay eager.
  ban-lazy = ["sitecustomize"]

  # Ban lazy imports everywhere except `typing`.
  ban-lazy = { include = "all", exclude = ["typing"] }
  ```
2026-03-10 14:27:53 -04:00
Charlie Marsh a76a6bf8b0 Use starred unpacking for RUF017 in Python 3.15+ (#23789)
## Summary

Closes https://github.com/astral-sh/ruff/issues/22230.
2026-03-09 19:15:27 +00:00
Charlie Marsh 2e227cdd5b Add a rule to enforce lazy imports (#23777)
## Summary

`TID254` enforces the use of `lazy` imports. You can specify a set of
modules, similar to `banned-module-level-imports`, or `"all"`:

```toml
# Require every module-level import to be lazy.
banned-eager-imports = "all"

# Require lazy imports for specific modules.
banned-eager-imports = [
    "boto3",
    "botocore",
]
```
2026-03-09 17:57:37 +00:00
Alex Waygood 5cdd2fe435 More minor improvements to conformance.py (#23792) 2026-03-07 17:54:21 +00:00
Alex Waygood c6418d2fee conformance.py: stop escaping | characters (#23758) 2026-03-06 11:01:27 +00:00
Carl Meyer 7d8c6422b1 [ty] do not union Unknown into unannotated container types (#23718)
## Summary

Part of https://github.com/astral-sh/ty/issues/1240

Stop unioning `Unknown` into the types of un-annotated container
literals.

We discussed perhaps continuing to union `Unknown` if the inferred type
is a singleton type like `None`. I'd like to explore this as a separate
change so we can see the ecosystem impact more clearly.

## Test Plan

Adjusted many mdtest expectations.

There's one test case that regresses with this change, because we don't
fully support union type contexts (it can require a lot of repeat
inference in pathological cases). So `x10: list[int | str] | list[int |
None] = [1, 2, 3]` previously passed only because we inferred the RHS as
`list[Unknown | int]` -- now we infer it as `list[int]` and the
assignment fails due to invariance. I've kept this test as a TODO since
it's not trivial to fix. Mypy errors in the same way we now do,
suggesting it's not necessarily a huge priority either.

## Ecosystem

This change is expected to cause new diagnostics and some false
positives, since we are replacing very-forgiving gradual types with
non-gradual inference heuristics.

Many of these issues could be solved or significantly mitigated by
https://github.com/astral-sh/ty/issues/1473, depending how far we are
able to go with that, and particularly whether we can afford to apply it
also to container literals which are not empty at construction. The
downside of broad application of this approach is that in some cases it
could cause us to widen container types when the user actually just made
a mistake and added the wrong thing to a container, and would prefer an
error at that location.

Some categories of new error that show up in the ecosystem report:

### Implicit TypedDicts

These are cases where the dictionary is heterogeneous and would ideally
be typed as a `TypedDict` but isn't, for example:

```py
def make_person(photo: bytes | None):
    person = {"name": "Pat", age: 29}
    if photo is not None:
        person["photo"] = photo
```

We (and pyrefly, and pyright in strict mode) error on the last line here
because we already inferred `dict[str, str | int]`, so we can't add a
`bytes` value.

Mypy prefers common-base joins over union joins, so it infers `dict[str,
object]`, which avoids the error adding a `bytes` value. This means the
value type is less precise, which theoretically means potentially more
errors using values from the dict later. But in practice with this
heterogeneous pattern, either `object` or the union will cause similar
problems when using values from the dict -- in either case you'd
probably have to cast or narrow.

Pyright (in non-strict mode) has a special case where it falls back to
`Unknown` when it sees heterogenous value types, so it infers this as
`dict[str, Unknown]`.

I think we could consider either the mypy or pyright approaches here,
but we don't need to do it in this PR; we can file an issue and consider
it as a follow-up.

Another symptom of this same root cause is repetitive diagnostics
arising from a large union inferred as value type; the same fixes would
address this.

### Negative intersections, particularly with e.g. `~AlwaysFalsy` or
`~None`.

Example:

```py
class A: ...

def _(a: A | None) -> dict[str, A]:
    if a:
        d = {"a": a}
        return d
    return {}
```

We error on `return d` because "expected `dict[str, A]`, found
`dict[str, A & ~AlwaysFalsy]`". This is an issue specific to
intersection types, so no other type checker has this problem.

I think when we "promote literals" (we may need to give this operation a
broader name -- it's really "type promotion to give a better inferred
type when invariance means too-precise is bad") we should also eliminate
all negative types from intersections. I would prefer to do this as a
separate PR for easier review and better visibility of ecosystem impact,
but I think it's high priority to land soon after this PR (ideally
before a release).

### Overly-precise inference for singleton `None`

This did show up, to the tune of ~100 new diagnostics
([example](https://github.com/pytorch/ignite/blob/b73a4c20e991b3e14949f2a69651ed2a7219f2fd/tests/ignite/engine/test_engine.py#L158)),
so I think it is worth addressing as a follow-up.
2026-03-05 15:40:48 -08:00
Alex Waygood 74b0553972 conformance.py: Collapse the summary paragraph when nothing changed (#23745) 2026-03-05 20:02:04 +00:00
Amethyst Reese 5e4a3d9c3b Bump 0.15.5 (#23743)
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2026-03-05 19:48:21 +00:00
Will Duke 69c23cc5a3 [ty] Render all changed diagnostics in conformance.py (#23613)
Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
2026-03-05 19:20:22 +00:00
Alex Waygood cd8e8d535f [ty] Add invalid-enum-member-annotation lint rule (#23648)
## Summary

This PR fixes the last remaining conformance failure on
`enums_members.py` in the conformance suite.

Implements a new lint rule `invalid-enum-member-annotation` that detects
type annotations on enum members. According to the typing spec, enum
members should not have explicit type annotations, as the actual runtime
type is the enum class itself, not the annotated type.

The rule:
- Flags annotated enum members (e.g., `DOG: int = 2` in an `Enum` class)
- Allows bare `Final` annotations (which don't specify a type)
- Excludes dunder names, private names, and special sunder names like
`_value_` and `_ignore_`
- Excludes pure declarations without values (non-members)

## Test Plan

mdtests
2026-03-02 17:31:36 +00:00
Brent Westbrook f14edd8661 Bump 0.15.4 (#23595)
Just to be sure, I ran the example from #23587 again on this branch:

```console
~/astral/ruff on  brent/0.15.4 [$] is 📦 v0.15.4 via 🐍 v3.14.2 via 🦀 v1.93.0
❯ echo 'x = id' | uvx ruff@latest --isolated check - --preview --select ANN003,PLR1712

error: Ruff crashed. If you could open an issue at:

    https://github.com/astral-sh/ruff/issues/new?title=%5BPanic%5D

...quoting the executed command, along with the relevant file contents and `pyproject.toml` settings, we'd be very appreciative!


thread 'main' (1681253) panicked at crates/ruff_python_semantic/src/definition.rs:285:26:
index out of bounds: the len is 0 but the index is 0
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

~/astral/ruff on  brent/0.15.4 [$] is 📦 v0.15.4 via 🐍 v3.14.2 via 🦀 v1.93.0
❯ echo 'x = id' | just run --isolated check - --preview --select ANN003,PLR1712
cargo run -p ruff -- --isolated check - --preview --select ANN003,PLR1712
   Compiling ruff_python_semantic v0.0.0 (/home/brent/astral/ruff/crates/ruff_python_semantic)
   Compiling ruff v0.15.4 (/home/brent/astral/ruff/crates/ruff)
   Compiling ruff_linter v0.15.4 (/home/brent/astral/ruff/crates/ruff_linter)
   Compiling ruff_graph v0.1.0 (/home/brent/astral/ruff/crates/ruff_graph)
   Compiling ruff_workspace v0.0.0 (/home/brent/astral/ruff/crates/ruff_workspace)
   Compiling ruff_markdown v0.0.0 (/home/brent/astral/ruff/crates/ruff_markdown)
   Compiling ruff_server v0.2.2 (/home/brent/astral/ruff/crates/ruff_server)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 23.14s
     Running `target/debug/ruff --isolated check - --preview --select ANN003,PLR1712`
warning: Detected debug build without --no-cache.
All checks passed!
```
2026-02-26 14:46:41 -05:00
Brent Westbrook e5f2f36a3f Bump 0.15.3 (#23585) 2026-02-26 10:22:43 -05:00
David Peter 9719e17c25 [ty] Diagnostic when combining Final and ClassVar (#23365)
## Summary

This PR implements the following paragraph in the typing spec:

> Type checkers should infer a final attribute that is initialized in a
class body as being a class variable, except in the case of
[Dataclasses](https://typing.python.org/en/latest/spec/dataclasses.html),
where `x: Final[int] = 3` creates a dataclass field and instance-level
final attribute `x` with default value `3`; `x: ClassVar[Final[int]] =
3` is necessary to create a final class variable with value `3`. In
non-dataclasses, combining `ClassVar` and `Final` is redundant, and type
checkers may choose to warn or error on the redundancy.
>
>
https://typing.python.org/en/latest/spec/qualifiers.html#semantics-and-examples

## Test Plan

New Markdown tests
2026-02-20 19:09:01 +01:00
Dylan 7cc15f024b Bump 0.15.2 (#23430) 2026-02-19 15:04:36 -06:00
Brent Westbrook 222574af90 Expand the default rule set (#23385)
## Summary

This PR adds the new default rule set in preview. This ended up being
pretty non-invasive because the `DEFAULT_SELECTORS` are only used in one
place where `preview` isn't set to the default value of `false`.

I've currently listed each rule with a separate `RuleSelector`, which I
generated with the script below. I thought about trying to be more
clever by finding the smallest set of prefix selectors that yield the
same rule set, but I figured this would be the easiest way to add and
remove rules in the future anyway.

<details><summary>Script</summary>
<p>

```py
import json
import subprocess
import tomllib
from pathlib import Path
from string import ascii_uppercase

RULES = {
    rule["code"]: rule["linter"]
    for rule in json.loads(
        subprocess.run(
            ["ruff", "rule", "--all", "--output-format=json"],
            check=True,
            text=True,
            capture_output=True,
        ).stdout
    )
}

for code, linter in RULES.items():
    if linter == "Ruff-specific rules":
        RULES[code] = "Ruff"


def kebab_to_pascal(s: str) -> str:
    return "".join(part.title() for part in s.split("-"))


rules = tomllib.loads(Path("proposal.toml").read_text())["lint"]["select"]

for rule in rules:
    linter = kebab_to_pascal(RULES[rule])
    suffix = rule.lstrip(ascii_uppercase)

    prefix = "_"
    match linter:
        case "Flake8Comprehensions":
            suffix = suffix.removeprefix("4")
        case "Pycodestyle":
            prefix = ""
            suffix = rule
        case "Flake8Gettext":
            linter = "Flake8GetText"
        case "Pep8Naming":
            linter = "PEP8Naming"
        case "Pylint":
            prefix = ""
            suffix = rule.removeprefix("PL")
        case "Flake8Debugger":
            suffix = suffix.removeprefix("10")

    print(
        " " * 4,
        f"RuleSelector::rule(RuleCodePrefix::{linter}("
        f"codes::{linter}::{prefix}{suffix})),"
        f" // {rule}",
        sep="",
    )
```

</p>
</details> 

## Test Plan

A new CLI test showing the preview default rules. I filtered down the
snapshot to just the `linter.rules.enabled` section, which isn't
strictly necessary but was a lot shorter. I also tested manually in VS
Code to make sure I didn't miss wiring up the preview defaults in the
server:

<img width="681" height="340" alt="image"
src="https://github.com/user-attachments/assets/9f7a0cd4-968e-40d6-abf0-dfbfa496531d"
/>


I also tested in the playground.
2026-02-19 14:45:18 -05:00
renovate[bot] b243865f68 Update prek dependencies (#23320) 2026-02-16 01:48:12 +00:00
Alex Waygood 8b7db2d35a [ty] Pass --error=deprecated when running conformance.py (#23304)
## Summary

This change bumps the recall score reported by the script from 74.33% to
74.82%
2026-02-15 23:51:43 +00:00
Amethyst Reese a2f11d239f Prepare for 0.15.1 (#23253)
- **Changelog**
- **Everything else**

---------

Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2026-02-12 14:17:21 -08:00
Douglas Creager dc65d12668 [ty] Infer typevar specializations for implicit generic protocols (#21902)
We now infer specializations that involve generic protocols. This
includes recursing into the methods of the protocol, matching up the
signatures of the class's methods with the signatures of the protocol,
and adding bindings for any typevars that appear in the protocol
signatures.

This required several performance updates, which were pulled out and
merged as separate PRs. There is still a performance and memory hit, but
I think a reasonable one, given the new functionality that this opens
up.

There are still some ecosystem false positives that relate to how this
interacts with overload resolution, but I plan to tackle that in
follow-on PRs.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2026-02-11 16:09:34 -05:00
Alex Waygood 40fd2f176f memory_report.py: suppress the detailed table if all changes are <0.01MB big (#23212) 2026-02-11 20:10:36 +00:00
Ibraheem Ahmed 1cf481a34d [ty] Improve memory report formatting (#23216)
A couple small improvements to the memory report:
- Consistent sorting between the summary and expanded view.
- Human readable memory size.
- Strip the inner whitespace from type names.
2026-02-10 17:53:36 -05:00
Alex Waygood e6dc572bb0 Make setup_primer_project.py executable and improve the shebang (#23205) 2026-02-10 19:27:48 +00:00
Carl Meyer 20a17411b2 [ty] add scripts/setup_primer_project.py (#23195)
## Summary

`uv run scripts/setup_primer_project.py <projname> <directory>` will
clone the mypy-primer project `<projname>` to `<directory>` and then
install it and its dependencies (in the way defined by mypy-primer) into
`.venv` in that directory, setting it up for easy reproduction of the
primer results.

Also added instructions to `CLAUDE.md` so Claude will use this script
when reproducing ecosystem results. This can short-circuit a lot of "it
doesn't reproduce! oh I didn't install the dependencies" churn.

## Test Plan

`uv run scripts/setup_primer_project.py artigraph /tmp/artigraph` set
things up such that I was able to just run two versions of ty in
`/tmp/artigraph` and quickly repro an ecosystem diff from CI.
2026-02-09 20:10:16 -08:00
Ibraheem Ahmed bbaa769822 [ty] More detailed memory usage reports (#23128)
Based on the feedback from https://github.com/astral-sh/ruff/pull/22899,
upload a memory usage report comment similar to the typing conformance
suit results.
2026-02-10 02:28:19 +00:00
Alex Waygood efc876f6b0 Bump mypy_primer pin (#23145)
Pulls in
https://github.com/hauntsaninja/mypy_primer/commit/850d65d9da947ef9e02498b6f07598e7c8401641
2026-02-08 19:58:37 +00:00
David Peter a1271fb00e [ty] Bump mypy_primer and ecosystem-analyzer (#23117)
https://github.com/hauntsaninja/mypy_primer/compare/ea7c45364a129b9a556b08a6285f8df0e5aedf0a...d4e091e8937adea5b2722b49e17d3b252f2c8950
2026-02-06 11:26:39 +01:00
Brent Westbrook ce5f7b6127 Bump 0.15.0 (#23055) 2026-02-03 12:20:59 -05:00
Will Duke 0d1322d0b1 [ty] fix(conformance): Add tests directory as extra search path (#23048)
## Summary

The conformance test suite has some underscore-prefixed helper files
from which some of the test files import items. This change adds the
tests/ directory as a search path so that these imports no longer raise
spurious unresolved-import diagnostics.

## Test Plan

Running `scripts/conformance.py` after this change removes any
unresolved-import diagnostics and improves the number of true positives.


# Command

```
uv run --no-project --python 3.12 scripts/conformance.py --tests-path ../typing/conformance/ --old-ty uvx ty@0.0.6 --output scripts/test.md
```

## Before

### Summary

| Metric | Old | New | Diff | Outcome |
|--------|-----|-----|------|---------|
| True Positives  | 686 | 747 | +61 |  () |
| False Positives | 244 | 201 | -43 |  () |
| False Negatives | 387 | 332 | -55 |  () |
| Total Diagnostics | 930 | 948 | +18 |  |
| Precision | 73.76% | 78.80% | +5.03% |  () |
| Recall | 63.93% | 69.23% | +5.30% |  () |

## After

### Summary

| Metric | Old | New | Diff | Outcome |
|--------|-----|-----|------|---------|
| True Positives  | 691 | 752 | +61 |  () |
| False Positives | 234 | 191 | -43 |  () |
| False Negatives | 383 | 328 | -55 |  () |
| Total Diagnostics | 925 | 943 | +18 |  |
| Precision | 74.70% | 79.75% | +5.04% |  () |
| Recall | 64.34% | 69.63% | +5.29% |  () |
2026-02-03 09:20:37 +01:00
Alex Waygood 6f1e6cb37f [ty] Emit a diagnostic on incorrect applications of the legacy convention for specifying positional-only parameters (#22943) 2026-01-31 10:14:00 +00:00
Alex Waygood fcbf6f1cc9 [ty] Add a new assert-type-unspellable-subtype diagnostic (#22815)
Fixes https://github.com/astral-sh/ty/issues/1762. If a type assertion
fails, but the actual type is an unspellable subtype of the asserted
type, we now emit `assert-type-unspellable-subtype` rather than
`type-assertion-failure`. We also ignore this error in
`scripts/conformance.py`. This results in 17 fewer false positives on
the conformance suite, and it's also something that our users have asked
for.
2026-01-23 21:16:16 +00:00
Will Duke 58bffa465c [ty] Handle tagged errors in conformance (#22746)
Co-authored-by: Micha Reiser <micha@reiser.io>
2026-01-23 14:44:28 +00:00