red_knot_python_semantic: migrate types to new diagnostics

This commit is contained in:
Andrew Gallant 2025-04-22 10:50:00 -04:00 committed by Andrew Gallant
parent c12640fea8
commit 17f799424a
25 changed files with 144 additions and 151 deletions

View file

@ -28,12 +28,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable` is not iterable because it has no `__iter__` method and its `__getitem__` method has an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`)
--> /src/mdtest_snippet.py:10:10
|
9 | # error: [not-iterable]
10 | for x in Iterable():
| ^^^^^^^^^^ Object of type `Iterable` is not iterable because it has no `__iter__` method and its `__getitem__` method has an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`)
| ^^^^^^^^^^
11 | reveal_type(x) # revealed: int
|

View file

@ -20,12 +20,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Literal[123]` is not iterable because it doesn't have an `__iter__` method or a `__getitem__` method
--> /src/mdtest_snippet.py:2:10
|
1 | nonsense = 123
2 | for x in nonsense: # error: [not-iterable]
| ^^^^^^^^ Object of type `Literal[123]` is not iterable because it doesn't have an `__iter__` method or a `__getitem__` method
| ^^^^^^^^
3 | pass
|

View file

@ -24,13 +24,13 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `NotIterable` is not iterable because its `__iter__` attribute has type `None`, which is not callable
--> /src/mdtest_snippet.py:6:10
|
4 | __iter__: None = None
5 |
6 | for x in NotIterable(): # error: [not-iterable]
| ^^^^^^^^^^^^^ Object of type `NotIterable` is not iterable because its `__iter__` attribute has type `None`, which is not callable
| ^^^^^^^^^^^^^
7 | pass
|

View file

@ -25,12 +25,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Bad` is not iterable because it has no `__iter__` method and its `__getitem__` attribute has type `None`, which is not callable
--> /src/mdtest_snippet.py:7:10
|
6 | # error: [not-iterable]
7 | for x in Bad():
| ^^^^^ Object of type `Bad` is not iterable because it has no `__iter__` method and its `__getitem__` attribute has type `None`, which is not callable
| ^^^^^
8 | reveal_type(x) # revealed: Unknown
|

View file

@ -46,12 +46,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable1` may not be iterable because it has no `__iter__` method and its `__getitem__` attribute (with type `CustomCallable`) may not be callable
--> /src/mdtest_snippet.py:22:14
|
21 | # error: [not-iterable]
22 | for x in Iterable1():
| ^^^^^^^^^^^ Object of type `Iterable1` may not be iterable because it has no `__iter__` method and its `__getitem__` attribute (with type `CustomCallable`) may not be callable
| ^^^^^^^^^^^
23 | # TODO... `int` might be ideal here?
24 | reveal_type(x) # revealed: int | Unknown
|
@ -73,12 +73,12 @@ info: revealed-type: Revealed type
```
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable2` may not be iterable because it has no `__iter__` method and its `__getitem__` attribute (with type `(bound method Iterable2.__getitem__(key: int) -> int) | None`) may not be callable
--> /src/mdtest_snippet.py:27:14
|
26 | # error: [not-iterable]
27 | for y in Iterable2():
| ^^^^^^^^^^^ Object of type `Iterable2` may not be iterable because it has no `__iter__` method and its `__getitem__` attribute (with type `(bound method Iterable2.__getitem__(key: int) -> int) | None`) may not be callable
| ^^^^^^^^^^^
28 | # TODO... `int` might be ideal here?
29 | reveal_type(y) # revealed: int | Unknown
|

View file

