Commit Graph

6616 Commits

Author SHA1 Message Date
Douglas Creager 9db63fc58c
[red-knot] Handle generic constructors of generic classes (#17552)
We now handle generic constructor methods on generic classes correctly:

```py
class C[T]:
    def __init__[S](self, t: T, s: S): ...

x = C(1, "str")
```

Here, constructing `C` requires us to infer a specialization for the
generic contexts of `C` and `__init__` at the same time.

At first I thought I would need to track the full stack of nested
generic contexts here (since the `[S]` context is nested within the
`[T]` context). But I think this is the only way that we might need to
specialize more than one generic context at once — in all other cases, a
containing generic context must be specialized before we get to a nested
one, and so we can just special-case this.

While we're here, we also construct the generic context for a generic
function lazily, when its signature is accessed, instead of eagerly when
inferring the function body.
2025-04-23 15:06:18 -04:00
David Peter 61e73481fe
[red-knot] Assignability of class instances to Callable (#17590)
## Summary

Model assignability of class instances with a `__call__` method to
`Callable` types. This should solve some false positives related to
`functools.partial` (yes, 1098 fewer diagnostics!).

Reference:
https://github.com/astral-sh/ruff/issues/17343#issuecomment-2824618483

## Test Plan

New Markdown tests.
2025-04-23 20:34:13 +02:00
David Peter e170fe493d
[red-knot] Trust all symbols in stub files (#17588)
## Summary

*Generally* trust undeclared symbols in stubs, not just at the module
level.

Follow-up on the discussion
[here](https://github.com/astral-sh/ruff/pull/17577#discussion_r2055945909).

## Test Plan

New Markdown test.
2025-04-23 20:07:29 +02:00
David Peter e91e2f49db
[red-knot] Trust module-level undeclared symbols in stubs (#17577)
## Summary

Many symbols in typeshed are defined without being declared. For
example:
```pyi
# builtins:
IOError = OSError

# types
LambdaType = FunctionType
NotImplementedType = _NotImplementedType

# typing
Text = str

# random
uniform = _inst.uniform

# optparse
make_option = Option

# all over the place:
_T = TypeVar("_T")
```

Here, we introduce a change that skips widening the public type of these
symbols (by unioning with `Unknown`).

fixes #17032

## Ecosystem analysis

This is difficult to analyze in detail, but I went over most changes and
it looks very favorable to me overall. The diff on the overall numbers
is:
```
errors: 1287 -> 859 (reduction by 428)
warnings: 45 -> 59 (increase by 14)
```

### Removed false positives

`invalid-base` examples:

```diff
- error[lint:invalid-base] /tmp/mypy_primer/projects/pip/src/pip/_vendor/rich/console.py:548:27: Invalid class base with type `Unknown | Literal[_local]` (all bases must be a class, `Any`, `Unknown` or `Todo`)
- error[lint:invalid-base] /tmp/mypy_primer/projects/tornado/tornado/iostream.py:84:25: Invalid class base with type `Unknown | Literal[OSError]` (all bases must be a class, `Any`, `Unknown` or `Todo`)
- error[lint:invalid-base] /tmp/mypy_primer/projects/mitmproxy/test/conftest.py:35:40: Invalid class base with type `Unknown | Literal[_UnixDefaultEventLoopPolicy]` (all bases must be a class, `Any`, `Unknown` or `Todo`)
```

`invalid-exception-caught` examples:

```diff
- error[lint:invalid-exception-caught] /tmp/mypy_primer/projects/cloud-init/cloudinit/cmd/status.py:334:16: Cannot catch object of type `Literal[ProcessExecutionError]` in an exception handler (must be a `BaseException` subclass or a tuple of `BaseException` subclasses)
- error[lint:invalid-exception-caught] /tmp/mypy_primer/projects/jinja/src/jinja2/loaders.py:537:16: Cannot catch object of type `Literal[TemplateNotFound]` in an exception handler (must be a `BaseException` subclass or a tuple of `BaseException` subclasses)
```

`unresolved-reference` examples


7a0265d36e/cloudinit/handlers/jinja_template.py (L120-L123)
(we now understand the `isinstance` narrowing)

```diff
- error[lint:unresolved-attribute] /tmp/mypy_primer/projects/cloud-init/cloudinit/handlers/jinja_template.py:123:16: Type `Exception` has no attribute `errno`
```

`unknown-argument` examples


https://github.com/hauntsaninja/boostedblob/blob/master/boostedblob/request.py#L53

```diff
- error[lint:unknown-argument] /tmp/mypy_primer/projects/boostedblob/boostedblob/request.py:53:17: Argument `connect` does not match any known parameter of bound method `__init__`
```

`unknown-argument`

There are a lot of `__init__`-related changes because we now understand
[`@attr.s`](3d42a6978a/src/attr/__init__.pyi (L387))
as a `@dataclass_transform` annotated symbol. For example:

```diff
- error[lint:unknown-argument] /tmp/mypy_primer/projects/attrs/tests/test_hooks.py:72:18: Argument `x` does not match any known parameter of bound method `__init__`
```

### New false positives

This can happen if a symbol that previously was inferred as `X |
Unknown` was assigned-to, but we don't yet understand the assignability
to `X`:


https://github.com/strawberry-graphql/strawberry/blob/main/strawberry/exceptions/handler.py#L90

```diff
+ error[lint:invalid-assignment] /tmp/mypy_primer/projects/strawberry/strawberry/exceptions/handler.py:90:9: Object of type `def strawberry_threading_exception_handler(args: tuple[type[BaseException], BaseException | None, TracebackType | None, Thread | None]) -> None` is not assignable to attribute `excepthook` of type `(_ExceptHookArgs, /) -> Any`
```

### New true positives


6bbb5519fe/tests/tracer/test_span.py (L714)

```diff
+ error[lint:invalid-argument-type] /tmp/mypy_primer/projects/dd-trace-py/tests/tracer/test_span.py:714:33: Argument to this function is incorrect: Expected `str`, found `Literal[b"\xf0\x9f\xa4\x94"]`
```

### Changed diagnostics

A lot of changed diagnostics because we now show `@Todo(Support for
`typing.TypeVar` instances in type expressions)` instead of `Unknown`
for all kinds of symbols that used a `_T = TypeVar("_T")` as a type. One
prominent example is the `list.__getitem__` method:

`builtins.pyi`:
```pyi
_T = TypeVar("_T")  # previously `TypeVar | Unknown`, now just `TypeVar`

# …

class list(MutableSequence[_T]):
    # …
    @overload
    def __getitem__(self, i: SupportsIndex, /) -> _T: ...
    # …
```

which causes this change in diagnostics:
```py
xs = [1, 2]
reveal_type(xs[0])  # previously `Unknown`, now `@Todo(Support for `typing.TypeVar` instances in type expressions)`
```

## Test Plan

Updated Markdown tests
2025-04-23 19:31:14 +02:00
Wei Lee b537552927
[`airflow`] Apply auto fixes to cases where the names have changed in Airflow 3 (`AIR301`) (#17355)
## Summary

Apply auto fixes to cases where the names have changed in Airflow 3

## Test Plan

Add `AIR301_names_fix.py` and `AIR301_provider_names_fix.py` test fixtures
2025-04-23 12:43:41 -04:00
Navdeep K 5a719f2d60
[`pycodestyle`] Auto-fix redundant boolean comparison (`E712`) (#17090)
This pull request fixes https://github.com/astral-sh/ruff/issues/17014

changes this
```python
from __future__ import annotations

flag1 = True
flag2 = True

if flag1 == True or flag2 == True:
    pass

if flag1 == False and flag2 == False:
    pass

flag3 = True
if flag1 == flag3 and (flag2 == False or flag3 == True):  # Should become: if flag1==flag3 and (not flag2 or flag3)
    pass

if flag1 == True and (flag2 == False or not flag3 == True):  # Should become: if flag1 and (not flag2 or not flag3)
    pass

if flag1 != True and (flag2 != False or not flag3 == True):  # Should become: if not flag1 and (flag2 or not flag3)
    pass


flag = True
while flag == True:  # Should become: while flag
    flag = False

flag = True
x = 5
if flag == True and x > 0:  # Should become: if flag and x > 0
    print("ok")

flag = True
result = "yes" if flag == True else "no"  # Should become: result = "yes" if flag else "no"

x = flag == True < 5

x = (flag == True) == False < 5
```

to this 
```python
from __future__ import annotations

flag1 = True
flag2 = True

if flag1 or flag2:
    pass

if not flag1 and not flag2:
    pass

flag3 = True
if flag1 == flag3 and (not flag2 or flag3):  # Should become: if flag1 == flag3 and (not flag2 or flag3)
    pass

if flag1 and (not flag2 or not flag3):  # Should become: if flag1 and (not flag2 or not flag3)
    pass

if not flag1 and (flag2 or not flag3):  # Should become: if not flag1 and (flag2 or not flag3)
    pass


flag = True
while flag:  # Should become: while flag
    flag = False

flag = True
x = 5
if flag and x > 0:  # Should become: if flag and x > 0
    print("ok")

flag = True
result = "yes" if flag else "no"  # Should become: result = "yes" if flag else "no"

x = flag is True < 5

x = (flag) is False < 5
```

---------

Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2025-04-23 11:49:20 -04:00
Brent Westbrook e7f38fe74b
[red-knot] Detect semantic syntax errors (#17463)
Summary
--

This PR extends semantic syntax error detection to red-knot. The main
changes here are:

1. Adding `SemanticSyntaxChecker` and `Vec<SemanticSyntaxError>` fields
to the `SemanticIndexBuilder`
2. Calling `SemanticSyntaxChecker::visit_stmt` and `visit_expr` in the
`SemanticIndexBuilder`'s `visit_stmt` and `visit_expr` methods
3. Implementing `SemanticSyntaxContext` for `SemanticIndexBuilder`
4. Adding new mdtests to test the context implementation and show
diagnostics

(3) is definitely the trickiest and required (I think) a minor addition
to the `SemanticIndexBuilder`. I tried to look around for existing code
performing the necessary checks, but I definitely could have missed
something or misused the existing code even when I found it.

There's still one TODO around `global` statement handling. I don't think
there's an existing way to look this up, but I'm happy to work on that
here or in a separate PR. This currently only affects detection of one
error (`LoadBeforeGlobalDeclaration` or
[PLE0118](https://docs.astral.sh/ruff/rules/load-before-global-declaration/)
in ruff), so it's not too big of a problem even if we leave the TODO.

Test Plan
--

New mdtests, as well as new errors for existing mdtests

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-04-23 09:52:58 -04:00
Micha Reiser 8abf93f5fb
[red-knot] Early return from `project.is_file_open` for vendored files (#17580) 2025-04-23 15:32:41 +02:00
Micha Reiser 5407249467
[red-knot] Make `BoundMethodType` a salsa interned (#17581) 2025-04-23 15:11:20 +02:00
Alex Waygood 0a1f9d090e
[red-knot] Emit a diagnostic if a non-protocol is passed to `get_protocol_members` (#17551) 2025-04-23 10:13:20 +00:00
Alex Waygood f9c7908bb7
[red-knot] Add more tests for protocol members (#17550) 2025-04-23 11:03:52 +01:00
David Peter 99fa850e53
[red-knot] Assignability for subclasses of `Any` and `Unknown` (#17557)
## Summary

Allow (instances of) subclasses of `Any` and `Unknown` to be assignable
to (instances of) other classes, unless they are final. This allows us
to get rid of ~1000 false positives, mostly when mock-objects like
`unittest.mock.MagicMock` are assigned to various targets.

## Test Plan

Adapted and new Markdown tests.
2025-04-23 11:37:30 +02:00
David Peter a241321735
[red-knot] mypy_primer: add strawberry, print compilation errors to stderr (#17578)
## Summary

mypy_primer changes included here:
ebaa9fd27b..4c22d192a4

- Add strawberry as a `good.txt` project (was previously included in our
fork)
- Print Red Knot compilation errors to stderr (thanks @MichaReiser)
2025-04-23 10:57:11 +02:00
David Peter b1b8ca3bcd
[red-knot] GenericAlias instances as a base class (#17575)
## Summary

We currently emit a diagnostic for code like the following:
```py
from typing import Any

# error: Invalid class base with type `GenericAlias` (all bases must be a class, `Any`, `Unknown` or `Todo`)
class C(tuple[Any, ...]): ...
```

The changeset here silences this diagnostic by recognizing instances of
`GenericAlias` in `ClassBase::try_from_type`, and inferring a `@Todo`
type for them. This is a change in preparation for #17557, because `C`
previously had `Unknown` in its MRO …
```py
reveal_type(C.__mro__)  # tuple[Literal[C], Unknown, Literal[object]]
```
… which would cause us to think that `C` is assignable to everything.

The changeset also removes some false positive `invalid-base`
diagnostics across the ecosystem.

## Test Plan

Updated Markdown tests.
2025-04-23 10:39:10 +02:00
Shaygan Hooshyari 3fae176345
Remove redundant `type_to_visitor_function` entries (#17564) 2025-04-23 09:27:00 +02:00
David Salvisberg f36262d970
Fixes how the checker visits `typing.cast`/`typing.NewType` arguments (#17538) 2025-04-23 09:26:00 +02:00
Matthew Mckee e45f23b0ec
[red-knot] Class literal `__new__` function callable subtyping (#17533)
## Summary

From
https://typing.python.org/en/latest/spec/constructors.html#converting-a-constructor-to-callable

this covers step 2 and partially step 3 (always respecting the
`__new__`)

## Test Plan

Update is_subtype_of.md

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2025-04-22 22:40:33 -07:00
Matthew Mckee aa46047649
[red-knot] Surround intersections with `()` in potentially ambiguous contexts (#17568)
## Summary

Add parentheses to multi-element intersections, when displayed in a
context that's otherwise potentially ambiguous.

## Test Plan

Update mdtest files

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2025-04-23 04:18:20 +00:00
Brent Westbrook f9da115fdc
[minor] Delete outdated TODO comment (#17565)
Summary
--

Delete a TODO I left that was handled in the last minor release
(#16125).

Test Plan
--

N/a
2025-04-22 20:23:08 +00:00
Carl Meyer 3872d57463
[red-knot] add regression test for fixed cycle panic (#17535)
Add a regression test for the cycle documented in
https://github.com/astral-sh/ruff/issues/14767, which no longer panics
(or even causes a cycle at all.)

Fixes https://github.com/astral-sh/ruff/issues/14767
2025-04-22 09:20:53 -07:00
Carl Meyer 27ada26ddb
[red-knot] fix unions of literals, again (#17534)
## Summary

#17451 was incomplete. `AlwaysFalsy` and `AlwaysTruthy` are not the only
two types that are super-types of some literals (of a given kind) and
not others. That set also includes intersections containing
`AlwaysTruthy` or `AlwaysFalsy`, and intersections containing literal
types of the same kind. Cover these cases as well.

Fixes #17478.

## Test Plan

Added mdtests.

`QUICKCHECK_TESTS=1000000 cargo test -p red_knot_python_semantic --
--ignored types::property_tests::stable` failed on both
`all_fully_static_type_pairs_are_subtypes_of_their_union` and
`all_type_pairs_are_assignable_to_their_union` prior to this PR, passes
after it.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-04-22 16:12:52 +00:00
Andrew Gallant 810478f68b red_knot_python_semantic: remove last vestige of old diagnostics! 2025-04-22 12:08:03 -04:00
Andrew Gallant 17f799424a red_knot_python_semantic: migrate `types` to new diagnostics 2025-04-22 12:08:03 -04:00
Andrew Gallant c12640fea8 red_knot_python_semantic: migrate `types/diagnostic` to new diagnostics 2025-04-22 12:08:03 -04:00
Andrew Gallant 3796b13ea2 red_knot_python_semantic: migrate `types/call/bind` to new diagnostics 2025-04-22 12:08:03 -04:00
Andrew Gallant ad5a659f29 red_knot_python_semantic: migrate `types/string_annotation` to new diagnostics 2025-04-22 12:08:03 -04:00
Andrew Gallant 27a377f077 red_knot_python_semantic: migrate `types/infer` to new diagnostic model
I gave up trying to do this one lint at a time and just (mostly)
mechanically translated this entire file in one go.

Generally the messages stay the same (with most moving from an
annotation message to the diagnostic's main message). I added a couple
of `info` sub-diagnostics where it seemed to be the obvious intent.
2025-04-22 12:08:03 -04:00
Andrew Gallant b8b624d890 red_knot_python_semantic: migrate INVALID_ASSIGNMENT for inference
This finishes the migration for the `INVALID_ASSIGNMENT` lint.

Notice how I'm steadily losing steam in terms of actually improving the
diagnostics. This change is more mechanical, because taking the time to
revamp every diagnostic is a ton of effort. Probably future migrations
will be similar unless there are easy pickings.
2025-04-22 12:08:03 -04:00
Andrew Gallant 6dc2d29966 red_knot_python_semantic: migrate INVALID_ASSIGNMENT for shadowing
We mostly keep things the same here, but the message has been moved from
the annotation to the diagnostic's top-line message. I think this is
perhaps a little worse, but some bigger improvements could be made here.
Indeed, we could perhaps even add a "fix" here.
2025-04-22 12:08:03 -04:00
Andrew Gallant 890ba725d9 red_knot_python_semantic: migrate INVALID_ASSIGNMENT for unpacking
This moves all INVALID_ASSIGNMENT lints related to unpacking over to the new
diagnostic model.

While we're here, we improve the diagnostic a bit by adding a secondary
annotation covering where the value is. We also split apart the original
singular message into one message for the diagnostic and the "expected
versus got" into annotation messages.
2025-04-22 12:08:03 -04:00
Andrew Gallant 298f43f34e red_knot_python_semantic: add invalid assignment diagnostic snapshot
This tests the diagnostic rendering of a case that wasn't previously
covered by snapshots: when unpacking fails because there are too few
values, but where the left hand side can tolerate "N or more." In the
code, this is a distinct diagnostic, so we capture it here.

(Sorry about the diff here, but it made sense to rename the other
sections and that changes the name of the snapshot file.)
2025-04-22 12:08:03 -04:00
Andrew Gallant 3b300559ab red_knot_python_semantic: remove `#[must_use]` on diagnostic guard constructor
I believe this was an artifact of an older iteration of the diagnostic
reporting API. But this is strictly not necessary now, and indeed, might
even be annoying. It is okay, but perhaps looks a little odd, to do
`builder.into_diagnostic("...")` if you don't want to add anything else
to the diagnostic.
2025-04-22 12:08:03 -04:00
Andrew Gallant 14f71ceb83 red_knot_python_semantic: add helper method for creating a secondary annotation
I suspect this will be used pretty frequently (I wanted it
immediately). And more practically, this avoids needing to
import `Annotation` to create it.
2025-04-22 12:08:03 -04:00
Alex Waygood 6bdffc3cbf
[red-knot] Consider two instance types disjoint if the underlying classes have disjoint metaclasses (#17545) 2025-04-22 15:14:10 +01:00
Aria Desires 775815ef22
Update cargo-dist and apply config improvements (#17453) 2025-04-22 10:05:15 -04:00
Carl Meyer 0299a52fb1
[red-knot] Add list of failing/slow ecosystem projects (#17474)
## Summary

I ran red-knot on every project in mypy-primer. I moved every project
where red-knot ran to completion (fast enough, and mypy-primer could
handle its output) into `good.txt`, so it will run in our CI.

The remaining projects I left listed in `bad.txt`, with a comment
summarizing the failure mode (a few don't fail, they are just slow -- on
a debug build, at least -- or output too many diagnostics for
mypy-primer to handle.)

We will now run CI on 109 projects; 34 are left in `bad.txt`.

## Test Plan

CI on this PR!

---------

Co-authored-by: David Peter <mail@david-peter.de>
2025-04-22 14:15:36 +02:00
David Peter 83d5ad8983
[red-knot] mypy_primer: extend ecosystem checks (#17544)
## Summary

Takes the `good.txt` changes from #17474, and removes the following
projects:
- arrow (not part of mypy_primer upstream)
- freqtrade, hydpy, ibis, pandera, xarray (saw panics locally, all
related to try_metaclass cycles)

Increases the mypy_primer CI run time to ~4 min.

## Test Plan

Three successful CI runs.
2025-04-22 13:39:42 +02:00
Alex Waygood ae6fde152c
[red-knot] Move `InstanceType` to its own submodule (#17525) 2025-04-22 11:34:46 +00:00
David Peter 38a3b056e3
[red-knot] mypy_primer: Use upstream repo (#17500)
## Summary

Switch to the official version of
[`mypy_primer`](https://github.com/hauntsaninja/mypy_primer), now that
Red Knot support has been upstreamed (see
https://github.com/hauntsaninja/mypy_primer/pull/138,
https://github.com/hauntsaninja/mypy_primer/pull/135,
https://github.com/hauntsaninja/mypy_primer/pull/151,
https://github.com/hauntsaninja/mypy_primer/pull/155).

## Test Plan

Locally and in CI
2025-04-22 11:55:16 +02:00
David Peter 37a0836bd2
[red-knot] `typing.dataclass_transform` (#17445)
## Summary

* Add initial support for `typing.dataclass_transform`
* Support decorating a function decorator with `@dataclass_transform(…)`
(used by `attrs`, `strawberry`)
* Support decorating a metaclass with `@dataclass_transform(…)` (used by
`pydantic`, but doesn't work yet, because we don't seem to model
`__new__` calls correctly?)
* *No* support yet for decorating base classes with
`@dataclass_transform(…)`. I haven't figured out how this even supposed
to work. And haven't seen it being used.
* Add `strawberry` as an ecosystem project, as it makes heavy use of
`@dataclass_transform`

## Test Plan

New Markdown tests
2025-04-22 10:33:02 +02:00
Matthew Mckee 9b5fe51b32
[red-knot] Fix variable name (#17532) 2025-04-21 17:20:04 -07:00
Matthew Mckee 53ffe7143f
[red-knot] Add basic subtyping between class literal and callable (#17469)
## Summary

This covers step 1 from
https://typing.python.org/en/latest/spec/constructors.html#converting-a-constructor-to-callable

Part of #17343

## Test Plan

Update is_subtype_of.md and is_assignable_to.md

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2025-04-21 22:29:36 +00:00
Hans 21561000b1
[`pyupgrade`] Add fix safety section to docs (`UP030`) (#17443)
## Summary

add fix safety section to format_literals, for #15584
2025-04-21 14:14:58 -04:00
w0nder1ng 9c0772d8f0
[`perflint`] Allow list function calls to be replaced with a comprehension (`PERF401`) (#17519)
This is an implementation of the discussion from #16719. 

This change will allow list function calls to be replaced with
comprehensions:

```python
result = list()
for i in range(3):
    result.append(i + 1)
# becomes
result = [i + 1 for i in range(3)]
```

I added a new test to `PERF401.py` to verify that this fix will now work
for `list()`.
2025-04-21 13:29:24 -04:00
Alex Waygood be54b840e9
[red-knot] Simplify visibility constraint handling for `*`-import definitions (#17486) 2025-04-21 15:33:35 +00:00
Alex Waygood 45b5dedee2
[red-knot] Detect (some) invalid protocols (#17488) 2025-04-21 16:24:19 +01:00
Alex Waygood 9ff4772a2c
[red-knot] Correctly identify protocol classes (#17487) 2025-04-21 16:17:06 +01:00
Shunsuke Shibayama da6b68cb58
[red-knot] infer attribute assignments bound in comprehensions (#17396)
## Summary

This PR is a follow-up to #16852.

Instance variables bound in comprehensions are recorded, allowing type
inference to work correctly.

This required adding support for unpacking in comprehension which
resolves https://github.com/astral-sh/ruff/issues/15369.

## Test Plan

One TODO in `mdtest/attributes.md` is now resolved, and some new test
cases are added.

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2025-04-19 06:42:48 +05:30
Carl Meyer 2a478ce1b2
[red-knot] simplify gradually-equivalent types out of unions and intersections (#17467)
## Summary

If two types are gradually-equivalent, that means they share the same
set of possible materializations. There's no need to keep two such types
in the same union or intersection; we should simplify them.

Fixes https://github.com/astral-sh/ruff/issues/17465

The one downside here is that now we will simplify e.g. `Unknown |
Todo(...)` to just `Unknown`, if `Unknown` was added to the union first.
This is correct from a type perspective (they are equivalent types), but
it can mean we lose visibility into part of the cause for the type
inferring as unknown. I think this is OK, but if we think it's important
to avoid this, I can add a special case to try to preserve `Todo` over
`Unknown`, if we see them both in the same union or intersection.

## Test Plan

Added and updated mdtests.
2025-04-18 15:08:57 -07:00
Carl Meyer 8fe2dd5e03
[red-knot] pull primer projects to run from file (#17473)
## Summary

The long line of projects in `mypy_primer.yaml` is hard to work with
when adding projects or checking whether they are currently run. Use a
one-per-line text file instead.

## Test Plan

Ecosystem check on this PR.
2025-04-18 21:20:18 +00:00
Alex Waygood 454ad15aee
[red-knot] Fix MRO inference for protocol classes; allow inheritance from subscripted `Generic[]`; forbid subclassing unsubscripted `Generic` (#17452) 2025-04-18 19:55:53 +00:00
Hans fd3fc34a9e
[`pyflakes`] Add fix safety section to docs (`F601`, `F602`) (#17440)
## Summary

add fix safety section to repeated_keys_docs, for #15584

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2025-04-18 18:27:40 +00:00
Hans c550b4d565
[`pyupgrade`] Add fix safety section to docs (`UP008`, `UP022`) (#17441)
## Summary

add fix safety section to replace_stdout_stderr and
super_call_with_parameters, for #15584
I checked the behavior and found that these two files could only
potentially delete the appended comments, so I submitted them as a PR.
2025-04-18 13:48:13 -04:00
Vasco Schiavo f8061e8b99
[`refurb`] Mark the `FURB161` fix unsafe except for integers and booleans (#17240)
The PR fixes #16457 .

Specifically, `FURB161` is marked safe, but the rule generates safe
fixes only in specific cases. Therefore, we attempt to mark the fix as
unsafe when we are not in one of these cases.

For instances, the fix is marked as aunsafe just in case of strings (as
pointed out in the issue). Let me know if I should change something.

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2025-04-18 13:46:01 -04:00
Carl Meyer 27a315b740
[red-knot] add fixpoint iteration for Type::member_lookup_with_policy (#17464)
## Summary

Member lookup can be cyclic, with type inference of implicit members. A
sample case is shown in the added mdtest.

There's no clear way to handle such cases other than to fixpoint-iterate
the cycle.

Fixes #17457.

## Test Plan

Added test.
2025-04-18 10:20:03 -07:00
w0nder1ng 08221454f6
[`perflint`] Implement fix for `manual-dict-comprehension` (`PERF403`) (#16719)
## Summary

This change adds an auto-fix for manual dict comprehensions. It also
copies many of the improvements from #13919 (and associated PRs fixing
issues with it), and moves some of the utility functions from
`manual_list_comprehension.rs` into a separate `helpers.rs` to be used
in both.

## Test Plan

I added a preview test case to showcase the new fix and added a test
case in `PERF403.py` to make sure lines with semicolons function. I
didn't yet make similar tests to the ones I added earlier to
`PERF401.py`, but the logic is the same, so it might be good to add
those to make sure they work.
2025-04-18 13:10:40 -04:00
Vasco Schiavo 5fec1039ed
[`pylint`] Make fix unsafe if it deletes comments (`PLR1730`) (#17459)
The PR addresses issue #17311

---------

Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2025-04-18 12:49:01 -04:00
Douglas Creager 787bcd1c6a
[red-knot] Handle explicit class specialization in type expressions (#17434)
You can now use subscript expressions in a type expression to explicitly
specialize generic classes, just like you could already do in value
expressions.

This still does not implement bidirectional checking, so a type
annotation on an assignment does not influence how we infer a
specialization for a (not explicitly specialized) constructor call. You
might get an `invalid-assignment` error if (a) we cannot infer a class
specialization from the constructor call (in which case you end up e.g.
trying to assign `C[Unknown]` to `C[int]`) or if (b) we can infer a
specialization, but it doesn't match the annotation.

Closes https://github.com/astral-sh/ruff/issues/17432
2025-04-18 11:49:22 -04:00
Matthew Mckee 5853eb28dd
[red-knot] allow assignment expression in call compare narrowing (#17461)
## Summary

There was some narrowing constraints not covered from the previous PR

```py
def _(x: object):
    if (type(y := x)) is bool:
        reveal_type(y)  # revealed: bool
```

Also, refactored a bit

## Test Plan

Update type_api.md
2025-04-18 08:46:15 -07:00
Carl Meyer 84d064a14c
[red-knot] fix building unions with literals and AlwaysTruthy/AlwaysFalsy (#17451)
In #17403 I added a comment asserting that all same-kind literal types
share all the same super-types. This is true, with two notable
exceptions: the types `AlwaysTruthy` and `AlwaysFalsy`. These two types
are super-types of some literal types within a given kind and not
others: `Literal[0]`, `Literal[""]`, and `Literal[b""]` inhabit
`AlwaysFalsy`, while other literals inhabit `AlwaysTruthy`.

This PR updates the literal-unions optimization to handle these types
correctly.

Fixes https://github.com/astral-sh/ruff/issues/17447

Verified locally that `QUICKCHECK_TESTS=100000 cargo test -p
red_knot_python_semantic -- --ignored types::property_tests::stable` now
passes again.
2025-04-18 08:20:03 -07:00
Carl Meyer e4e405d2a1
[red-knot] Type narrowing for assertions (take 2) (#17345)
## Summary

Fixes #17147.

This was landed in #17149 and then reverted in #17335 because it caused
cycle panics in checking pybind11. #17456 fixed the cause of that panic.

## Test Plan

Add new narrow/assert.md test file

Co-authored-by: Matthew Mckee <matthewmckee04@yahoo.co.uk>
2025-04-18 08:11:07 -07:00
Carl Meyer 1918c61623
[red-knot] class bases are not affected by __future__.annotations (#17456)
## Summary

We were over-conflating the conditions for deferred name resolution.
`from __future__ import annotations` defers annotations, but not class
bases. In stub files, class bases are also deferred. Modeling this
correctly also reduces likelihood of cycles in Python files using `from
__future__ import annotations` (since deferred resolution is inherently
cycle-prone). The same cycles are still possible in `.pyi` files, but
much less likely, since typically there isn't anything in a `pyi` file
that would cause an early return from a scope, or otherwise cause
visibility constraints to persist to end of scope. Usually there is only
code at module global scope and class scope, which can't have `return`
statements, and `raise` or `assert` statements in a stub file would be
very strange. (Technically according to the spec we'd be within our
rights to just forbid a whole bunch of syntax outright in a stub file,
but I kinda like minimizing unnecessary differences between the handling
of Python files and stub files.)

## Test Plan

Added mdtests.
2025-04-18 06:46:21 -07:00
Dhruv Manilawala 44ad201262
[red-knot] Add support for overloaded functions (#17366)
## Summary

Part of #15383, this PR adds support for overloaded callables.

Typing spec: https://typing.python.org/en/latest/spec/overload.html

Specifically, it does the following:
1. Update the `FunctionType::signature` method to return signatures from
a possibly overloaded callable using a new `FunctionSignature` enum
2. Update `CallableType` to accommodate overloaded callable by updating
the inner type to `Box<[Signature]>`
3. Update the relation methods on `CallableType` with logic specific to
overloads
4. Update the display of callable type to display a list of signatures
enclosed by parenthesis
5. Update `CallableTypeOf` special form to recognize overloaded callable
6. Update subtyping, assignability and fully static check to account for
callables (equivalence is planned to be done as a follow-up)

For (2), it is required to be done in this PR because otherwise I'd need
to add some workaround for `into_callable_type` and I though it would be
best to include it in here.

For (2), another possible design would be convert `CallableType` in an
enum with two variants `CallableType::Single` and
`CallableType::Overload` but I decided to go with `Box<[Signature]>` for
now to (a) mirror it to be equivalent to `overload` field on
`CallableSignature` and (b) to avoid any refactor in this PR. This could
be done in a follow-up to better split the two kind of callables.

### Design

There were two main candidates on how to represent the overloaded
definition:
1. To include it in the existing infrastructure which is what this PR is
doing by recognizing all the signatures within the
`FunctionType::signature` method
2. To create a new `Overload` type variant

<details><summary>For context, this is what I had in mind with the new
type variant:</summary>
<p>

```rs
pub enum Type {
	FunctionLiteral(FunctionType),
    Overload(OverloadType),
    BoundMethod(BoundMethodType),
    ...
}

pub struct OverloadType {
	// FunctionLiteral or BoundMethod
    overloads: Box<[Type]>,
	// FunctionLiteral or BoundMethod
    implementation: Option<Type>
}

pub struct BoundMethodType {
    kind: BoundMethodKind,
    self_instance: Type,
}

pub enum BoundMethodKind {
    Function(FunctionType),
    Overload(OverloadType),
}
```

</p>
</details> 

The main reasons to choose (1) are the simplicity in the implementation,
reusing the existing infrastructure, avoiding any complications that the
new type variant has specifically around the different variants between
function and methods which would require the overload type to use `Type`
instead.

### Implementation

The core logic is how to collect all the overloaded functions. The way
this is done in this PR is by recording a **use** on the `Identifier`
node that represents the function name in the use-def map. This is then
used to fetch the previous symbol using the same name. This way the
signatures are going to be propagated from top to bottom (from first
overload to the final overload or the implementation) with each function
/ method. For example:

```py
from typing import overload

@overload
def foo(x: int) -> int: ...
@overload
def foo(x: str) -> str: ...
def foo(x: int | str) -> int | str:
	return x
```

Here, each definition of `foo` knows about all the signatures that comes
before itself. So, the first overload would only see itself, the second
would see the first and itself and so on until the implementation or the
final overload.

This approach required some updates specifically recognizing
`Identifier` node to record the function use because it doesn't use
`ExprName`.

## Test Plan

Update existing test cases which were limited by the overload support
and add test cases for the following cases:
* Valid overloads as functions, methods, generics, version specific
* Invalid overloads as stated in
https://typing.python.org/en/latest/spec/overload.html#invalid-overload-definitions
(implementation will be done in a follow-up)
* Various relation: fully static, subtyping, and assignability (others
in a follow-up)

## Ecosystem changes

_WIP_

After going through the ecosystem changes (there are a lot!), here's
what I've found:

We need assignability check between a callable type and a class literal
because a lot of builtins are defined as classes in typeshed whose
constructor method is overloaded e.g., `map`, `sorted`, `list.sort`,
`max`, `min` with the `key` parameter, `collections.abc.defaultdict`,
etc. (https://github.com/astral-sh/ruff/issues/17343). This makes up
most of the ecosystem diff **roughly 70 diagnostics**. For example:

```py
from collections import defaultdict

# red-knot: No overload of bound method `__init__` matches arguments [lint:no-matching-overload]
defaultdict(int)
# red-knot: No overload of bound method `__init__` matches arguments [lint:no-matching-overload]
defaultdict(list)

class Foo:
    def __init__(self, x: int):
        self.x = x

# red-knot: No overload of function `__new__` matches arguments [lint:no-matching-overload]
map(Foo, ["a", "b", "c"])
```

Duplicate diagnostics in unpacking
(https://github.com/astral-sh/ruff/issues/16514) has **~16
diagnostics**.

Support for the `callable` builtin which requires `TypeIs` support. This
is **5 diagnostics**. For example:
```py
from typing import Any

def _(x: Any | None) -> None:
    if callable(x):
        # red-knot: `Any | None`
        # Pyright: `(...) -> object`
        # mypy: `Any`
        # pyrefly: `(...) -> object`
        reveal_type(x)
```

Narrowing on `assert` which has **11 diagnostics**. This is being worked
on in https://github.com/astral-sh/ruff/pull/17345. For example:
```py
import re

match = re.search("", "")
assert match
match.group()  # error: [possibly-unbound-attribute]
```

Others:
* `Self`: 2
* Type aliases: 6
* Generics: 3
* Protocols: 13
* Unpacking in comprehension: 1
(https://github.com/astral-sh/ruff/pull/17396)

## Performance

Refer to
https://github.com/astral-sh/ruff/pull/17366#issuecomment-2814053046.
2025-04-18 09:57:40 +05:30
Hans c7372d218d
[`pyupgrade`] Add fix safety section to docs (`UP036`) (#17444)
## Summary

add fix safety section to outdated_version_block, for #15584
2025-04-17 22:45:53 -04:00
Eric Mark Martin de8f4e62e2
[red-knot] more type-narrowing in match statements (#17302)
## Summary

Add more narrowing analysis for match statements:
* add narrowing constraints from guard expressions
* add negated constraints from previous predicates and guards to
subsequent cases

This PR doesn't address that guards can mutate your subject, and so
theoretically invalidate some of these narrowing constraints that you've
previously accumulated. Some prior art on this issue [here][mutable
guards].

[mutable guards]:
https://www.irif.fr/~scherer/research/mutable-patterns/mutable-patterns-mlworkshop2024-abstract.pdf

## Test Plan

Add some new tests, and update some existing ones


---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2025-04-17 18:18:34 -07:00
Matthew Mckee edfa03a692
[red-knot] Add some narrowing for assignment expressions (#17448)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

Fixes #14866
Fixes #17437

## Test Plan

Update mdtests in `narrow/`
2025-04-17 17:28:06 -07:00
Alex Waygood 9965cee998
[red-knot] Understand `typing.Protocol` and `typing_extensions.Protocol` as equivalent (#17446) 2025-04-17 21:54:22 +01:00
Nuri Jung 58807b2980
Server: Use `min` instead of `max` to limit the number of threads (#17421)
## Summary

Prevent overcommit by using max 4 threads as intended.

Unintuitively, `.max()` returns the maximum value of `self` and the
argument (not limiting to the argument). To limit the value to 4, one
needs to use `.min()`.

https://doc.rust-lang.org/std/cmp/trait.Ord.html#method.max
2025-04-18 01:32:12 +05:30
Brent Westbrook 9c47b6dbb0
[red-knot] Detect version-related syntax errors (#16379)
## Summary
This PR extends version-related syntax error detection to red-knot. The
main changes here are:

1. Passing `ParseOptions` specifying a `PythonVersion` to parser calls
2. Adding a `python_version` method to the `Db` trait to make this
possible
3. Converting `UnsupportedSyntaxError`s to `Diagnostic`s
4. Updating existing mdtests  to avoid unrelated syntax errors

My initial draft of (1) and (2) in #16090 instead tried passing a
`PythonVersion` down to every parser call, but @MichaReiser suggested
the `Db` approach instead
[here](https://github.com/astral-sh/ruff/pull/16090#discussion_r1969198407),
and I think it turned out much nicer.

All of the new `python_version` methods look like this:

```rust
fn python_version(&self) -> ruff_python_ast::PythonVersion {
    Program::get(self).python_version(self)
}
```

with the exception of the `TestDb` in `ruff_db`, which hard-codes
`PythonVersion::latest()`.

## Test Plan

Existing mdtests, plus a new mdtest to see at least one of the new
diagnostics.
2025-04-17 14:00:30 -04:00
Hans d2ebfd6ed7
[`pyflakes`] Add fix safety section (`F841`) (#17410)
add fix safety section to docs for #15584, I'm new to ruff and not sure
if the content of this PR is correct, but I hope it can be helpful.

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2025-04-17 09:58:26 -04:00
Alex Waygood c36f3f5304
[red-knot] Add `KnownFunction` variants for `is_protocol`, `get_protocol_members` and `runtime_checkable` (#17450) 2025-04-17 14:49:52 +01:00
Brent Westbrook fcd50a0496
Bump 0.11.6 (#17449) 2025-04-17 09:20:29 -04:00
Shaygan Hooshyari 3ada36b766
Auto generate `visit_source_order` (#17180)
## Summary

part of: #15655 

I tried generating the source order function using code generation. I
tried a simple approach, but it is not enough to generate all of them
this way.

There is one good thing, that most of the implementations are fine with
this. We only have a few that are not. So one benefit of this PR could
be it eliminates a lot of the code, hence changing the AST structure
will only leave a few places to be fixed.

The `source_order` field determines if a node requires a source order
implementation. If it’s empty it means source order does not visit
anything.

Initially I didn’t want to repeat the field names. But I found two
things:
- `ExprIf` statement unlike other statements does not have the fields
defined in source order. This and also some fields do not need to be
included in the visit. So we just need a way to determine order, and
determine presence.
- Relying on the fields sounds more complicated to me. Maybe another
solution is to add a new attribute `order` to each field? I'm open to
suggestions.
But anyway, except for the `ExprIf` we don't need to write the field
names in order. Just knowing what fields must be visited are enough.

Some nodes had a more complex visitor:

`ExprCompare` required zipping two fields.

`ExprBoolOp` required a match over the fields.

`FstringValue` required a match, I created a new walk_ function that
does the match. and used it in code generation. I don’t think this
provides real value. Because I mostly moved the code from one file to
another. I was tried it as an option. I prefer to leave it in the code
as before.

Some visitors visit a slice of items. Others visit a single element. I
put a check on this in code generation to see if the field requires a
for loop or not. I think better approach is to have a consistent style.
So we can by default loop over any field that is a sequence.

For field types `StringLiteralValue` and `BytesLiteralValue` the types
are not a sequence in toml definition. But they implement `iter` so they
are iterated over. So the code generation does not properly identify
this. So in the code I'm checking for their types.

## Test Plan

All the tests should pass without any changes.
I checked the generated code to make sure it's the same as old code. I'm
not sure if there's a test for the source order visitor.
2025-04-17 08:59:57 -04:00
Alex Waygood bd89838212
[red-knot] Initial tests for protocols (#17436) 2025-04-17 11:36:41 +00:00
David Peter b32407b6f3
[red-knot] Dataclasses: synthesize `__init__` with proper signature (#17428)
## Summary

This changeset allows us to generate the signature of synthesized
`__init__` functions in dataclasses by analyzing the fields on the class
(and its superclasses). There are certain things that I have not yet
attempted to model in this PR, like `kw_only`,
[`dataclasses.KW_ONLY`](https://docs.python.org/3/library/dataclasses.html#dataclasses.KW_ONLY)
or functionality around
[`dataclasses.field`](https://docs.python.org/3/library/dataclasses.html#dataclasses.field).

ticket: https://github.com/astral-sh/ruff/issues/16651

## Ecosystem analysis

These two seem to depend on missing features in generics (see [relevant
code
here](9898ccbb78/tests/core/test_generics.py (L54))):

> ```diff
> + error[lint:unknown-argument]
/tmp/mypy_primer/projects/dacite/tests/core/test_generics.py:54:24:
Argument `x` does not match any known parameter
> + error[lint:unknown-argument]
/tmp/mypy_primer/projects/dacite/tests/core/test_generics.py:54:38:
Argument `y` does not match any known parameter
> ```



These two are true positives. See [relevant code
here](9898ccbb78/tests/core/test_config.py (L154-L161)).

> ```diff
> + error[lint:invalid-argument-type]
/tmp/mypy_primer/projects/dacite/tests/core/test_config.py:161:24:
Argument to this function is incorrect: Expected `int`, found
`Literal["test"]`
> + error[lint:invalid-argument-type]
/tmp/mypy_primer/projects/dacite/tests/core/test_config.py:172:24:
Argument to this function is incorrect: Expected `int | float`, found
`Literal["test"]`
> ```


This one depends on `**` unpacking of dictionaries, which we don't
support yet:

> ```diff
> + error[lint:missing-argument]
/tmp/mypy_primer/projects/mypy_primer/mypy_primer/globals.py:218:11: No
arguments provided for required parameters `new`, `old`, `repo`,
`type_checker`, `mypyc_compile_level`, `custom_typeshed_repo`,
`new_typeshed`, `old_typeshed`, `new_prepend_path`, `old_prepend_path`,
`additional_flags`, `project_selector`, `known_dependency_selector`,
`local_project`, `expected_success`, `project_date`, `shard_index`,
`num_shards`, `output`, `old_success`, `coverage`, `bisect`,
`bisect_output`, `validate_expected_success`,
`measure_project_runtimes`, `concurrency`, `base_dir`, `debug`, `clear`
> ```



## Test Plan

New Markdown tests.
2025-04-17 09:30:59 +02:00
David Peter b4de245a5a
[red-knot] Dataclasses: support `order=True` (#17406)
## Summary

Support dataclasses with `order=True`:

```py
@dataclass(order=True)
class WithOrder:
    x: int

WithOrder(1) < WithOrder(2)  # no error
```

Also adds some additional tests to `dataclasses.md`.

ticket: #16651

## Test Plan

New Markdown tests
2025-04-17 08:58:46 +02:00
Douglas Creager 914095d08f
[red-knot] Super-basic generic inference at call sites (#17301)
This PR adds **_very_** basic inference of generic typevars at call
sites. It does not bring in a full unification algorithm, and there are
a few TODOs in the test suite that are not discharged by this. But it
handles a good number of useful cases! And the PR does not add anything
that would go away with a more sophisticated constraint solver.

In short, we just look for typevars in the formal parameters, and assume
that the inferred type of the corresponding argument is what that
typevar should map to. If a typevar appears more than once, we union
together the corresponding argument types.

Cases we are not yet handling:

- We are not widening literals.
- We are not recursing into parameters that are themselves generic
aliases.
- We are not being very clever with parameters that are union types.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Carl Meyer <carl@astral.sh>
2025-04-16 15:07:36 -04:00
Dhruv Manilawala 5350288d07
[red-knot] Check assignability of bound methods to callables (#17430)
## Summary

This is similar to https://github.com/astral-sh/ruff/pull/17095, it adds
assignability check for bound methods to callables.

## Test Plan

Add test cases to for assignability; specifically it uses gradual types
because otherwise it would just delegate to `is_subtype_of`.
2025-04-17 00:21:59 +05:30
cake-monotone 649610cc98
[red-knot] Support `super` (#17174)
## Summary

closes #16615 

This PR includes:

- Introduces a new type: `Type::BoundSuper`
- Implements member lookup for `Type::BoundSuper`, resolving attributes
by traversing the MRO starting from the specified class
- Adds support for inferring appropriate arguments (`pivot_class` and
`owner`) for `super()` when it is used without arguments

When `super(..)` appears in code, it can be inferred into one of the
following:

- `Type::Unknown`: when a runtime error would occur (e.g. calling
`super()` out of method scope, or when parameter validation inside
`super` fails)
- `KnownClass::Super::to_instance()`: when the result is an *unbound
super object* or when a dynamic type is used as parameters (MRO
traversing is meaningless)
- `Type::BoundSuper`: the common case, representing a properly
constructed `super` instance that is ready for MRO traversal and
attribute resolution

### Terminology

Python defines the terms *bound super object* and *unbound super
object*.

An **unbound super object** is created when `super` is called with only
one argument (e.g.
`super(A)`). This object may later be bound via the `super.__get__`
method. However, this form is rarely used in practice.

A **bound super object** is created either by calling
`super(pivot_class, owner)` or by using the implicit form `super()`,
where both arguments are inferred from the context. This is the most
common usage.

### Follow-ups

- Add diagnostics for `super()` calls that would result in runtime
errors (marked as TODO)
- Add property tests for `Type::BoundSuper`

## Test Plan

- Added `mdtest/class/super.md`

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2025-04-16 18:41:55 +00:00
Wei Lee 1a79722ee0
[`airflow`] Extend `AIR311` rules (#17422)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

* Extend the following AIR311 rules
* `airflow.io.path.ObjectStoragePath` → `airflow.sdk.ObjectStoragePath`
    * `airflow.io.storage.attach` → `airflow.sdk.io.attach`
    * `airflow.models.dag.DAG` → `airflow.sdk.DAG`
    * `airflow.models.DAG` → `airflow.sdk.DAG`
    * `airflow.decorators.dag` → `airflow.sdk.dag`
    * `airflow.decorators.task` → `airflow.sdk.task`
    * `airflow.decorators.task_group` → `airflow.sdk.task_group`
    * `airflow.decorators.setup` → `airflow.sdk.setup`
    * `airflow.decorators.teardown` → `airflow.sdk.teardown`

## Test Plan

<!-- How was it tested? -->

The test case has been added to the button of the existing test
fixtures, confirmed to be correct and later reorgnaized
2025-04-16 12:40:15 -04:00
Carl Meyer b67590bfde
[red-knot] simplify union size limit handling (#17429) 2025-04-16 09:22:16 -07:00
Wei Lee e6a2de3ac6
[`airflow`] Extract `AIR311` from `AIR301` rules (`AIR301`, `AIR311`) (#17310)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

As discussed in
https://github.com/astral-sh/ruff/issues/14626#issuecomment-2766146129,
we're to separate suggested changes from required changes.

The following symbols have been moved to AIR311 from AIR301. They still
work in Airflow 3.0, but they're suggested to be changed as they're
expected to be removed in a future version.

* arguments
    * `airflow..DAG | dag`
        * `sla_miss_callback`
    * operators
        * `sla`
* name
* `airflow.Dataset] | [airflow.datasets.Dataset` → `airflow.sdk.Asset`
    * `airflow.datasets, rest @ ..`
        * `DatasetAlias` → `airflow.sdk.AssetAlias`
        * `DatasetAll` → `airflow.sdk.AssetAll`
        * `DatasetAny` → `airflow.sdk.AssetAny`
* `expand_alias_to_datasets` → `airflow.sdk.expand_alias_to_assets`
        * `metadata.Metadata` → `airflow.sdk.Metadata`
    <!--airflow.models.baseoperator-->
    * `airflow.models.baseoperator.chain` → `airflow.sdk.chain`
* `airflow.models.baseoperator.chain_linear` →
`airflow.sdk.chain_linear`
* `airflow.models.baseoperator.cross_downstream` →
`airflow.sdk.cross_downstream`
* `airflow.models.baseoperatorlink.BaseOperatorLink` →
`airflow.sdk.definitions.baseoperatorlink.BaseOperatorLink`
    * `airflow.timetables, rest @ ..`
* `datasets.DatasetOrTimeSchedule` → *
`airflow.timetables.assets.AssetOrTimeSchedule`
    * `airflow.utils, rest @ ..`
        <!--airflow.utils.dag_parsing_context-->
* `dag_parsing_context.get_parsing_context` →
`airflow.sdk.get_parsing_context`

## Test Plan

<!-- How was it tested? -->

The test fixture has been updated acccordingly
2025-04-16 11:06:57 -04:00
Carl Meyer c7b5067ef8
[red-knot] set a size limit on unions of literals (#17419)
## Summary

Until we optimize our full union/intersection representation to
efficiently handle large numbers of same-kind literal types "as a
block", set a fairly low limit on the size of unions of literals.

We will want to increase this limit once we've made the broader
efficiency improvement (tracked in
https://github.com/astral-sh/ruff/issues/17420).

## Test Plan

`cargo bench --bench red_knot`
2025-04-16 14:23:11 +00:00
Carl Meyer 5a115e750d
[red-knot] make large-union benchmark slow again (#17418)
## Summary

Now that we've made the large-unions benchmark fast, let's make it slow
again!

This adds a following operation (checking `len`) on the large union,
which is slow, even though building the large union is now fast. (This
is also observed in a real-world code sample.) It's slow because for
every element of the union, we fetch its `__len__` method and check it
for compatibility with `Sized`.

We can make this fast by extending the grouped-types approach, as
discussed in https://github.com/astral-sh/ruff/pull/17403, so that we
can do this `__len__` operation (which is identical for every literal
string) just once for all literal strings, instead of once per literal
string type in the union.

Until we do that, we can make this acceptably fast again for now by
setting a lowish limit on union size, which we can increase in the
future when we make it fast. This is what I'll do in the next PR.

## Test Plan

`cargo bench --bench red_knot`
2025-04-16 14:05:42 +00:00
Carl Meyer a1f361949e
[red-knot] optimize building large unions of literals (#17403)
## Summary

Special-case literal types in `UnionBuilder` to speed up building large
unions of literals.

This optimization is extremely effective at speeding up building even a
very large union (it improves the large-unions benchmark by 41x!). The
problem we can run into is that it is easy to then run into another
operation on the very large union (for instance, narrowing may add it to
an intersection, which then distributes it over the intersection) which
is still slow.

I think it is possible to avoid this by extending this optimized
"grouped" representation throughout not just `UnionBuilder`, but all of
our union and intersection representations. I have some work in this
direction, but rather than spending more time on it right now, I'd
rather just land this much, along with a limit on the size of these
unions (to avoid building really big unions quickly and then hitting
issues where they are used.)

## Test Plan

Existing tests and benchmarks.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-04-16 13:55:37 +00:00
Matthew Mckee 13ea4e5d0e
[red-knot] Fix comments in type_api.md (#17425) 2025-04-16 11:19:48 +00:00
Matthew Mckee a2a7b1e268
[red-knot] Do not assume that `x != 0` if `x` inhabits `~Literal[0]` (#17370)
## Summary

Fixes incorrect negated type eq and ne assertions in
infer_binary_intersection_type_comparison

fixes #17360

## Test Plan

Remove and update some now incorrect tests
2025-04-15 22:27:27 -07:00
Carl Meyer 1dedcb9e0d
[red-knot] make large-union benchmark more challenging (#17416) 2025-04-15 18:04:57 -07:00
Douglas Creager 807a8a7a29
[red-knot] Acknowledge that `T & anything` is assignable to `T` (#17413)
This reworks the assignability/subtyping relations a bit to handle
typevars better:

1. For the most part, types are not assignable to typevars, since
there's no guarantee what type the typevar will be specialized to.

2. An intersection is an exception, if it contains the typevar itself as
one of the positive elements. This should fall out from the other
clauses automatically, since a typevar is assignable to itself, and an
intersection is assignable to something if any positive element is
assignable to that something.

3. Constrained typevars are an exception, since they must be specialized
to _exactly_ one of the constraints, not to a _subtype_ of a constraint.
If a type is assignable to every constraint, then the type is also
assignable to the constrained typevar.

We already had a special case for (3), but the ordering of it relative
to the intersection clauses meant we weren't catching (2) correctly. To
fix this, we keep the special case for (3), but fall through to the
other match arms for non-constrained typevars and if the special case
isn't true for a constrained typevar.

Closes https://github.com/astral-sh/ruff/issues/17364
2025-04-15 16:34:07 -04:00
Dhruv Manilawala bfc17fecaa
Raise syntax error when `\` is at end of file (#17409)
## Summary

This PR fixes a bug in the lexer specifically around line continuation
character at end of file.

The reason this was occurring is because the lexer wouldn't check for
EOL _after_ consuming the escaped newline but only if the EOL was right
after the line continuation character.

fixes: #17398 

## Test Plan

Add tests for the scenarios where this should occur mainly (a) when the
state is `AfterNewline` and (b) when the state is `Other`.
2025-04-15 21:26:12 +05:30
cake-monotone 942cb9e3ad
[red-knot] Add regression tests for narrowing constraints cycles (#17408)
## Summary

closes #17215 

This PR adds regression tests for the following cycled queries:
- all_narrowing_constraints_for_expression
- all_negative_narrowing_constraints_for_expression

The following test files are included:
-
`red_knot_project/resources/test/corpus/cycle_narrowing_constraints.py`
-
`red_knot_project/resources/test/corpus/cycle_negative_narrowing_constraints.py`

These test names don't follow the existing naming convention based on
Cinder.
However, I’ve chosen these names to clearly reflect the regression
cases.
Let me know if you’d prefer to align more closely with the existing
Cinder-based style.

## Test Plan

```sh
git checkout 1a6a10b30
cargo test --package red_knot_project  -- corpus
```
2025-04-15 07:27:54 -07:00
Alex Waygood 312a487ea7
[red-knot] Add some knowledge of `__all__` to `*`-import machinery (#17373) 2025-04-15 12:56:40 +01:00
Andrew Gallant 1d49e71ddd dependencies: switch from `chrono` to `jiff`
We weren't really using `chrono` for anything other than getting the
current time and formatting it for logs.

Unfortunately, this doesn't quite get us to a point where `chrono`
can be removed. From what I can tell, we're still bringing it via
[`tracing-subscriber`](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/)
and
[`quick-junit`](https://docs.rs/quick-junit/latest/quick_junit/).
`tracing-subscriber` does have an
[issue open about Jiff](https://github.com/tokio-rs/tracing/discussions/3128),
but there's no movement on it.

Normally I'd suggest holding off on this since it doesn't get us all of
the way there and it would be better to avoid bringing in two datetime
libraries, but we are, it appears, already there. In particular,
`env_logger` brings in Jiff. So this PR doesn't really make anything
worse, but it does bring us closer to an all-Jiff world.
2025-04-15 07:47:55 -04:00
Alex Waygood 79b921179c
[red-knot] Further optimize `*`-import visibility constraints (#17375) 2025-04-15 12:32:22 +01:00
David Peter 1f85e0d0a0
[red-knot] Minor 'member_lookup_with_policy' fix (#17407)
## Summary

Couldn't really think of a regression test, but it's probably better to
fix this if we ever add new member-lookup-policies.
2025-04-15 13:28:51 +02:00
David Peter 03adae80dc
[red-knot] Initial support for `dataclass`es (#17353)
## Summary

Add very early support for dataclasses. This is mostly to make sure that
we do not emit false positives on dataclass construction, but it also
lies some foundations for future extensions.

This seems like a good initial step to merge to me, as it basically
removes all false positives on dataclass constructor calls. This allows
us to use the ecosystem checks for making sure we don't introduce new
false positives as we continue to work on dataclasses.

## Ecosystem analysis

I re-ran the mypy_primer evaluation of [the `__init__`
PR](https://github.com/astral-sh/ruff/pull/16512) locally with our
current mypy_primer version and project selection. It introduced 1597
new diagnostics. Filtering those by searching for `__init__` and
rejecting those that contain `invalid-argument-type` (those could not
possibly be solved by this PR) leaves 1281 diagnostics. The current
version of this PR removes 1171 diagnostics, which leaves 110
unaccounted for. I extracted the lint + file path for all of these
diagnostics and generated a diff (of diffs), to see which
`__init__`-diagnostics remain. I looked at a subset of these: There are
a lot of `SomeClass(*args)` calls where we don't understand the
unpacking yet (this is not even related to `__init__`). Some others are
related to `NamedTuple`, which we also don't support yet. And then there
are some errors related to `@attrs.define`-decorated classes, which
would probably require support for `dataclass_transform`, which I made
no attempt to include in this PR.

## Test Plan

New Markdown tests.
2025-04-15 10:39:21 +02:00
github-actions[bot] 4894f52bae
Sync vendored typeshed stubs (#17402)
Close and reopen this PR to trigger CI

---------

Co-authored-by: typeshedbot <>
Co-authored-by: David Peter <mail@david-peter.de>
2025-04-15 09:16:42 +02:00
Mike Perlov 3b24fe5c07
[red-knot] improve function/bound method type display (#17294)
## Summary

* Partial #17238
* Flyby from discord discussion - `todo_type!` now statically checks for
no parens in the message to avoid issues between debug & release build
tests

## Test Plan

many mdtests are changing
2025-04-14 15:56:18 -07:00
Dhruv Manilawala b5d529e976
[red-knot] Move relation methods from `CallableType` to `Signature` (#17365)
## Summary

This PR moves all the relation methods from `CallableType` to
`Signature`.

The main reason for this is that `Signature` is going to be the common
denominator between normal and overloaded callables and the core logic
to check a certain relationship is going to just require the information
that would exists on `Signature`. For example, to check whether an
overloaded callable is a subtype of a normal callable, we need to check
whether _every_ overloaded signature is a subtype of the normal
callable's signature. This "every" logic would become part of the
`CallableType` and the core logic of checking the subtyping would exists
on `Signature`.
2025-04-15 03:32:25 +05:30
Brent Westbrook 014bb526f4
[syntax-errors] `await` outside async functions (#17363)
Summary
--

This PR implements detecting the use of `await` expressions outside of
async functions. This is a reimplementation of
[await-outside-async
(PLE1142)](https://docs.astral.sh/ruff/rules/await-outside-async/) as a
semantic syntax error.

Despite the rule name, PLE1142 also applies to `async for` and `async
with`, so these are covered here too.

Test Plan
--

Existing PLE1142 tests.

I also deleted more code from the `SemanticSyntaxCheckerVisitor` to
avoid changes in other parser tests.
2025-04-14 13:01:48 -04:00
Carl Meyer e2a38e4c00
[red-knot] optimize is_subtype_of for literals (#17394)
## Summary

Allows us to establish that two literals do not have a subtype
relationship with each other, without having to fallback to a typeshed
Instance type, which is comparatively slow.

Improves the performance of the many-string-literals union benchmark by
5x.

## Test Plan

`cargo test -p red_knot_python_semantic` and `cargo bench --bench
red_knot`.
2025-04-14 09:42:44 -07:00
Carl Meyer 9bee9429de
[red-knot] add a large-union-of-string-literals benchmark (#17393)
## Summary

Add a benchmark for a large-union case that currently has exponential
blow-up in execution time.

## Test Plan

`cargo bench --bench red_knot`
2025-04-14 09:40:46 -07:00
David Peter 850360a0b4
[red-knot] Document limitations of diagnostics-silencing in unreachable code (#17387)
## Summary

Document the limitations of our current approach to silencing only a
subset of diagnostics in unreachable sections.
2025-04-14 12:55:14 +02:00
Shunsuke Shibayama dfd8eaeb32
[red-knot] detect unreachable attribute assignments (#16852)
## Summary

This PR closes #15967.

Attribute assignments that are statically known to be unreachable are
excluded from consideration for implicit instance attribute type
inference. If none of the assignments are found to be reachable, an
`unresolved-attribute` error is reported.

## Test Plan

[A test
case](https://github.com/astral-sh/ruff/blob/main/crates/red_knot_python_semantic/resources/mdtest/attributes.md#attributes-defined-in-statically-known-to-be-false-branches)
marked as TODO now work as intended, and new test cases have been added.

---------

Co-authored-by: David Peter <mail@david-peter.de>
2025-04-14 09:23:20 +02:00
Dhruv Manilawala 3aa3ee8b89
[red-knot] Use concise message for the server (#17367)
## Summary

This is mainly a follow-up from
https://github.com/astral-sh/ruff/pull/17357 to use the
`concise_message` method for the red-knot server which I noticed
recently while testing the overload implementation.
2025-04-12 04:49:28 +00:00
David Peter f0c3abd198
[red-knot] Minor followup on str.startswith (#17362)
## Summary

Minor follow-up to https://github.com/astral-sh/ruff/pull/17351, thank
you @AlexWaygood.
2025-04-11 18:40:08 +00:00
Dhruv Manilawala e5026c0877
Use concise message to show diagnostics in playground (#17357)
## Summary

This PR fixes the playground to use the new `concise_diagnostic` method.

## Test plan

**Before:**

<img width="1728" alt="Screenshot 2025-04-11 at 11 37 34 AM"
src="https://github.com/user-attachments/assets/cbfcbc52-2e70-4277-9363-ba197711390e"
/>

**After:**

<img width="1728" alt="Screenshot 2025-04-11 at 11 38 03 AM"
src="https://github.com/user-attachments/assets/356ec63c-50d9-49a8-8df4-84000b46fb6d"
/>
2025-04-11 22:44:24 +05:30
Brent Westbrook da32a83c9f
[syntax-errors] `return` outside function (#17300)
Summary
--

This PR reimplements [return-outside-function
(F706)](https://docs.astral.sh/ruff/rules/return-outside-function/) as a
semantic syntax error.

These changes are very similar to those in
https://github.com/astral-sh/ruff/pull/17298.

Test Plan
--

New linter tests, plus existing F706 tests.
2025-04-11 17:05:54 +00:00
Andrew Gallant 7d11ef1564 red_knot_python_semantic: make `TextRange` required for reporting a lint diagnostic
This commit shuffles the reporting API around a little bit such that a
range is required, up front, when reporting a lint diagnostic. This in
turn enables us to make suppression checking eager.

In order to avoid callers needing to provide the range twice, we create
a primary annotation *without* a message inside the `Diagnostic`
encapsulated by the guard. We do this instead of requiring the message
up front because we're concerned about API complexity and the effort
involved in creating the message.

In order to provide a means of attaching a message to the primary
annotation, we expose a convenience API on `LintDiagnosticGuard` for
setting the message. This isn't generally possible for a `Diagnostic`,
but since a `LintDiagnosticGuard` knows how the `Diagnostic` was
constructed, we can offer this API correctly.

It strikes me that it might be easy to forget to attach a primary
annotation message, btu I think this the "least" bad failure mode. And
in particular, it should be somewhat obvious that it's missing once one
adds a snapshot test for how the diagnostic renders.

Otherwise, this API gives us the ability to eagerly check whether a
diagnostic should be reported with nearly minimal information. It also
shouldn't have any footguns since it guarantees that the primary
annotation is tied to the file in the typing context. And it keeps
things pretty simple: callers only need to provide what is actually
strictly necessary to make a diagnostic.
2025-04-11 12:36:36 -04:00
Andrew Gallant b79d43a852 ruff_db: add primary annotation message mutators on `Diagnostic`
This will enable us to provide an API on `LintDiagnosticGuard` for
setting the primary annotation message. It will require an `unwrap()`,
but due to how `LintDiagnosticGuard` will build a `Diagnostic`, this
`unwrap()` will be guaranteed to succeed. (And it won't bubble out to
every user of `LintDiagnosticGuard`.)
2025-04-11 12:36:36 -04:00
Andrew Gallant a4d3c4bf8b red_knot_python_semantic: make the guards implement DerefMut
This is the payoff from removing a bit of indirection. The types still
exist, but now callers don't need to do builder -> reporter ->
diagnostic. They can just conceptually think of it as builder ->
diagnostic.
2025-04-11 12:36:36 -04:00
Andrew Gallant f3cc287a40 red_knot_python_semantic: tweak naming
We're going to make the guards deref to `Diagnostic` in order to remove
a layer of indirection in the reporter API. (Well, technically the layer
is not removed since the types still exist, but in actual _usage_ the
layer will be removed. We'll see how it shakes out in the next commit.)
2025-04-11 12:36:36 -04:00
Andrew Gallant bd5b8a9ec6 ruff_db: tweak APIs accepting a diagnostic message
This expands the set of types accepted for diagnostic messages. Instead
of only `std::fmt::Display` impls, we now *also* accept a concrete
`DiagnosticMessage`.

This will be useful to avoid unnecessary copies of every single
diagnostic message created via `InferContext::report_lint`. (I'll call
out how this helps in a subsequent commit.)
2025-04-11 12:36:36 -04:00
David Peter 47956db567
[red-knot] Specialize `str.startswith` for string literals (#17351)
## Summary

Infer precise Boolean literal types for `str.startswith` calls where the
instance and the prefix are both string literals. This allows us to
understand `sys.platform.startswith(…)` branches.

## Test Plan

New Markdown tests
2025-04-11 16:26:45 +02:00
Brent Westbrook ffef71d106
[syntax-errors] `yield`, `yield from`, and `await` outside functions (#17298)
Summary
--

This PR reimplements [yield-outside-function
(F704)](https://docs.astral.sh/ruff/rules/yield-outside-function/) as a
semantic syntax error. Despite the name, this rule covers `yield from`
and `await` in addition to `yield`.

Test Plan
--

New linter tests, along with the existing F704 test.

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2025-04-11 10:16:23 -04:00
Micha Reiser 7e571791c0
[red-knot] Refresh diagnostics when changing related files (#17350) 2025-04-11 15:50:28 +02:00
Brent Westbrook 8e11c53310
Add `Checker::import_from_typing` (#17340)
Summary
--

This PR replaces uses of version-dependent imports from `typing` or
`typing_extensions` with a centralized `Checker::import_from_typing`
method.

The idea here is to make the fix for #9761 (whatever it ends up being)
applicable to all of the rules performing similar checks.

Test Plan
--

Existing tests for the affected rules.
2025-04-11 13:37:55 +00:00
Max Mynter 1aad180aae
Don't add chaperone space after escaped quote in triple quote (#17216)
Co-authored-by: Micha Reiser <micha@reiser.io>
2025-04-11 10:21:47 +02:00
David Peter 1a3b73720c
[red-knot] Silence errors in unreachable type annotations / class bases (#17342)
## Summary

For silencing `invalid-type-form` diagnostics in unreachable code, we
use the same approach that we use before and check the reachability that
we already record.

For silencing `invalid-bases`, we simply check if the type of the base
is `Never`. If so, we silence the diagnostic with the argument that the
class construction would never happen.

## Test Plan

Updated Markdown tests.
2025-04-10 22:47:47 +02:00
David Peter 8b2727cf67
[red-knot] Silence `unresolved-import` in unreachable code (#17336)
## Summary

Similar to what we did for `unresolved-reference` and
`unresolved-attribute`, we now also silence `unresolved-import`
diagnostics if the corresponding `import` statement is unreachable.

This addresses the (already closed) issue #17049.

## Test Plan

Adapted Markdown tests.
2025-04-10 21:13:28 +02:00
Andrew Gallant 410aa4b8fd red_knot_python_semantic: move TODO comment
It fits with reporting lint diagnostics much better than reporting
general diagnostics.
2025-04-10 13:21:00 -04:00
Andrew Gallant bd58135b0d red_knot_python_semantic: rename `lint()` and `report()`
... to `report_lint()` and `report_diagnostic()`. And rename the old
`report_lint()` to `report_lint_old()`.
2025-04-10 13:21:00 -04:00
Andrew Gallant 81045758d3 ruff_db: use `Annotation::get_message` in more places
I added this accessor because tests want it, but we can also use it in
other places internally. It's a little nicer because it does the
`as_deref()` for you.
2025-04-10 13:21:00 -04:00
Andrew Gallant 0b2a5b5cd3 red_knot_python_semantic: tweak docs on building reporter builders 2025-04-10 13:21:00 -04:00
Andrew Gallant 7d958a9ee5 red_knot_python_semantic: remove the "old" secondary message type
This finally completes the deletion of all old diagnostic types.

We do this by migrating the second (and last) use of secondary
diagnostic messages: to highlight the return type of a function
definition when its return value is inconsistent with the type.

Like the last diagnostic, we do actually change the message here a bit.
We don't need a sub-diagnostic here, and we can instead just add a
secondary annotation to highlight the return type.
2025-04-10 13:21:00 -04:00
Andrew Gallant 7e2eb591bc red_knot_python_semantic: replace one use of "old" secondary diagnostic messages
This is the first use of the new `lint()` reporter.

I somewhat skipped a step here and also modified the actual diagnostic
message itself. The snapshots should tell the story.

We couldn't do this before because we had no way of differentiating
between "message for the diagnostic as a whole" and "message for a
specific code annotation." Now we can, so we can write more precise
messages based on the assumption that users are also seeing the code
snippet.

The downside here is that the actual message text can become quite vague
in the absence of the code snippet. This occurs, for example, with
concise diagnostic formatting. It's unclear if we should do anything
about it. I don't really see a way to make it better that doesn't
involve creating diagnostics with messages for each mode, which I think
would be a major PITA.

The upside is that this code gets a bit simpler, and we very
specifically avoid doing extra work if this specific lint is disabled.
2025-04-10 13:21:00 -04:00
Andrew Gallant ba408f4231 red_knot_python_semantic: update revealed type snapshots
This required a bit of surgery in the diagnostic matching and more
faffing about using a "concise" message from a diagnostic instead of
only printing the "primary" message.
2025-04-10 13:21:00 -04:00
Andrew Gallant 28b64064f5 ruff_db: tweak how the revealed type diagnostic is rendered
In the new diagnostic data model, we really should have a main
diagnostic message *and* a primary span (with an optional message
attached to it) for every diagnostic.

In this commit, I try to make this true for the "revealed type"
diagnostic. Instead of the annotation saying both "revealed type is"
and also the revealed type itself, the annotation is now just the
revealed type and the main diagnostic message is "Revealed type."

I expect this may be controversial. I'm open to doing something
different. I tried to avoid redundancy, but maybe this is a special case
where we want the redundancy. I'm honestly not sure. I do *like* how it
looks with this commit, but I'm not working with Red Knot's type
checking daily, so my opinion doesn't count for much.

This did also require some tweaking to concise diagnostic formatting in
order to preserve the essential information.

This commit doesn't update every relevant snapshot. Just a few. I split
the rest out into the next commit.
2025-04-10 13:21:00 -04:00
Andrew Gallant 75b15ea2d0 red_knot: add explicit test for concise `reveal_type` diagnostic
This test reflects the status quo before we change things.
2025-04-10 13:21:00 -04:00
Andrew Gallant e7e86b8584 red_knot_python_semantic: remove `InferContext::report_diagnostic`
... and replace it with use of `report()`.

Interestingly, this is the only instance of `report_diagnostic` used
directly, and thus anticipated to be the only instance of using
`report()`. If this ends up being a true single use method, we could
make it less generic and tailored specifically to "reveal type."

Two other things to note:

I left the "primary message" as empty. This avoids changing snapshots.
I address this in a subsequent commit.

The creation of a diagnostic here is a bit verbose/annoying. Certainly
more so than it was. This is somewhat expected since our diagnostic
model is more expressive and because we don't have a proc macro. I
avoided creating helpers for this case since there's only one use of
`report()`. But I expect to create helpers for the `lint()` case.
2025-04-10 13:21:00 -04:00
Andrew Gallant f84bc07d56 red_knot_python_semantic: add "reporter" API
This is a surgical change that adds new `report()` and `lint()`
APIs to `InferContext`. These are intended to replace the existing
`report_*` APIs.

The comments should explain what these reporters are meant to do. For
the most part, this is "just" shuffling some code around. The actual
logic for determining whether a lint *should* be reported or not remains
unchanged and we don't make any changes to how a `Diagnostic` is
actually constructed (yet).

I initially tried to just use `LintReporter` and `DiagnosticReporter`
without the builder types, since I perceive the builder types to be an
annoying additional layer. But I found it also exceedingly annoying to
have to construct and provide the diagnostic message before you even
know if you are going to build the diagnostic. I also felt like this
could result in potentially unnecessary and costly querying in some
cases, although this is somewhat hand wavy. So I overall felt like the
builder route was the way to go. If the builders end up being super
annoying, we can probably add convenience APIs for common patterns to
paper over them.
2025-04-10 13:21:00 -04:00
Dylan 7186d5e9ad
Bump 0.11.5 (#17337) 2025-04-10 11:57:44 -05:00
David Peter 5b6e94981d
[red-knot] Silence `unresolved-attribute` in unreachable code (#17305)
## Summary

Basically just repeat the same thing that we did for
`unresolved-reference`, but now for attribute expressions.

We now also handle the case where the unresolved attribute (or the
unresolved reference) diagnostic originates from a stringified type
annotation.

And I made the evaluation of reachability constraints lazy (will only be
evaluated right before we are about to emit a diagnostic).

## Test Plan

New Markdown tests for stringified annotations.
2025-04-10 17:15:47 +02:00
Carl Meyer ec74f2d522
Revert "[red-knot] Type narrowing for assertions (#17149)" (#17335)
I merged #17149 without checking the ecosystem results, and it still
caused a cycle panic in pybind11. Reverting for now until I fix that, so
we don't lose the ecosystem signal on other PRs.
2025-04-10 11:06:25 -04:00
Matthew Mckee 907b6ed7b5
[red-knot] Type narrowing for assertions (#17149)
## Summary

Fixes #17147 

## Test Plan

Add new narrow/assert.md test file

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2025-04-10 10:15:52 -04:00
Carl Meyer fd9882a1f4
[red-knot] avoid unnecessary evaluation of visibility constraint on definitely-unbound symbol (#17326)
This causes spurious query cycles.

This PR also includes an update to Salsa, which gives us db events on
cycle iteration, so we can write tests asserting the absence of a cycle.
2025-04-10 13:59:38 +00:00
David Peter 4d50ee6f52
[red-knot] Track reachability of scopes (#17332)
## Summary

Track the reachability of nested scopes within their parent scopes. We
use this as an additional requirement for emitting
`unresolved-reference` diagnostics (and in the future,
`unresolved-attribute` and `unresolved-import`). This means that we only
emit `unresolved-reference` for a given use of a symbol if the use
itself is reachable (within its own scope), *and if the scope itself is
reachable*. For example, no diagnostic should be emitted for the use of
`x` here:

```py
if False:
    x = 1

    def f():
        print(x)  # this use of `x` is reachable inside the `f` scope,
                  # but the whole `f` scope is not reachable.
```

There are probably more fine-grained ways of solving this problem, but
they require a more sophisticated understanding of nested scopes (see
#15777, in particular
https://github.com/astral-sh/ruff/issues/15777#issuecomment-2788950267).
But it doesn't seem completely unreasonable to silence *this specific
kind of error* in unreachable scopes.

## Test Plan

Observed changes in reachability tests and ecosystem.
2025-04-10 11:56:40 +00:00
Matthew Mckee 10e44124e6
[red-knot] Add inlay type hints (#17214)
Co-authored-by: Micha Reiser <micha@reiser.io>
2025-04-10 09:21:40 +00:00
Micha Reiser 9f6913c488
[red-knot] Update salsa (#17320)
## Summary

Update Salsa to pull in https://github.com/salsa-rs/salsa/pull/788 which
fixes the, by now, famous *access to field whilst the value is being
initialized*.

This PR also re-enables all tests that previously triggered the panic.

## Test Plan

`cargo test`
2025-04-09 16:22:02 -04:00
David Peter 5fef4d4572
Use python.typing.org for typing documentation links (#17323)
## Summary

There is a new official URL for the typing documentation:
https://typing.python.org/

Change all https://typing.readthedocs.io/ links to use the new sub
domain, which is slightly shorter and looks more official.

## Test Plan

Tested to see if each and every new URL is accessible. I noticed that
some links go to https://typing.python.org/en/latest/source/stubs.html
which seems to be outdated, but that is a separate issue. The same page
shows up for the old URL.
2025-04-09 20:38:20 +02:00
Brent Westbrook 144484d46c
Refactor semantic syntax error scope handling (#17314)
## Summary

Based on the discussion in
https://github.com/astral-sh/ruff/pull/17298#discussion_r2033975460, we
decided to move the scope handling out of the `SemanticSyntaxChecker`
and into the `SemanticSyntaxContext` trait. This PR implements that
refactor by:

- Reverting all of the `Checkpoint` and `in_async_context` code in the
`SemanticSyntaxChecker`
- Adding four new methods to the `SemanticSyntaxContext` trait
- `in_async_context`: matches `SemanticModel::in_async_context` and only
detects the nearest enclosing function
- `in_sync_comprehension`: uses the new `is_async` tracking on
`Generator` scopes to detect any enclosing sync comprehension
  - `in_module_scope`: reports whether we're at the top-level scope
  - `in_notebook`: reports whether we're in a Jupyter notebook
- In-lining the `TestContext` directly into the
`SemanticSyntaxCheckerVisitor`
- This allows modifying the context as the visitor traverses the AST,
which wasn't possible before

One potential question here is "why not add a single method returning a
`Scope` or `Scopes` to the context?" The main reason is that the `Scope`
type is defined in the `ruff_python_semantic` crate, which is not
currently a dependency of the parser. It also doesn't appear to be used
in red-knot. So it seemed best to use these more granular methods
instead of trying to access `Scope` in `ruff_python_parser` (and
red-knot).

## Test Plan

Existing parser and linter tests.
2025-04-09 14:23:29 -04:00
Wei Lee c87e3ccb2f
[`airflow`] Add missing `AIR302` attribute check (#17115)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

attribute check was missing in the previous implementation

e.g.

```python
from airflow.api.auth.backend import basic_auth

basic_auth.auth_current_user
```

This PR adds this kind of check.

## Test Plan

<!-- How was it tested? -->

The test case has been added to the button of the existing test
fixtures, confirmed to be correct and later reorgnaized
2025-04-09 13:58:41 -04:00
Alex Waygood 781b653511
[red-knot] Fix false positives on `types.UnionType` instances in type expressions (#17297) 2025-04-09 18:33:16 +01:00
Brent Westbrook 2fbc4d577e
[syntax-errors] Document behavior of `global` declarations in `try` nodes before 3.13 (#17285)
Summary
--

This PR extends the documentation of the `LoadBeforeGlobalDeclaration`
check to specify the behavior on versions of Python before 3.13. Namely,
on Python 3.12, the `else` clause of a `try` statement is visited before
the `except` handlers:

```pycon
Python 3.12.9 (main, Feb 12 2025, 14:50:50) [Clang 19.1.6 ] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 10
>>> def g():
...     try:
...         1 / 0
...     except:
...         a = 1
...     else:
...         global a
...
>>> def f():
...     try:
...         pass
...     except:
...         global a
...     else:
...         print(a)
...
  File "<stdin>", line 5
SyntaxError: name 'a' is used prior to global declaration

```

The order is swapped on 3.13 (see
[CPython#111123](https://github.com/python/cpython/issues/111123)):

```pycon
Python 3.13.2 (main, Feb  5 2025, 08:05:21) [GCC 14.2.1 20250128] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 10
... def g():
...     try:
...         1 / 0
...     except:
...         a = 1
...     else:
...         global a
...
  File "<python-input-0>", line 8
    global a
    ^^^^^^^^
SyntaxError: name 'a' is assigned to before global declaration
>>> def f():
...     try:
...         pass
...     except:
...         global a
...     else:
...         print(a)
...
>>>
```

The current implementation of PLE0118 is correct for 3.13 but not 3.12:
[playground](https://play.ruff.rs/d7467ea6-f546-4a76-828f-8e6b800694c9)
(it flags the first case regardless of Python version).

We decided to maintain this incorrect diagnostic for Python versions
before 3.13 because the pre-3.13 behavior is very unintuitive and
confirmed to be a bug, although the bug fix was not backported to
earlier versions. This can lead to false positives and false negatives
for pre-3.13 code, but we also expect that to be very rare, as
demonstrated by the ecosystem check (before the version-dependent check
was reverted here).

Test Plan
--

N/a
2025-04-09 12:54:21 -04:00
Alex Waygood 73399029b2
[red-knot] Optimise visibility constraints for `*`-import definitions (#17317) 2025-04-09 16:53:26 +00:00
Douglas Creager ff376fc262
[red-knot] Allow explicit specialization of generic classes (#17023)
This PR lets you explicitly specialize a generic class using a subscript
expression. It introduces three new Rust types for representing classes:

- `NonGenericClass`
- `GenericClass` (not specialized)
- `GenericAlias` (specialized)

and two enum wrappers:

- `ClassType` (a non-generic class or generic alias, represents a class
_type_ at runtime)
- `ClassLiteralType` (a non-generic class or generic class, represents a
class body in the AST)

We also add internal support for specializing callables, in particular
function literals. (That is, the internal `Type` representation now
attaches an optional specialization to a function literal.) This is used
in this PR for the methods of a generic class, but should also give us
most of what we need for specializing generic _functions_ (which this PR
does not yet tackle).

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Carl Meyer <carl@astral.sh>
2025-04-09 11:18:46 -04:00
Wei Lee 7c81408c54
[`airflow`] Refactor `AIR301` logic and fix typos (`AIR301`) (#17293)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

* Simplify match conditions in AIR301
* Fix
* `airflow.datasets.manager.DatasetManager` →
`airflow.assets.manager.AssetManager`
* `airflow.www.auth.has_access_dataset` →
`airflow.www.auth.has_access_dataset`

## Test Plan

<!-- How was it tested? -->
The test fixture has been updated accordingly
2025-04-09 10:46:17 -04:00
Wei Lee 7207c86971
[`airflow`] Extract `AIR312` from `AIR302` rules (`AIR302`, `AIR312`) (#17152)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

As discussed in
https://github.com/astral-sh/ruff/issues/14626#issuecomment-2766146129,
we're to separate suggested changes from required changes.

The following symbols has been moved to AIR312 from AIR302. They still
work in Airflow 3.0, but they're suggested to be changed as they're
expected to be removed in future version

```python
from airflow.hooks.filesystem import FSHook
from airflow.hooks.package_index import PackageIndexHook
from airflow.hooks.subprocess import (SubprocessHook, SubprocessResult, working_directory)
from airflow.operators.bash import BashOperator
from airflow.operators.datetime import BranchDateTimeOperator, target_times_as_dates
from airflow.operators.trigger_dagrun import TriggerDagRunLink, TriggerDagRunOperator
from airflow.operators.empty import EmptyOperator
from airflow.operators.latest_only import LatestOnlyOperator
from airflow.operators.python import (BranchPythonOperator, PythonOperator, PythonVirtualenvOperator, ShortCircuitOperator)
from airflow.operators.weekday import BranchDayOfWeekOperator
from airflow.sensors.date_time import DateTimeSensor, DateTimeSensorAsync
from airflow.sensors.external_task import ExternalTaskMarker, ExternalTaskSensor, ExternalTaskSensorLink
from airflow.sensors.filesystem import FileSensor
from airflow.sensors.time_sensor import TimeSensor, TimeSensorAsync
from airflow.sensors.time_delta import TimeDeltaSensor, TimeDeltaSensorAsync, WaitSensor
from airflow.sensors.weekday import DayOfWeekSensor
from airflow.triggers.external_task import DagStateTrigger, WorkflowTrigger
from airflow.triggers.file import FileTrigger
from airflow.triggers.temporal import DateTimeTrigger, TimeDeltaTrigger
```

## Test Plan

<!-- How was it tested? -->

The test fixture has been updated acccordingly

---------

Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2025-04-09 10:43:07 -04:00
Alex Waygood 6ec4c6a97e
[red-knot] Improve handling of visibility constraints in external modules when resolving `*` imports (#17286) 2025-04-09 14:36:52 +00:00
Alex Waygood f1ba596f22
[red-knot] Add more tests for `*` imports (#17315) 2025-04-09 15:10:30 +01:00
Micha Reiser 8249a72412
[red-knot] Default `python-platform` to current platform (#17183)
## Summary

As discussed in https://github.com/astral-sh/ruff/issues/16983 and
"mitigate" said issue for the alpha.

This PR changes the default for `PythonPlatform` to be the current
platform rather than `all`.

I'm not sure if we should be as sophisticated as supporting `ios` and
`android` as defaults but it was easy...

## Test Plan

Updated Markdown tests.

---------

Co-authored-by: David Peter <mail@david-peter.de>
2025-04-09 12:05:18 +02:00
David Peter 00e00b9ad6
[red-knot] Add new 'unreachable code' test case (#17306)
## Summary

This is a new test case that I don't know how to handle yet. It leads to
many false positives in `rich/tests/test_win32_console.py`, which does
something like:

```py
if sys.platform == "win32":
    from windows_only_module import some_symbol

    some_other_symbol = 1

    def some_test_case():
        use(some_symbol)  # Red Knot: unresolved-reference
        use(some_other_symbol)  # Red Knot: unresolved-reference
```

Also adds a test for using unreachable symbols in type annotations or as
class bases.
2025-04-09 11:45:42 +02:00
David Peter 2cee86d807
[red-knot] Add custom `__setattr__` support (#16748)
## Summary

Add support for classes with a custom `__setattr__` method.

## Test Plan

New Markdown tests, ecosystem checks.
2025-04-09 08:04:11 +02:00
Mike Perlov fab7d820bd
[red-knot] Add `__init__` arguments check when doing `try_call` on a class literal (#16512)
## Summary

* Addresses #16511 for simple cases where only `__init__` method is
bound on class or doesn't exist at all.
* fixes a bug with argument counting in bound method diagnostics

Caveats:
* No handling of `__new__` or modified `__call__` on metaclass.
* This leads to a couple of false positive errors in tests

## Test Plan

- A couple new cases in mdtests
- cargo nextest run -p red_knot_python_semantic --no-fail-fast

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
Co-authored-by: David Peter <sharkdp@users.noreply.github.com>
2025-04-08 17:26:20 -04:00
Denys Kyslytsyn ed14dbb1a2
[`flake8-pie`] Avoid false positive for multiple assignment with `auto()` (`PIE796`) (#17274)
This fix closes #16868 

I noticed the issue is assigned, but the assignee appears to be actively
working on another pull request. I hope that’s okay!

<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

As of Python 3.11.1, `enum.auto()` can be used in multiple assignments.
This pattern should not trigger non-unique-enums check.
Reference: [Python docs on
enum.auto()](https://docs.python.org/3/library/enum.html#enum.auto)

This fix updates the check logic to skip enum variant statements where
the right-hand side is a tuple containing a call to `enum.auto()`.

## Test Plan

<!-- How was it tested? -->

The added test case uses the example from the original issue. It
previously triggered a false positive, but now passes successfully.
2025-04-08 15:53:27 -04:00
Brent Westbrook 058439d5d3
[syntax-errors] Async comprehension in sync comprehension (#17177)
Summary
--

Detect async comprehensions nested in sync comprehensions in async
functions before Python 3.11, when this was [changed].

The actual logic of this rule is very straightforward, but properly
tracking the async scopes took a bit of work. An alternative to the
current approach is to offload the `in_async_context` check into the
`SemanticSyntaxContext` trait, but that actually required much more
extensive changes to the `TestContext` and also to ruff's semantic
model, as you can see in the changes up to
31554b473507034735bd410760fde6341d54a050. This version has the benefit
of mostly centralizing the state tracking in `SemanticSyntaxChecker`,
although there was some subtlety around deferred function body traversal
that made the changes to `Checker` more intrusive too (hence the new
linter test).

The `Checkpoint` struct/system is obviously overkill for now since it's
only tracking a single `bool`, but I thought it might be more useful
later.

[changed]: https://github.com/python/cpython/issues/77527

Test Plan
--

New inline tests and a new linter integration test.
2025-04-08 12:50:52 -04:00
Wei Lee dc02732d4d
[`airflow`] Expand module path check to individual symbols (`AIR302`) (#17278)
## Summary

### Improvement
Expand the following moved module into individual symbols.

* airflow.triggers.temporal
* airflow.triggers.file
* airflow.triggers.external_task
* airflow.hooks.subprocess
* airflow.hooks.package_index
* airflow.hooks.filesystem
* airflow.sensors.weekday
* airflow.sensors.time_delta
* airflow.sensors.time_sensor
* airflow.sensors.date_time
* airflow.operators.weekday
* airflow.operators.datetime
* airflow.operators.bash 

This removes `Replacement::ImportPathMoved`.

## Fix
During the expansion, the following paths were also fixed

* airflow.sensors.s3_key_sensor.S3KeySensor →
airflow.providers.amazon.aws.sensors.S3KeySensor
* airflow.operators.sql.SQLThresholdCheckOperator →
airflow.providers.common.sql.operators.sql.SQLThresholdCheckOperator
* airflow.hooks.druid_hook.DruidDbApiHook →
airflow.providers.apache.druid.hooks.druid.DruidDbApiHook
* airflow.hooks.druid_hook.DruidHook →
airflow.providers.apache.druid.hooks.druid.DruidHook
* airflow.kubernetes.pod_generator.extend_object_field →
airflow.providers.cncf.kubernetes.pod_generator.extend_object_field
* airflow.kubernetes.pod_launcher.PodLauncher →
airflow.providers.cncf.kubernetes.pod_launcher_deprecated.PodLauncher
* airflow.kubernetes.pod_launcher.PodStatus →
airflow.providers.cncf.kubernetes.pod_launcher_deprecated.PodStatus
* airflow.kubernetes.pod_generator.PodDefaults →
airflow.providers.cncf.kubernetes.pod_generator.PodDefaults
* airflow.kubernetes.pod_launcher_deprecated.PodDefaults →
airflow.providers.cncf.kubernetes.pod_launcher_deprecated.PodDefaults

### Refactor
As many symbols are moved into the same module,
`SourceModuleMovedToProvider` is introduced for grouping similar logic

## Test Plan
2025-04-08 09:03:27 -04:00
Brent Westbrook 0891689d2f
[syntax-errors] Check annotations in annotated assignments (#17283)
Summary
--

This PR extends the checks in #17101 and #17282 to annotated assignments
after Python 3.13.

Currently stacked on #17282 to include `await`.

Test Plan
--

New inline tests. These are simpler than the other cases because there's
no place to put generics.
2025-04-08 08:56:25 -04:00
Brent Westbrook 127a45622f
[syntax-errors] Extend annotation checks to `await` (#17282)
Summary
--

This PR extends the changes in #17101 to include `await` in the same
positions.

I also renamed the `valid_annotation_function` test to include `_py313`
and explicitly passed a Python version to contrast it with the `_py314`
version.

Test Plan
--

New test cases added to existing files.
2025-04-08 08:55:43 -04:00
David Peter b662c3ff7e
[red-knot] Add support for `assert_never` (#17287)
## Summary

We already have partial "support" for `assert_never`, because it is
annotated as
```pyi
def assert_never(arg: Never, /) -> Never: ...
```
in typeshed. So we already emit a `invalid-argument-type` diagnostic if
the argument type to `assert_never` is not assignable to `Never`.

That is not enough, however. Gradual types like `Any`, `Unknown`,
`@Todo(…)` or `Any & int` can be assignable to `Never`. Which means that
we didn't issue any diagnostic in those cases.

Also, it seems like `assert_never` deserves a dedicated diagnostic
message, not just a generic "invalid argument type" error.

## Test Plan

New Markdown tests.
2025-04-08 09:31:49 +02:00
Denys Kyslytsyn 97dd6d120c
[`flake8-pytest-style`] Avoid false positive for legacy form of `pytest.raises` (`PT011`) (#17231)
This fix closes #17026 

## Summary

The check for the `PytestRaisesTooBroad` rule is now skipped if there is
a second positional argument present, which means `pytest.raises` is
used as a function.

## Test Plan

Tested on the example from the issue, which now passes the check.
```Python3
pytest.raises(Exception, func, *func_args, **func_kwargs).match("error message")
```

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2025-04-08 09:24:47 +02:00
InSync 34e06f2d17
[red-knot] Do not show types for literal expressions on hover (#17290)
## Summary

Resolves #17289.

After this change, Red Knot will no longer show types on hover for
`None`, `...`, `True`, `False`, numbers, strings (but not f-strings),
and bytes literals.

## Test Plan

Unit tests.
2025-04-08 09:05:51 +02:00
David Peter a388c73752
[red-knot] Fix dead-code clippy warning (#17291)
## Summary

Failed run on main:
https://github.com/astral-sh/ruff/actions/runs/14326812317
2025-04-08 08:56:59 +02:00
David Peter 60f2e67454
[red-knot] Reachability analysis (#17199)
## Summary

This implements a new approach to silencing `unresolved-reference`
diagnostics by keeping track of the reachability of each use of a
symbol. The changes merged in
https://github.com/astral-sh/ruff/pull/17169 are still needed for the
"Use of variable in nested function" test case, but that could also be
solved in another way eventually (see
https://github.com/astral-sh/ruff/issues/15777). We can use the same
technique to silence `unresolved-import` and `unresolved-attribute`
false-positives, but I think this could be merged in isolation.

## Test Plan

New Markdown tests, ecosystem tests
2025-04-08 08:37:20 +02:00
Micha Reiser cb7f56fb20
[red-knot] Don't use latency-sensitive for handlers (#17227)
## Summary

The priority latency-sensitive is reserved for actions that need to run
immediately because they would otherwise block the user's action. An
example of this is a format request. VS code blocks the editor until the
save action is complete. That's why formatting a document is very
sensitive to delays and it's important that we always have a worker
thread available to run a format request *immediately*. Another example
are code completions, where it's important that they appear immediately
when the user types.

On the other hand, showing diagnostics, hover, or inlay hints has high
priority but users are used that the editor takes a few ms to compute
the overlay.
Computing this information can also be expensive (e.g. find all
references), blocking the worker for quiet some time (a few 100ms).
That's why it's important
that those requests don't clog the sensitive worker threads.
2025-04-08 08:33:30 +02:00
David Peter 3657f798c9
[red-knot] Add `--python-platform` CLI option (#17284)
## Summary

Add a new `--python-platform` command-line option, in analogy to
`--python-version`.

## Test Plan

Added new integration test.
2025-04-07 21:04:44 +02:00
Matthew Mckee 4a4a376f02
[red-knot] Allow ellipsis default params in stub functions (#17243)
## Summary

Fixes #17234

## Test Plan

Add tests to functions/paremeters.md

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2025-04-07 17:34:59 +00:00
Max Mynter f1d4ba32cc
Fix RUF100 to detect unused file-level noqa directives with specific codes (#17042) (#17061)
Closes #17042

## Summary
This PR fixes the issue outlined in #17042 where RUF100 (unused-noqa)
fails to detect unused file-level noqa directives (`# ruff: noqa` or `#
ruff: noqa: {code}`).

The issue stems from two underlying causes:

1. For blanket file-level directives (`# ruff: noqa`), there's a
circular dependency: the directive exempts all rules including RUF100
itself, which prevents checking for usage. This isn't changed by this
PR. I would argue it is intendend behavior - a blanket `# ruff: noqa`
directive should exempt all rules including RUF100 itself.

2. For code-specific file-level directives (e.g. `# ruff: noqa: F841`),
the handling was missing in the `check_noqa` function. This is added in
this PR.

## Notes
- For file-level directives, the `matches` array is pre-populated with
the specified codes during parsing, unlike line-level directives which
only populate their `matches` array when actually suppressing
diagnostics. This difference requires the somewhat clunky handling of
both cases. I would appreciate guidance on a cleaner design :)

- A more fundamental solution would be to change how file-level
directives initialize the `matches` array in
`FileNoqaDirectives::extract()`, but that requires more substantial
changes as it breaks existing functionality. I suspect discussions in
#16483 are relevant for this.

## Test Plan
- Local verification
- Added a test case and fixture
2025-04-07 09:21:52 -05:00
Wei Lee 1e9e423362
[`airflow`] Update oudated `AIR301`, `AIR302` rules (#17123)
## Summary

Some of the migration rules has been changed during Airflow 3
development. The following are new AIR302 rules. Corresponding AIR301
has also been removed.

* airflow.sensors.external_task_sensor.ExternalTaskMarker →
airflow.providers.standard.sensors.external_task.ExternalTaskMarker
* airflow.sensors.external_task_sensor.ExternalTaskSensor →
airflow.providers.standard.sensors.external_task.ExternalTaskSensor
* airflow.sensors.external_task_sensor.ExternalTaskSensorLink →
airflow.providers.standard.sensors.external_task.ExternalTaskSensorLink
* airflow.sensors.time_delta_sensor.TimeDeltaSensor →
airflow.providers.standard.sensors.time_delta.TimeDeltaSensor
* airflow.operators.dagrun_operator.TriggerDagRunLink →
airflow.providers.standard.operators.trigger_dagrun.TriggerDagRunLink
* airflow.operators.dagrun_operator.TriggerDagRunOperator →
airflow.providers.standard.operators.trigger_dagrun.TriggerDagRunOperator
* airflow.operators.python_operator.BranchPythonOperator →
airflow.providers.standard.operators.python.BranchPythonOperator
* airflow.operators.python_operator.PythonOperator →
airflow.providers.standard.operators.python.PythonOperator
* airflow.operators.python_operator.PythonVirtualenvOperator →
airflow.providers.standard.operators.python.PythonVirtualenvOperator
* airflow.operators.python_operator.ShortCircuitOperator →
airflow.providers.standard.operators.python.ShortCircuitOperator
* airflow.operators.latest_only_operator.LatestOnlyOperator →
airflow.providers.standard.operators.latest_only.LatestOnlyOperator
* airflow.sensors.date_time_sensor.DateTimeSensor →
airflow.providers.standard.sensors.DateTimeSensor
* airflow.operators.email_operator.EmailOperator →
airflow.providers.smtp.operators.smtp.EmailOperator
* airflow.operators.email.EmailOperator →
airflow.providers.smtp.operators.smtp.EmailOperator
* airflow.operators.bash.BashOperator →
airflow.providers.standard.operators.bash.BashOperator
* airflow.operators.EmptyOperator →
airflow.providers.standard.operators.empty.EmptyOperator

closes: https://github.com/astral-sh/ruff/issues/17103

## Test Plan

The test fixture has been updated and checked after each change and
later reorganized in the latest commit
2025-04-07 09:45:56 -04:00
Micha Reiser 6cc2d02dfa
[red-knot] Support stub packages (#17204)
## Summary

This PR adds support for stub packages, except for partial stub packages
(a stub package is always considered non-partial).

I read the specification at
[typing.python.org/en/latest/spec/distributing.html#stub-only-packages](https://typing.python.org/en/latest/spec/distributing.html#stub-only-packages)
but I found it lacking some details, especially on how to handle
namespace packages or when the regular and stub packages disagree on
whether they're namespace packages. I tried to document my decisions in
the mdtests where the specification isn't clear and compared the
behavior to Pyright.

Mypy seems to only support stub packages in the venv folder. At least,
it never picked up my stub packages otherwise. I decided not to spend
too much time fighting mypyp, which is why I focused the comparison
around Pyright

Closes https://github.com/astral-sh/ruff/issues/16612

## Test plan

Added mdtests
2025-04-07 14:40:50 +02:00
Andrew Gallant c12c76e9c8 ruff_annotate_snippets: address unused code warnings
Fixes #17230
2025-04-07 08:24:08 -04:00
Alex Waygood 81cf860dc8
[red-knot] Add a couple more tests for `*` imports (#17270)
## Summary

Some more edge cases that I thought of while working on integrating
knowledge of statically known branches into the `*`-import machinery

## Test Plan

`cargo test -p red_knot_python_semantic`
2025-04-07 11:12:28 +00:00
Micha Reiser 3150812ac4
[red-knot] Add 'Format document' to playground (#17217)
## Summary
This is more "because we can" than something we need. 

But since we're already building an "almost IDE" 

## Test Plan



https://github.com/user-attachments/assets/3a4bdad1-ba32-455a-9909-cfeb8caa1b28
2025-04-07 09:26:03 +02:00
Micha Reiser 67f8c30b53
[red-knot] Remove global `dead_code` from red-knot-server (#17229)
## Summary

Use more local `expect(dead_code)` suppressions instead of a global
`allow(dead_code)` in `lib.rs`.

Remove some methods that are either easy to add later, are less likely
to be needed for red knot, or it's unclear if we'd add it the same way
as in ruff.
2025-04-06 22:09:24 +01:00
Alex Waygood ac5d220d75
[red-knot] Fix `python` setting in mdtests, and rewrite a `site-packages` test as an mdtest (#17222)
## Summary

This PR does the following things:
- Fixes the `python` configuration setting for mdtest (added in
https://github.com/astral-sh/ruff/pull/17221) so that it expects a path
pointing to a venv's `sys.prefix` variable rather than the a path
pointing to the venv's `site-packages` subdirectory. This brings the
`python` setting in mdtest in sync with our CLI `--python` flag.
- Tweaks mdtest so that it automatically creates a valid `pyvenv.cfg`
file for you if you don't specify one. This makes it much more ergonomic
to write an mdtest with a custom `python` setting: red-knot will reject
a `python` setting that points to a directory that doesn't have a
`pyvenv.cfg` file in it
- Tweaks mdtest so that it doesn't check a custom `pyvenv.cfg` as Python
source code if you _do_ add a custom `pyvenv.cfg` file for your mock
virtual environment in an mdtest. (You get a lot of diagnostics about
Python syntax errors in the `pyvenv.cfg` file, otherwise!)
- Rewrites the test added in
https://github.com/astral-sh/ruff/pull/17178 as an mdtest, and deletes
the original test that was added in that PR

## Test Plan

I verified that the new mdtest fails if I revert the changes to
`resolver.rs` that were added in
https://github.com/astral-sh/ruff/pull/17178
2025-04-06 18:24:32 +01:00
Matthew Mckee 73a9974d8a
Fix `CallableTypeOf` display signature (#17235) 2025-04-06 18:12:52 +01:00
Micha Reiser 1c652e6b98
[red-knot] Allow setting `python` in mdtests (#17221)
## Summary

This PR extends the mdtest options to allow setting the
`environment.python` option.

## Test Plan

I let @AlexWaygood write a test and he'll tell me if it works 😆
2025-04-05 16:43:31 +02:00
cake-monotone 7e6d3838bd
[red-knot] Add cycle handling to narrow constraints queries (#17209)
## Summary

This PR fixes the cycle issue that was causing problems in the `support
super` PR.

### Affected queries
- `all_narrowing_constraints_for_expression`
- `all_negative_narrowing_constraints_for_expression`


--

Additionally, `bidict` and `werkzeug` have been added to the
project-selection list in `mypy_primer`.
This PR also addresses the panics that occurred while analyzing those
packages:

- `bidict`: panic triggered by
`all_narrowing_constraints_for_expression`
- `werkzeug`: panic triggered by
`all_negative_narrowing_constraints_for_expression`

I think the mypy-primer results for this PR can serve as sufficient test
:)
2025-04-04 22:26:20 -07:00
David Peter 1a6a10b30f
[red-knot] Empty tuple is always-falsy (#17213)
## Summary

Fix assignability of `tuple[()]` to `AlwaysFalsy`.

closes #17202 

## Test Plan

Ran the property tests for a while
2025-04-04 22:00:28 +02:00
Brent Westbrook 95d6ed40cc
Bump 0.11.4 (#17212) 2025-04-04 14:09:10 -04:00
Brent Westbrook acc5662e8b
[syntax-errors] Allow `yield` in base classes and annotations (#17206)
Summary
--

This PR fixes the issue pointed out by @JelleZijlstra in
https://github.com/astral-sh/ruff/pull/17101#issuecomment-2777480204.
Namely, I conflated two very different errors from CPython:

```pycon
>>> def m[T](x: (yield from 1)): ...
  File "<python-input-310>", line 1
    def m[T](x: (yield from 1)): ...
                 ^^^^^^^^^^^^
SyntaxError: yield expression cannot be used within the definition of a generic
>>> def m(x: (yield from 1)): ...
  File "<python-input-311>", line 1
    def m(x: (yield from 1)): ...
              ^^^^^^^^^^^^
SyntaxError: 'yield from' outside function
>>> def outer():
...     def m(x: (yield from 1)): ...
...
>>>
```

I thought the second error was the same as the first, but `yield` (and
`yield from`) is actually valid in this position when inside a function
scope. The same is true for base classes, as pointed out in the original
comment.

We don't currently raise an error for `yield` outside of a function, but
that should be handled separately.

On the upside, this had the benefit of removing the
`InvalidExpressionPosition::BaseClass` variant and the
`allow_named_expr` field from the visitor because they were both no
longer used.

Test Plan
--

Updated inline tests.
2025-04-04 13:48:28 -04:00
David Salvisberg 33a56f198b
Don't skip visiting non-tuple slice in `typing.Annotated` subscripts (#17201)
Fixes: #17196

## Summary

Skipping these nodes for malformed type expressions would lead to
incorrect semantic state, which can in turn mean we emit false positives
for rules like `unused-variable`(`F841`)

## Test Plan

`cargo nextest run`
2025-04-04 18:47:40 +05:30
Micha Reiser ffa824e037
[red-knot] Add `Type.definition` method (#17153)
## Summary

This is a follow up to the goto type definition PR. Specifically, that
we want to avoid exposing too many semantic model internals publicly.

I want to get some feedback on the approach taken. I think it goes into
the right direction but I'm not super happy with it.
The basic idea is that we add a `Type::definition` method which does the
"goto type definition". The parts that I think make it awkward:

* We can't directly return `Definition` because we don't create a
`Definition` for modules (but we could?). Although I think it makes
sense to possibly have a more public wrapper type anyway?
* It doesn't handle unions and intersections. Mainly because not all
elements in an intersection may have a definition and we only want to
show a navigation target for intersections if there's only a single
positive element (besides maybe `Unknown`).


An alternative design or an addition to this design is to introduce a
`SemanticAnalysis(Db)` struct that has methods like
`type_definition(&self, type)` which explicitly exposes the methods we
want. I don't feel comfortable design this API yet because it's unclear
how fine granular it has to be (and if it is very fine granular,
directly using `Type` might be better after all)


## Test Plan

`cargo test`
2025-04-04 10:56:20 +02:00
Max Mynter 98b95c9c38
Implement `Invalid rule provided` as rule RUF102 with `--fix` (#17138)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

Closes #17084

## Summary
This PR adds a new rule (RUF102) to detect and fix invalid rule codes in
`noqa` comments.
Invalid rule codes in `noqa` directives serve no purpose and may
indicate outdated code suppressions.

This extends the previous behaviour originating from
`crates/ruff_linter/src/noqa.rs` which would only emit a warnigs.
With this rule a `--fix` is available.

The rule:
1. Analyzes all `noqa` directives to identify invalid rule codes
2. Provides autofix functionality to:
   - Remove the entire comment if all codes are invalid
   - Remove only the invalid codes when mixed with valid codes
3. Preserves original comment formatting and whitespace where possible

Example cases:
- `# noqa: XYZ111` → Remove entire comment (keep empty line)
- `# noqa: XYZ222, XYZ333` → Remove entire comment (keep empty line)
-  `# noqa: F401, INVALID123` → Keep only valid codes (`# noqa: F401`)

## Test Plan
- Added tests in
`crates/ruff_linter/resources/test/fixtures/ruff/RUF102.py` covering
different example cases.

<!-- How was it tested? -->

## Notes 
- This does not handle cases where parsing fails. E.g. `# noqa:
NON_EXISTENT, ANOTHER_INVALID` causes a `LexicalError` and the
diagnostic is not propagated and we cannot handle the diagnostic. I am
also unsure what proper `fix` handling would be and making the user
aware we don't understand the codes is probably the best bet.
- The rule is added to the Preview rule group as it's a new addition

## Questions
- Should we remove the warnings, now that we have a rule?
- Is the current fix behavior appropriate for all cases, particularly
the handling of whitespace and line deletions?
- I'm new to the codebase; let me know if there are rule utilities which
could have used but didn't.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2025-04-04 08:05:59 +00:00
Micha Reiser a4ba10ff0a
[red-knot] Add basic on-hover to playground and LSP (#17057)
## Summary

Implement a very basic hover in the playground and LSP.

It's basic, because it only shows the type on-hover. Most other LSPs
also show:

* The signature of the symbol beneath the cursor. E.g. `class
Test(a:int, b:int)` (we want something like
54f7da25f9/packages/pyright-internal/src/analyzer/typeEvaluator.ts (L21929-L22129))
* The symbols' documentation
* Do more fancy markdown rendering

I decided to defer these features for now because it requires new
semantic APIs (similar to *goto definition*), and investing in fancy
rendering only makes sense once we have the relevant data.

Closes [#16826](https://github.com/astral-sh/ruff/issues/16826)

## Test Plan



https://github.com/user-attachments/assets/044aeee4-58ad-4d4e-9e26-ac2a712026be


https://github.com/user-attachments/assets/4a1f4004-2982-4cf2-9dfd-cb8b84ff2ecb
2025-04-04 08:13:43 +02:00
Carl Meyer bf0306887a
[red-knot] don't remove negations when simplifying constrained typevars (#17189)
For two non-disjoint types `P` and `Q`, the simplification of `(P | Q) &
~Q` is not `P`, but `P & ~Q`. In other words, the non-empty set `P & Q`
is also excluded from the type.

The same applies for a constrained typevar `[T: (P, Q)]`: `T & ~Q`
should simplify to `P & ~Q`, not just `P`.

Implementing this is actually purely a matter of removing code from the
constrained typevar simplification logic; we just need to not bother
removing the negations. If the negations are actually redundant (because
the constraint types are disjoint), normal intersection simplification
will already eliminate them (as shown in the added test.)
2025-04-03 16:30:57 -07:00
Brent Westbrook 4f924bb975
[minor] Fix extra semicolon for clippy (#17188) 2025-04-03 18:17:00 -04:00
Brent Westbrook c2b2e42ad3
[syntax-errors] Invalid syntax in annotations (#17101)
Summary
--

This PR detects the use of invalid syntax in annotation scopes,
including
`yield` and `yield from` expressions and named expressions. I combined a
few
different types of CPython errors here, but I think the resulting error
messages
still make sense and are even preferable to what CPython gives. For
example, we
report `yield expression cannot be used in a type annotation` for both
of these:

```pycon
>>> def f[T](x: (yield 1)): ...
  File "<python-input-26>", line 1
    def f[T](x: (yield 1)): ...
                 ^^^^^^^
SyntaxError: yield expression cannot be used within the definition of a generic
>>> def foo() -> (yield x): ...
  File "<python-input-28>", line 1
    def foo() -> (yield x): ...
                  ^^^^^^^
SyntaxError: 'yield' outside function
```

Fixes https://github.com/astral-sh/ruff/issues/11118.

Test Plan
--

New inline tests, along with some updates to existing tests.
2025-04-03 17:56:55 -04:00
Brent Westbrook 24b1b1d52c
[syntax-errors] Duplicate attributes in match class pattern (#17186)
Summary
--

Detects duplicate attributes in a `match` class pattern:

```python
match x:
    case Class(x=1, x=2): ...
```

which are more analogous to the similar check for mapping patterns than
to the
multiple assignments rule.

I also realized that both this and the mapping check would only work on
top-level patterns, despite the possibility that they can be nested
inside other
patterns:

```python
match x:
    case [{"x": 1, "x": 2}]: ...  # false negative in the old version
```

and moved these checks into the recursive pattern visitor instead.

I also tidied up some of the names like the `multiple_case_assignment`
function
and the `MultipleCaseAssignmentVisitor`, which are now doing more than
checking
for multiple assignments.

Test Plan
--

New inline tests for both classes and mappings.
2025-04-03 17:55:37 -04:00
Brent Westbrook 6a07dd227d
[syntax-errors] Fix multiple assignment for class keyword argument (#17184)
Summary
--

Fixes #17181. The cases being tested with multiple *keys* being equal
are actually a slightly different error, more like the error for
`MatchMapping` than like the other multiple assignment errors:

```pycon
>>> match x:
...     case Class(x=x, x=x): ...
...
  File "<python-input-249>", line 2
    case Class(x=x, x=x): ...
                      ^
SyntaxError: attribute name repeated in class pattern: x
>>> match x:
...     case {"x": 1, "x": 2}: ...
...
  File "<python-input-251>", line 2
    case {"x": 1, "x": 2}: ...
         ^^^^^^^^^^^^^^^^
SyntaxError: mapping pattern checks duplicate key ('x')
>>> match x:
...     case [x, x]: ...
...
  File "<python-input-252>", line 2
    case [x, x]: ...
             ^
SyntaxError: multiple assignments to name 'x' in pattern
```

This PR just stops the false positive reported in the issue, but I will
quickly follow it up with a new rule (or possibly combined with the
mapping rule) catching the repeated attributes separately.

Test Plan
--

New inline `test_ok` and updating the `test_err` cases to have duplicate
values instead of keys.
2025-04-03 17:32:39 -04:00
Micha Reiser e7684d3493
Enable overindented docs lint (#17182)
## Summary

It turns out that `a.` isn't a list format supported by rustdoc. I
changed the documentation to use `1.`, `2.` instead.

## Test Plan

`cargo clippy`
2025-04-03 20:27:11 +01:00
Douglas Creager 64e7e1aa64
[red-knot] Add `Type::TypeVar` variant (#17102)
This adds a new `Type` variant for holding an instance of a typevar
inside of a generic function or class. We don't handle specializing the
typevars yet, but this should implement most of the typing rules for
inside the generic function/class, where we don't know yet which
specific type the typevar will be specialized to.

This PR does _not_ yet handle the constraint that multiple occurrences
of the typevar must be specialized to the _same_ time. (There is an
existing test case for this in `generics/functions.md` which is still
marked as TODO.)

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Carl Meyer <carl@astral.sh>
2025-04-03 14:36:29 -04:00
Micha Reiser 8a4158c5f8
Upgrade to Rust 1.86 and bump MSRV to 1.84 (#17171)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

I decided to disable the new
[`needless_continue`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue)
rule because I often found the explicit `continue` more readable over an
empty block or having to invert the condition of an other branch.


## Test Plan

`cargo test`

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-04-03 15:59:44 +00:00
David Peter fedd982fd5
[red-knot] Avoid unresolved-reference in unreachable code (#17169)
## Summary

This PR changes the inferred type for symbols in unreachable sections of
code to `Never` (instead of reporting them as unbound), in order to
silence false positive diagnostics. See the lengthy comment in the code
for further details.

## Test Plan

- Updated Markdown tests.
- Manually verified a couple of ecosystem diagnostic changes.
2025-04-03 16:52:11 +02:00
Alex Waygood a1eb834a5f
Fix relative import resolution in `site-packages` packages when the `site-packages` search path is a subdirectory of the first-party search path (#17178)
## Summary

If a package in `site-packages` had this directory structure:

```py
# bar/__init__.py
from .a import A

# bar/a.py
class A: ...
```

then we would fail to resolve the `from .a import A` import _if_ (as is
usually the case!) the `site-packages` search path was located inside a
`.venv` directory that was a subdirectory of the project's first-party
search path. The reason for this is a bug in `file_to_module` in the
module resolver. In this loop, we would identify that
`/project_root/.venv/lib/python3.13/site-packages/foo/__init__.py` can
be turned into a path relative to the first-party search path
(`/project_root`):


6e2b8f9696/crates/red_knot_python_semantic/src/module_resolver/resolver.rs (L101-L110)

but we'd then try to turn the relative path
(.venv/lib/python3.13/site-packages/foo/__init__.py`) into a module
path, realise that it wasn't a valid module path... and therefore
immediately `break` out of the loop before trying any other search paths
(such as the `site-packages` search path).

This bug was originally reported on Discord by @MatthewMckee4.

## Test Plan

I added a unit test for `file_to_module` in `resolver.rs`, and an
integration test that shows we can now resolve the import correctly in
`infer.rs`.
2025-04-03 15:48:05 +01:00
Brent Westbrook 6e2b8f9696
[syntax-errors] Detect duplicate keys in `match` mapping patterns (#17129)
Summary
--

Detects duplicate literals in `match` mapping keys.

This PR also adds a `source` method to `SemanticSyntaxContext` to
display the duplicated key in the error message by slicing out its
range.

Test Plan
--

New inline tests.
2025-04-03 10:22:37 -04:00
Alex Waygood ca0cce3f9c
[red-knot] Fix more [redundant-cast] false positives (#17170)
Fixes #17164. Simply checking whether one type is gradually equivalent
to another is too simplistic here: `Any` is gradually equivalent to
`Todo`, but we should permit users to cast from `Todo` or `Unknown` to
`Any` without complaining about it. This changes our logic so that we
only complain about redundant casts if:
- the two types are exactly equal (when normalized) OR they are
equivalent (we'll still complain about `Any -> Any` casts, and about
`Any | str | int` -> `str | int | Any` casts, since their normalized
forms are exactly equal, even though the type is not fully static -- and
therefore does not participate in equivalence relations)
- AND the casted type does not contain `Todo`
2025-04-03 15:00:00 +01:00
David Peter 3f00010a7a
[red-knot] Three-argument type-calls take 'str' as the first argument (#17168)
## Summary

Similar to #17163, a minor fix in the signature of `type(…)`.

## Test Plan

New MD tests
2025-04-03 15:45:08 +02:00
Dylan d401a5440e
Control flow: `return` and `raise` (#17121)
We add support for `return` and `raise` statements in the control flow
graph: we simply add an edge to the terminal block, push the statements
to the current block, and proceed.

This implementation will have to be modified somewhat once we add
support for `try` statements - then we will need to check whether to
_defer_ the jump. But for now this will do!

Also in this PR: We fix the `unreachable` diagnostic range so that it
lumps together consecutive unreachable blocks.
2025-04-03 08:30:29 -05:00
Brent Westbrook 755ece0c36
Bump 0.11.3 (#17173) 2025-04-03 09:05:40 -04:00