Skip to content

Commit 9430014

Browse files
committed
Merge branch 'main' into dcreager/legacy-class
* main: [red-knot] Use 'full' salsa backtrace output that includes durability and revisions (#17735) [red-knot] Initial support for protocol types (#17682) [red-knot] Computing a type ordering for two non-normalized types is meaningless (#17734) [red-knot] Include salsa backtrace in check and mdtest panic messages (#17732) [red-knot] Fix control flow for `assert` statements (#17702) [red-knot] Fix recording of negative visibility constraints (#17731) [red-knot] Update salsa (#17730) [red-knot] Support overloads for callable equivalence (#17698) [red-knot] Run py-fuzzer in CI to check for new panics (#17719) Upload red-knot binaries in CI on completion of linux tests (#17720) [`flake8-use-pathlib`] Fix `PTH123` false positive when `open` is passed a file descriptor from a function call (#17705)
2 parents f59488e + 0861ecf commit 9430014

File tree

31 files changed

+1286
-391
lines changed

31 files changed

+1286
-391
lines changed

.github/workflows/ci.yaml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,10 @@ jobs:
276276
with:
277277
name: ruff
278278
path: target/debug/ruff
279+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
280+
with:
281+
name: red_knot
282+
path: target/debug/red_knot
279283

280284
cargo-test-linux-release:
281285
name: "cargo test (linux, release)"
@@ -632,6 +636,53 @@ jobs:
632636
name: ecosystem-result
633637
path: ecosystem-result
634638

639+
fuzz-redknot:
640+
name: "Fuzz for new red-knot panics"
641+
runs-on: depot-ubuntu-22.04-16
642+
needs:
643+
- cargo-test-linux
644+
- determine_changes
645+
# Only runs on pull requests, since that is the only we way we can find the base version for comparison.
646+
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && github.event_name == 'pull_request' && needs.determine_changes.outputs.red_knot == 'true' }}
647+
timeout-minutes: 20
648+
steps:
649+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
650+
with:
651+
persist-credentials: false
652+
- uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
653+
name: Download new red-knot binary
654+
id: redknot-new
655+
with:
656+
name: red_knot
657+
path: target/debug
658+
- uses: dawidd6/action-download-artifact@20319c5641d495c8a52e688b7dc5fada6c3a9fbc # v8
659+
name: Download baseline red-knot binary
660+
with:
661+
name: red_knot
662+
branch: ${{ github.event.pull_request.base.ref }}
663+
workflow: "ci.yaml"
664+
check_artifacts: true
665+
- uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
666+
- name: Fuzz
667+
env:
668+
FORCE_COLOR: 1
669+
NEW_REDKNOT: ${{ steps.redknot-new.outputs.download-path }}
670+
run: |
671+
# Make executable, since artifact download doesn't preserve this
672+
chmod +x "${PWD}/red_knot" "${NEW_REDKNOT}/red_knot"
673+
674+
(
675+
uvx \
676+
--python="${PYTHON_VERSION}" \
677+
--from=./python/py-fuzzer \
678+
fuzz \
679+
--test-executable="${NEW_REDKNOT}/red_knot" \
680+
--baseline-executable="${PWD}/red_knot" \
681+
--only-new-bugs \
682+
--bin=red_knot \
683+
0-500
684+
)
685+
635686
cargo-shear:
636687
name: "cargo shear"
637688
runs-on: ubuntu-latest

Cargo.lock

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ rayon = { version = "1.10.0" }
124124
regex = { version = "1.10.2" }
125125
rustc-hash = { version = "2.0.0" }
126126
# When updating salsa, make sure to also update the revision in `fuzz/Cargo.toml`
127-
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "c75b0161aba55965ab6ad8cc9aaee7dc177967f1" }
127+
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "79afd59ed5a5edb4dac63cf5b6cf4a6aa9514bdf" }
128128
schemars = { version = "0.8.16" }
129129
seahash = { version = "4.1.0" }
130130
serde = { version = "1.0.197", features = ["derive"] }

crates/red_knot_project/src/lib.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use ruff_db::system::{SystemPath, SystemPathBuf};
2020
use rustc_hash::FxHashSet;
2121
use salsa::Durability;
2222
use salsa::Setter;
23+
use std::backtrace::BacktraceStatus;
2324
use std::panic::{AssertUnwindSafe, UnwindSafe};
2425
use std::sync::Arc;
2526
use thiserror::Error;
@@ -626,10 +627,27 @@ where
626627
));
627628