@ -43,12 +43,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable1` may not be iterable because it has no `__iter__` method and its `__getitem__` attribute (with type `(bound method Iterable1.__getitem__(item: int) -> str) | None`) may not be callable
--> /src/mdtest_snippet.py:20:14
|
19 | # error: [not-iterable]
20 | for x in Iterable1():
| ^^^^^^^^^^^ Object of type `Iterable1` may not be iterable because it has no `__iter__` method and its `__getitem__` attribute (with type `(bound method Iterable1.__getitem__(item: int) -> str) | None`) may not be callable
| ^^^^^^^^^^^
21 | # TODO: `str` might be better
22 | reveal_type(x) # revealed: str | Unknown
|
@ -70,12 +70,12 @@ info: revealed-type: Revealed type
```
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable2` may not be iterable because it has no `__iter__` method and its `__getitem__` method (with type `(bound method Iterable2.__getitem__(item: int) -> str) | (bound method Iterable2.__getitem__(item: str) -> int)`) may have an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`)
--> /src/mdtest_snippet.py:25:14
|
24 | # error: [not-iterable]
25 | for y in Iterable2():
| ^^^^^^^^^^^ Object of type `Iterable2` may not be iterable because it has no `__iter__` method and its `__getitem__` method (with type `(bound method Iterable2.__getitem__(item: int) -> str) | (bound method Iterable2.__getitem__(item: str) -> int)`) may have an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`)
| ^^^^^^^^^^^
26 | reveal_type(y) # revealed: str | int
|

View file

@ -47,12 +47,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable1` may not be iterable because its `__iter__` method (with type `(bound method Iterable1.__iter__() -> Iterator) | (bound method Iterable1.__iter__(invalid_extra_arg) -> Iterator)`) may have an invalid signature (expected `def __iter__(self): ...`)
--> /src/mdtest_snippet.py:17:14
|
16 | # error: [not-iterable]
17 | for x in Iterable1():
| ^^^^^^^^^^^ Object of type `Iterable1` may not be iterable because its `__iter__` method (with type `(bound method Iterable1.__iter__() -> Iterator) | (bound method Iterable1.__iter__(invalid_extra_arg) -> Iterator)`) may have an invalid signature (expected `def __iter__(self): ...`)
| ^^^^^^^^^^^
18 | reveal_type(x) # revealed: int
|
@ -73,12 +73,12 @@ info: revealed-type: Revealed type
```
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable2` may not be iterable because its `__iter__` attribute (with type `(bound method Iterable2.__iter__() -> Iterator) | None`) may not be callable
--> /src/mdtest_snippet.py:28:14
|
27 | # error: [not-iterable]
28 | for x in Iterable2():
| ^^^^^^^^^^^ Object of type `Iterable2` may not be iterable because its `__iter__` attribute (with type `(bound method Iterable2.__iter__() -> Iterator) | None`) may not be callable
| ^^^^^^^^^^^
29 | # TODO: `int` would probably be better here:
30 | reveal_type(x) # revealed: int | Unknown
|

View file

@ -51,12 +51,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable1` may not be iterable because its `__iter__` method returns an object of type `Iterator1`, which may have an invalid `__next__` method (expected `def __next__(self): ...`)
--> /src/mdtest_snippet.py:28:14
|
27 | # error: [not-iterable]
28 | for x in Iterable1():
| ^^^^^^^^^^^ Object of type `Iterable1` may not be iterable because its `__iter__` method returns an object of type `Iterator1`, which may have an invalid `__next__` method (expected `def __next__(self): ...`)
| ^^^^^^^^^^^
29 | reveal_type(x) # revealed: int | str
|
@ -77,12 +77,12 @@ info: revealed-type: Revealed type
```
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable2` may not be iterable because its `__iter__` method returns an object of type `Iterator2`, which has a `__next__` attribute that may not be callable
--> /src/mdtest_snippet.py:32:14
|
31 | # error: [not-iterable]
32 | for y in Iterable2():
| ^^^^^^^^^^^ Object of type `Iterable2` may not be iterable because its `__iter__` method returns an object of type `Iterator2`, which has a `__next__` attribute that may not be callable
| ^^^^^^^^^^^
33 | # TODO: `int` would probably be better here:
34 | reveal_type(y) # revealed: int | Unknown
|

View file

@ -36,12 +36,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable` may not be iterable because it may not have an `__iter__` method and its `__getitem__` method has an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`)
--> /src/mdtest_snippet.py:18:14
|
17 | # error: [not-iterable]
18 | for x in Iterable():
| ^^^^^^^^^^ Object of type `Iterable` may not be iterable because it may not have an `__iter__` method and its `__getitem__` method has an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`)
| ^^^^^^^^^^
19 | reveal_type(x) # revealed: int | bytes
|

View file

