Skip to content

Commit 2f85749

Browse files
authored
type: ignore[codes] and knot: ignore (#15078)
1 parent 9eb73cb commit 2f85749

File tree

13 files changed

+736
-47
lines changed

13 files changed

+736
-47
lines changed

Cargo.lock

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

crates/red_knot_python_semantic/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ ruff_python_stdlib = { workspace = true }
2020
ruff_source_file = { workspace = true }
2121
ruff_text_size = { workspace = true }
2222
ruff_python_literal = { workspace = true }
23+
ruff_python_trivia = { workspace = true }
2324

2425
anyhow = { workspace = true }
2526
bitflags = { workspace = true }
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Suppressing errors with `knot: ignore`
2+
3+
Type check errors can be suppressed by a `knot: ignore` comment on the same line as the violation.
4+
5+
## Simple `knot: ignore`
6+
7+
```py
8+
a = 4 + test # knot: ignore
9+
```
10+
11+
## Suppressing a specific code
12+
13+
```py
14+
a = 4 + test # knot: ignore[unresolved-reference]
15+
```
16+
17+
## Useless suppression
18+
19+
TODO: Red Knot should emit an `unused-suppression` diagnostic for the
20+
`possibly-unresolved-reference` suppression.
21+
22+
```py
23+
test = 10
24+
a = test + 3 # knot: ignore[possibly-unresolved-reference]
25+
```
26+
27+
## Useless suppression if the error codes don't match
28+
29+
TODO: Red Knot should emit a `unused-suppression` diagnostic for the `possibly-unresolved-reference`
30+
suppression because it doesn't match the actual `unresolved-reference` diagnostic.
31+
32+
```py
33+
# error: [unresolved-reference]
34+
a = test + 3 # knot: ignore[possibly-unresolved-reference]
35+
```
36+
37+
## Multiple suppressions
38+
39+
```py
40+
# fmt: off
41+
def test(a: f"f-string type annotation", b: b"byte-string-type-annotation"): ... # knot: ignore[fstring-type-annotation, byte-string-type-annotation]
42+
```
43+
44+
## Can't suppress syntax errors
45+
46+
<!-- blacken-docs:off -->
47+
48+
```py
49+
# error: [invalid-syntax]
50+
def test( # knot: ignore
51+
```
52+
53+
<!-- blacken-docs:on -->
54+
55+
## Can't suppress `revealed-type` diagnostics
56+
57+
```py
58+
a = 10
59+
# revealed: Literal[10]
60+
reveal_type(a) # knot: ignore
61+
```
62+
63+
## Extra whitespace in type ignore comments is allowed
64+
65+
```py
66+
a = 10 / 0 # knot : ignore
67+
a = 10 / 0 # knot: ignore [ division-by-zero ]
68+
```
69+
70+
## Whitespace is optional
71+
72+
```py
73+
# fmt: off
74+
a = 10 / 0 #knot:ignore[division-by-zero]
75+
```
76+
77+
## Trailing codes comma
78+
79+
Trailing commas in the codes section are allowed:
80+
81+
```py
82+
a = 10 / 0 # knot: ignore[division-by-zero,]
83+
```
84+
85+
## Invalid characters in codes
86+
87+
```py
88+
# error: [division-by-zero]
89+
a = 10 / 0 # knot: ignore[*-*]
90+
```
91+
92+
## Trailing whitespace
93+
94+
<!-- blacken-docs:off -->
95+
96+
```py
97+
a = 10 / 0 # knot: ignore[division-by-zero]
98+
# ^^^^^^ trailing whitespace
99+
```
100+
101+
<!-- blacken-docs:on -->
102+
103+
## Missing comma
104+
105+
A missing comma results in an invalid suppression comment. We may want to recover from this in the
106+
future.
107+
108+
```py
109+
# error: [unresolved-reference]
110+
a = x / 0 # knot: ignore[division-by-zero unresolved-reference]
111+
```
112+
113+
## Empty codes
114+
115+
An empty codes array suppresses no-diagnostics and is always useless
116+
117+
```py
118+
# error: [division-by-zero]
119+
a = 4 / 0 # knot: ignore[]
120+
```

crates/red_knot_python_semantic/resources/mdtest/suppressions/type-ignore.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,8 @@ a = test # type: ignore[name-defined]
9595

9696
## Nested comments
9797

98-
TODO: We should support this for better interopability with other suppression comments.
99-
10098
```py
10199
# fmt: off
102-
# TODO this error should be suppressed
103-
# error: [unresolved-reference]
104100
a = test \
105101
+ 2 # fmt: skip # type: ignore
106102

crates/red_knot_python_semantic/src/db.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::lint::RuleSelection;
1+
use crate::lint::{LintRegistry, RuleSelection};
22
use ruff_db::files::File;
33
use ruff_db::{Db as SourceDb, Upcast};
44

@@ -8,6 +8,8 @@ pub trait Db: SourceDb + Upcast<dyn SourceDb> {
88
fn is_file_open(&self, file: File) -> bool;
99

1010
fn rule_selection(&self) -> &RuleSelection;
11+
12+
fn lint_registry(&self) -> &LintRegistry;
1113
}
1214

1315
#[cfg(test)]
@@ -19,7 +21,7 @@ pub(crate) mod tests {
1921
use crate::{default_lint_registry, ProgramSettings, PythonPlatform};
2022

2123
use super::Db;
22-
use crate::lint::RuleSelection;
24+
use crate::lint::{LintRegistry, RuleSelection};
2325
use anyhow::Context;
2426
use ruff_db::files::{File, Files};
2527
use ruff_db::system::{DbWithTestSystem, System, SystemPathBuf, TestSystem};
@@ -45,7 +47,7 @@ pub(crate) mod tests {
4547
vendored: red_knot_vendored::file_system().clone(),
4648
events: Arc::default(),
4749
files: Files::default(),
48-
rule_selection: Arc::new(RuleSelection::from_registry(&default_lint_registry())),
50+
rule_selection: Arc::new(RuleSelection::from_registry(default_lint_registry())),
4951
}
5052
}
5153

@@ -112,6 +114,10 @@ pub(crate) mod tests {
112114
fn rule_selection(&self) -> &RuleSelection {
113115
&self.rule_selection
114116
}
117+
118+
fn lint_registry(&self) -> &LintRegistry {
119+
default_lint_registry()
120+
}
115121
}
116122

117123
#[salsa::db]

crates/red_knot_python_semantic/src/lib.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,15 @@ mod visibility_constraints;
3333

3434
type FxOrderSet<V> = ordermap::set::OrderSet<V, BuildHasherDefault<FxHasher>>;
3535

36-
/// Creates a new registry with all known semantic lints.
37-
pub fn default_lint_registry() -> LintRegistry {
38-
let mut registry = LintRegistryBuilder::default();
39-
register_lints(&mut registry);
40-
registry.build()
36+
/// Returns the default registry with all known semantic lints.
37+
pub fn default_lint_registry() -> &'static LintRegistry {
38+
static REGISTRY: std::sync::LazyLock<LintRegistry> = std::sync::LazyLock::new(|| {
39+
let mut registry = LintRegistryBuilder::default();
40+
register_lints(&mut registry);
41+
registry.build()
42+
});
43+
44+
&REGISTRY
4145
}
4246

4347
/// Register all known semantic lints.

crates/red_knot_python_semantic/src/lint.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ impl LintRegistryBuilder {
321321
}
322322
}
323323

324-
#[derive(Default, Debug)]
324+
#[derive(Default, Debug, Clone)]
325325
pub struct LintRegistry {
326326
lints: Vec<LintId>,
327327
by_name: FxHashMap<&'static str, LintEntry>,
@@ -385,7 +385,7 @@ pub enum GetLintError {
385385
Unknown(String),
386386
}
387387

388-
#[derive(Debug, PartialEq, Eq)]
388+
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
389389
pub enum LintEntry {
390390
/// An existing lint rule. Can be in preview, stable or deprecated.
391391
Lint(LintId),

0 commit comments

Comments
 (0)