628629
if let Some(backtrace) = error.backtrace {
629-
diagnostic.sub(SubDiagnostic::new(
630-
Severity::Info,
631-
format!("Backtrace:\n{backtrace}"),
632-
));
630+
match backtrace.status() {
631+
BacktraceStatus::Disabled => {
632+
diagnostic.sub(SubDiagnostic::new(
633+
Severity::Info,
634+
"run with `RUST_BACKTRACE=1` environment variable to show the full backtrace information",
635+
));
636+
}
637+
BacktraceStatus::Captured => {
638+
diagnostic.sub(SubDiagnostic::new(
639+
Severity::Info,
640+
format!("Backtrace:\n{backtrace}"),
641+
));
642+
}
643+
_ => {}
644+
}
645+
}
646+
647+
if let Some(backtrace) = error.salsa_backtrace {
648+
salsa::attach(db, || {
649+
diagnostic.sub(SubDiagnostic::new(Severity::Info, backtrace.to_string()));
650+
});
633651
}
634652

635653
Err(diagnostic)

crates/red_knot_python_semantic/resources/mdtest/import/builtins.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ Builtin symbols can be explicitly imported:
77
```py
88
import builtins
99

10-
reveal_type(builtins.chr) # revealed: def chr(i: int | SupportsIndex, /) -> str
10+
reveal_type(builtins.chr) # revealed: def chr(i: SupportsIndex, /) -> str
1111
```
1212

1313
## Implicit use of builtin
1414

1515
Or used implicitly:
1616

1717
```py
18-
reveal_type(chr) # revealed: def chr(i: int | SupportsIndex, /) -> str
18+
reveal_type(chr) # revealed: def chr(i: SupportsIndex, /) -> str
1919
reveal_type(str) # revealed: Literal[str]
2020
```
2121

crates/red_knot_python_semantic/resources/mdtest/narrow/assert.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,64 @@ def _(x: Literal[1, 2, 3], y: Literal[1, 2, 3]):
5151
assert y not in (1, 2)
5252
reveal_type(y) # revealed: Literal[3]
5353
```
54+
55+
## Assertions with messages
56+
57+
```py
58+
def _(x: int | None, y: int | None):
59+
reveal_type(x) # revealed: int | None
60+
assert x is None, reveal_type(x) # revealed: int
61+
reveal_type(x) # revealed: None
62+
63+
reveal_type(y) # revealed: int | None
64+
assert isinstance(y, int), reveal_type(y) # revealed: None
65+
reveal_type(y) # revealed: int
66+
```
67+
68+
## Assertions with definitions inside the message
69+
70+
```py
71+
def one(x: int | None):
72+
assert x is None, (y := x * 42) * reveal_type(y) # revealed: int
73+
74+
# error: [unresolved-reference]
75+
reveal_type(y) # revealed: Unknown
76+
77+
def two(x: int | None, y: int | None):
78+
assert x is None, (y := 42) * reveal_type(y) # revealed: Literal[42]
79+
reveal_type(y) # revealed: int | None
80+
```
81+
82+
## Assertions with `test` predicates that are statically known to always be `True`
83+
84+
```py
85+
assert True, (x := 1)
86+
87+
# error: [unresolved-reference]
88+
reveal_type(x) # revealed: Unknown
89+
90+
assert False, (y := 1)
91+
92+
# The `assert` statement is terminal if `test` resolves to `False`,
93+
# so even though we know the `msg` branch will have been taken here
94+
# (we know what the truthiness of `False is!), we also know that the
95+
# `y` definition is not visible from this point in control flow
96+
# (because this point in control flow is unreachable).
97+
# We make sure that this does not emit an `[unresolved-reference]`
98+
# diagnostic by adding a reachability constraint,
99+
# but the inferred type is `Unknown`.
100+
#
101+
reveal_type(y) # revealed: Unknown
102+
```
103+
104+
## Assertions with messages that reference definitions from the `test`
105+
106+
```py
107+
def one(x: int | None):
108+
assert (y := x), reveal_type(y) # revealed: (int & ~AlwaysTruthy) | None
109+
reveal_type(y) # revealed: int & ~AlwaysFalsy
110+
111+
def two(x: int | None):
112+
assert isinstance((y := x), int), reveal_type(y) # revealed: None
113+
reveal_type(y) # revealed: int
114+
```

0 commit comments

Comments
 (0)