@ -54,12 +54,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable1` may not be iterable because it may not have an `__iter__` method and its `__getitem__` attribute (with type `(bound method Iterable1.__getitem__(item: int) -> str) | None`) may not be callable
--> /src/mdtest_snippet.py:31:14
|
30 | # error: [not-iterable]
31 | for x in Iterable1():
| ^^^^^^^^^^^ Object of type `Iterable1` may not be iterable because it may not have an `__iter__` method and its `__getitem__` attribute (with type `(bound method Iterable1.__getitem__(item: int) -> str) | None`) may not be callable
| ^^^^^^^^^^^
32 | # TODO: `bytes | str` might be better
33 | reveal_type(x) # revealed: bytes | str | Unknown
|
@ -81,12 +81,12 @@ info: revealed-type: Revealed type
```
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable2` may not be iterable because it may not have an `__iter__` method and its `__getitem__` method (with type `(bound method Iterable2.__getitem__(item: int) -> str) | (bound method Iterable2.__getitem__(item: str) -> int)`) may have an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`)
--> /src/mdtest_snippet.py:36:14
|
35 | # error: [not-iterable]
36 | for y in Iterable2():
| ^^^^^^^^^^^ Object of type `Iterable2` may not be iterable because it may not have an `__iter__` method and its `__getitem__` method (with type `(bound method Iterable2.__getitem__(item: int) -> str) | (bound method Iterable2.__getitem__(item: str) -> int)`) may have an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`)
| ^^^^^^^^^^^
37 | reveal_type(y) # revealed: bytes | str | int
|

View file

@ -35,12 +35,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable` may not be iterable because it may not have an `__iter__` method or a `__getitem__` method
--> /src/mdtest_snippet.py:17:14
|
16 | # error: [not-iterable]
17 | for x in Iterable():
| ^^^^^^^^^^ Object of type `Iterable` may not be iterable because it may not have an `__iter__` method or a `__getitem__` method
| ^^^^^^^^^^
18 | reveal_type(x) # revealed: int | bytes
|

View file

@ -36,13 +36,13 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Test | Test2` may not be iterable because its `__iter__` method returns an object of type `TestIter | int`, which may not have a `__next__` method
--> /src/mdtest_snippet.py:18:14
|
16 | # TODO: Improve error message to state which union variant isn't iterable (https://github.com/astral-sh/ruff/issues/13989)
17 | # error: [not-iterable]
18 | for x in Test() if flag else Test2():
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Object of type `Test | Test2` may not be iterable because its `__iter__` method returns an object of type `TestIter | int`, which may not have a `__next__` method
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
19 | reveal_type(x) # revealed: int
|

View file

@ -31,13 +31,13 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Test | Literal[42]` may not be iterable because it may not have an `__iter__` method and it doesn't have a `__getitem__` method
--> /src/mdtest_snippet.py:13:14
|
11 | def _(flag: bool):
12 | # error: [not-iterable]
13 | for x in Test() if flag else 42:
| ^^^^^^^^^^^^^^^^^^^^^^ Object of type `Test | Literal[42]` may not be iterable because it may not have an `__iter__` method and it doesn't have a `__getitem__` method
| ^^^^^^^^^^^^^^^^^^^^^^
14 | reveal_type(x) # revealed: int
|

View file

@ -33,12 +33,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `NotIterable` is not iterable because its `__iter__` attribute has type `int | None`, which is not callable
--> /src/mdtest_snippet.py:11:14
|
10 | # error: [not-iterable]
11 | for x in NotIterable():
| ^^^^^^^^^^^^^ Object of type `NotIterable` is not iterable because its `__iter__` attribute has type `int | None`, which is not callable
| ^^^^^^^^^^^^^
12 | pass
|

View file

@ -26,12 +26,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Bad` is not iterable because its `__iter__` method returns an object of type `int`, which has no `__next__` method
--> /src/mdtest_snippet.py:8:10
|
7 | # error: [not-iterable]
8 | for x in Bad():
| ^^^^^ Object of type `Bad` is not iterable because its `__iter__` method returns an object of type `int`, which has no `__next__` method
| ^^^^^
9 | reveal_type(x) # revealed: Unknown
|

View file

@ -30,12 +30,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable` is not iterable because its `__iter__` method has an invalid signature (expected `def __iter__(self): ...`)
--> /src/mdtest_snippet.py:12:10
|
11 | # error: [not-iterable]
12 | for x in Iterable():
| ^^^^^^^^^^ Object of type `Iterable` is not iterable because its `__iter__` method has an invalid signature (expected `def __iter__(self): ...`)
| ^^^^^^^^^^
13 | reveal_type(x) # revealed: int
|

View file

@ -41,12 +41,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable1` is not iterable because its `__iter__` method returns an object of type `Iterator1`, which has an invalid `__next__` method (expected `def __next__(self): ...`)
--> /src/mdtest_snippet.py:19:10
|
18 | # error: [not-iterable]
19 | for x in Iterable1():
| ^^^^^^^^^^^ Object of type `Iterable1` is not iterable because its `__iter__` method returns an object of type `Iterator1`, which has an invalid `__next__` method (expected `def __next__(self): ...`)
| ^^^^^^^^^^^
20 | reveal_type(x) # revealed: int
|
@ -67,12 +67,12 @@ info: revealed-type: Revealed type
```
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Iterable2` is not iterable because its `__iter__` method returns an object of type `Iterator2`, which has a `__next__` attribute that is not callable
--> /src/mdtest_snippet.py:23:10
|
22 | # error: [not-iterable]
23 | for y in Iterable2():
| ^^^^^^^^^^^ Object of type `Iterable2` is not iterable because its `__iter__` method returns an object of type `Iterator2`, which has a `__next__` attribute that is not callable
| ^^^^^^^^^^^
24 | reveal_type(y) # revealed: Unknown
|

View file

@ -24,12 +24,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/binary/instances.m
# Diagnostics
```
error: lint:unsupported-bool-conversion
error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable
--> /src/mdtest_snippet.py:7:8
|
6 | # error: [unsupported-bool-conversion]
7 | 10 and a and True
| ^ Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable
| ^
|
```

View file

@ -28,12 +28,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/comparison/instanc
# Diagnostics
```
error: lint:unsupported-bool-conversion
error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable
--> /src/mdtest_snippet.py:9:1
|
8 | # error: [unsupported-bool-conversion]
9 | 10 in WithContains()
| ^^^^^^^^^^^^^^^^^^^^ Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable
| ^^^^^^^^^^^^^^^^^^^^
10 | # error: [unsupported-bool-conversion]
11 | 10 not in WithContains()
|
@ -41,13 +41,13 @@ error: lint:unsupported-bool-conversion
```
```
error: lint:unsupported-bool-conversion
error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable
--> /src/mdtest_snippet.py:11:1
|
9 | 10 in WithContains()
10 | # error: [unsupported-bool-conversion]
11 | 10 not in WithContains()
| ^^^^^^^^^^^^^^^^^^^^^^^^ Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
```

View file

@ -22,12 +22,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/unary/not.md
# Diagnostics
```
error: lint:unsupported-bool-conversion
error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable
--> /src/mdtest_snippet.py:5:1
|
4 | # error: [unsupported-bool-conversion]
5 | not NotBoolable()
| ^^^^^^^^^^^^^^^^^ Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable
| ^^^^^^^^^^^^^^^^^
|
```

View file

@ -33,12 +33,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/comparison/instanc
# Diagnostics
```
error: lint:unsupported-bool-conversion
error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable
--> /src/mdtest_snippet.py:12:1
|
11 | # error: [unsupported-bool-conversion]
12 | 10 < Comparable() < 20
| ^^^^^^^^^^^^^^^^^ Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable
| ^^^^^^^^^^^^^^^^^
13 | # error: [unsupported-bool-conversion]
14 | 10 < Comparable() < Comparable()
|
@ -46,13 +46,13 @@ error: lint:unsupported-bool-conversion
```
```
error: lint:unsupported-bool-conversion
error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable
--> /src/mdtest_snippet.py:14:1
|
12 | 10 < Comparable() < 20
13 | # error: [unsupported-bool-conversion]
14 | 10 < Comparable() < Comparable()
| ^^^^^^^^^^^^^^^^^ Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable
| ^^^^^^^^^^^^^^^^^
15 |
16 | Comparable() < Comparable() # fine
|

View file

@ -34,12 +34,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/comparison/tuples.
# Diagnostics
```
error: lint:unsupported-bool-conversion
error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable | Literal[False]`; its `__bool__` method isn't callable
--> /src/mdtest_snippet.py:15:1
|
14 | # error: [unsupported-bool-conversion]
15 | a < b < b
| ^^^^^ Boolean conversion is unsupported for type `NotBoolable | Literal[False]`; its `__bool__` method isn't callable
| ^^^^^
16 |
17 | a < b # fine
|

View file

@ -26,12 +26,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/comparison/tuples.
# Diagnostics
```
error: lint:unsupported-bool-conversion
error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable
--> /src/mdtest_snippet.py:9:1
|
8 | # error: [unsupported-bool-conversion]
9 | (A(),) == (A(),)
| ^^^^^^^^^^^^^^^^ Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable
| ^^^^^^^^^^^^^^^^
|
```

View file

@ -18,11 +18,11 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/unpack
# Diagnostics
```
error: lint:not-iterable
error: lint:not-iterable: Object of type `Literal[1]` is not iterable because it doesn't have an `__iter__` method or a `__getitem__` method
--> /src/mdtest_snippet.py:1:8
|
1 | a, b = 1 # error: [not-iterable]
| ^ Object of type `Literal[1]` is not iterable because it doesn't have an `__iter__` method or a `__getitem__` method
| ^
|
```

View file

@ -5029,11 +5029,10 @@ impl<'db> InvalidTypeExpressionError<'db> {
} = self;
if is_reachable {
for error in invalid_expressions {
context.report_lint_old(
&INVALID_TYPE_FORM,
node,
format_args!("{}", error.reason(context.db())),
);
let Some(builder) = context.report_lint(&INVALID_TYPE_FORM, node) else {
continue;
};
builder.into_diagnostic(error.reason(context.db()));
}
}
fallback_type
@ -5218,6 +5217,11 @@ impl<'db> ContextManagerError<'db> {
context_expression_type: Type<'db>,
context_expression_node: ast::AnyNodeRef,
) {
let Some(builder) = context.report_lint(&INVALID_CONTEXT_MANAGER, context_expression_node)
else {
return;
};
let format_call_dunder_error = |call_dunder_error: &CallDunderError<'db>, name: &str| {
match call_dunder_error {
CallDunderError::MethodNotAvailable => format!("it does not implement `{name}`"),
@ -5269,9 +5273,7 @@ impl<'db> ContextManagerError<'db> {
} => format_call_dunder_errors(enter_error, "__enter__", exit_error, "__exit__"),
};
context.report_lint_old(
&INVALID_CONTEXT_MANAGER,
context_expression_node,
builder.into_diagnostic(
format_args!(
"Object of type `{context_expression}` cannot be used with `with` because {formatted_errors}",
context_expression = context_expression_type.display(db)
@ -5369,10 +5371,13 @@ impl<'db> IterationError<'db> {
iterable_type: Type<'db>,
iterable_node: ast::AnyNodeRef,
) {
let Some(builder) = context.report_lint(&NOT_ITERABLE, iterable_node) else {
return;
};
let db = context.db();
let report_not_iterable = |arguments: std::fmt::Arguments| {
context.report_lint_old(&NOT_ITERABLE, iterable_node, arguments);
builder.into_diagnostic(arguments);
};
// TODO: for all of these error variants, the "explanation" for the diagnostic
@ -5646,13 +5651,14 @@ impl<'db> BoolError<'db> {
}
fn report_diagnostic_impl(&self, context: &InferContext, condition: TextRange) {
let Some(builder) = context.report_lint(&UNSUPPORTED_BOOL_CONVERSION, condition) else {
return;
};
match self {
Self::IncorrectArguments {
not_boolable_type, ..
} => {
context.report_lint_old(
&UNSUPPORTED_BOOL_CONVERSION,
condition,
builder.into_diagnostic(
format_args!(
"Boolean conversion is unsupported for type `{}`; it incorrectly implements `__bool__`",
not_boolable_type.display(context.db())
@ -5663,25 +5669,20 @@ impl<'db> BoolError<'db> {
not_boolable_type,
return_type,
} => {
context.report_lint_old(
&UNSUPPORTED_BOOL_CONVERSION,
condition,
format_args!(
"Boolean conversion is unsupported for type `{not_boolable}`; the return type of its bool method (`{return_type}`) isn't assignable to `bool",
builder.into_diagnostic(format_args!(
"Boolean conversion is unsupported for type `{not_boolable}`; \
the return type of its bool method (`{return_type}`) \
isn't assignable to `bool",
not_boolable = not_boolable_type.display(context.db()),
return_type = return_type.display(context.db())
),
);
));
}
Self::NotCallable { not_boolable_type } => {
context.report_lint_old(
&UNSUPPORTED_BOOL_CONVERSION,
condition,
format_args!(
"Boolean conversion is unsupported for type `{}`; its `__bool__` method isn't callable",
builder.into_diagnostic(format_args!(
"Boolean conversion is unsupported for type `{}`; \
its `__bool__` method isn't callable",
not_boolable_type.display(context.db())
),
);
));
}
Self::Union { union, .. } => {
let first_error = union
@ -5690,26 +5691,20 @@ impl<'db> BoolError<'db> {
.find_map(|element| element.try_bool(context.db()).err())
.unwrap();
context.report_lint_old(
&UNSUPPORTED_BOOL_CONVERSION,
condition,
format_args!(
"Boolean conversion is unsupported for union `{}` because `{}` doesn't implement `__bool__` correctly",
builder.into_diagnostic(format_args!(
"Boolean conversion is unsupported for union `{}` \
because `{}` doesn't implement `__bool__` correctly",
Type::Union(*union).display(context.db()),
first_error.not_boolable_type().display(context.db()),
),
);
));
}
Self::Other { not_boolable_type } => {
context.report_lint_old(
&UNSUPPORTED_BOOL_CONVERSION,
condition,
format_args!(
"Boolean conversion is unsupported for type `{}`; it incorrectly implements `__bool__`",
builder.into_diagnostic(format_args!(
"Boolean conversion is unsupported for type `{}`; \
it incorrectly implements `__bool__`",
not_boolable_type.display(context.db())
),
);
));
}
}
}
@ -5740,27 +5735,28 @@ impl<'db> ConstructorCallError<'db> {
) {
let report_init_error = |call_dunder_error: &CallDunderError<'db>| match call_dunder_error {
CallDunderError::MethodNotAvailable => {
if let Some(builder) =
context.report_lint(&CALL_POSSIBLY_UNBOUND_METHOD, context_expression_node)
{
// If we are using vendored typeshed, it should be impossible to have missing
// or unbound `__init__` method on a class, as all classes have `object` in MRO.
// Thus the following may only trigger if a custom typeshed is used.
context.report_lint_old(
&CALL_POSSIBLY_UNBOUND_METHOD,
context_expression_node,
format_args!(
"`__init__` method is missing on type `{}`. Make sure your `object` in typeshed has its definition.",
builder.into_diagnostic(format_args!(
"`__init__` method is missing on type `{}`. \
Make sure your `object` in typeshed has its definition.",
context_expression_type.display(context.db()),
),
);
));
}
}
CallDunderError::PossiblyUnbound(bindings) => {
context.report_lint_old(
&CALL_POSSIBLY_UNBOUND_METHOD,
context_expression_node,
format_args!(
if let Some(builder) =
context.report_lint(&CALL_POSSIBLY_UNBOUND_METHOD, context_expression_node)
{
builder.into_diagnostic(format_args!(
"Method `__init__` on type `{}` is possibly unbound.",
context_expression_type.display(context.db()),
),
);
));
}
bindings.report_diagnostics(context, context_expression_node);
}
@ -5776,14 +5772,14 @@ impl<'db> ConstructorCallError<'db> {
unreachable!("`__new__` method may not be called if missing");
}
CallDunderError::PossiblyUnbound(bindings) => {
context.report_lint_old(
&CALL_POSSIBLY_UNBOUND_METHOD,
context_expression_node,
format_args!(
if let Some(builder) =
context.report_lint(&CALL_POSSIBLY_UNBOUND_METHOD, context_expression_node)
{
builder.into_diagnostic(format_args!(
"Method `__new__` on type `{}` is possibly unbound.",
context_expression_type.display(context.db()),
),
);
));
}
bindings.report_diagnostics(context, context_expression_node);
}
@ -7130,34 +7126,31 @@ impl BoundSuperError<'_> {
pub(super) fn report_diagnostic(&self, context: &InferContext, node: AnyNodeRef) {
match self {
BoundSuperError::InvalidPivotClassType { pivot_class } => {
context.report_lint_old(
&INVALID_SUPER_ARGUMENT,
node,
format_args!(
if let Some(builder) = context.report_lint(&INVALID_SUPER_ARGUMENT, node) {
builder.into_diagnostic(format_args!(
"`{pivot_class}` is not a valid class",
pivot_class = pivot_class.display(context.db()),
),
);
));
}
}
BoundSuperError::FailingConditionCheck { pivot_class, owner } => {
context.report_lint_old(
&INVALID_SUPER_ARGUMENT,
node,
format_args!(
"`{owner}` is not an instance or subclass of `{pivot_class}` in `super({pivot_class}, {owner})` call",
if let Some(builder) = context.report_lint(&INVALID_SUPER_ARGUMENT, node) {
builder.into_diagnostic(format_args!(
"`{owner}` is not an instance or subclass of \
`{pivot_class}` in `super({pivot_class}, {owner})` call",
pivot_class = pivot_class.display(context.db()),
owner = owner.display(context.db()),
),
);
));
}
}
BoundSuperError::UnavailableImplicitArguments => {
context.report_lint_old(
&UNAVAILABLE_IMPLICIT_SUPER_ARGUMENTS,
node,
format_args!(
if let Some(builder) =
context.report_lint(&UNAVAILABLE_IMPLICIT_SUPER_ARGUMENTS, node)
{
builder.into_diagnostic(format_args!(
"Cannot determine implicit arguments for 'super()' in this context",
),
);
));
}
}
}
}