red_knot_python_semantic: migrate types/diagnostic to new diagnostics

This commit is contained in:
Andrew Gallant 2025-04-22 09:46:43 -04:00 committed by Andrew Gallant
parent 3796b13ea2
commit c12640fea8
7 changed files with 134 additions and 145 deletions

View file

@ -274,13 +274,13 @@ fn configuration_rule_severity() -> anyhow::Result<()> {
4 | for a in range(0, int(y)):
|
warning: lint:possibly-unresolved-reference
warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined
--> <temp_dir>/test.py:7:7
|
5 | x = a
6 |
7 | print(x) # possibly-unresolved-reference
| ^ Name `x` used when possibly not defined
| ^
|
Found 2 diagnostics
@ -361,13 +361,13 @@ fn cli_rule_severity() -> anyhow::Result<()> {
6 | for a in range(0, int(y)):
|
warning: lint:possibly-unresolved-reference
warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined
--> <temp_dir>/test.py:9:7
|
7 | x = a
8 |
9 | print(x) # possibly-unresolved-reference
| ^ Name `x` used when possibly not defined
| ^
|
Found 3 diagnostics
@ -448,13 +448,13 @@ fn cli_rule_severity_precedence() -> anyhow::Result<()> {
4 | for a in range(0, int(y)):
|
warning: lint:possibly-unresolved-reference
warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined
--> <temp_dir>/test.py:7:7
|
5 | x = a
6 |
7 | print(x) # possibly-unresolved-reference
| ^ Name `x` used when possibly not defined
| ^
|
Found 2 diagnostics
@ -555,11 +555,11 @@ fn exit_code_only_warnings() -> anyhow::Result<()> {
success: true
exit_code: 0
----- stdout -----
warning: lint:unresolved-reference
warning: lint:unresolved-reference: Name `x` used when not defined
--> <temp_dir>/test.py:1:7
|
1 | print(x) # [unresolved-reference]
| ^ Name `x` used when not defined
| ^
|
Found 1 diagnostic
@ -638,11 +638,11 @@ fn exit_code_no_errors_but_error_on_warning_is_true() -> anyhow::Result<()> {
success: false
exit_code: 1
----- stdout -----
warning: lint:unresolved-reference
warning: lint:unresolved-reference: Name `x` used when not defined
--> <temp_dir>/test.py:1:7
|
1 | print(x) # [unresolved-reference]
| ^ Name `x` used when not defined
| ^
|
Found 1 diagnostic
@ -670,11 +670,11 @@ fn exit_code_no_errors_but_error_on_warning_is_enabled_in_configuration() -> any
success: false
exit_code: 1
----- stdout -----
warning: lint:unresolved-reference
warning: lint:unresolved-reference: Name `x` used when not defined
--> <temp_dir>/test.py:1:7
|
1 | print(x) # [unresolved-reference]
| ^ Name `x` used when not defined
| ^
|
Found 1 diagnostic
@ -699,20 +699,20 @@ fn exit_code_both_warnings_and_errors() -> anyhow::Result<()> {
success: false
exit_code: 1
----- stdout -----
warning: lint:unresolved-reference
warning: lint:unresolved-reference: Name `x` used when not defined
--> <temp_dir>/test.py:2:7
|
2 | print(x) # [unresolved-reference]
| ^ Name `x` used when not defined
| ^
3 | print(4[1]) # [non-subscriptable]
|
error: lint:non-subscriptable
error: lint:non-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method
--> <temp_dir>/test.py:3:7
|
2 | print(x) # [unresolved-reference]
3 | print(4[1]) # [non-subscriptable]
| ^ Cannot subscript object of type `Literal[4]` with no `__getitem__` method
| ^
|
Found 2 diagnostics
@ -737,20 +737,20 @@ fn exit_code_both_warnings_and_errors_and_error_on_warning_is_true() -> anyhow::
success: false
exit_code: 1
----- stdout -----
warning: lint:unresolved-reference
warning: lint:unresolved-reference: Name `x` used when not defined
--> <temp_dir>/test.py:2:7
|
2 | print(x) # [unresolved-reference]
| ^ Name `x` used when not defined
| ^
3 | print(4[1]) # [non-subscriptable]
|
error: lint:non-subscriptable
error: lint:non-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method
--> <temp_dir>/test.py:3:7
|
2 | print(x) # [unresolved-reference]
3 | print(4[1]) # [non-subscriptable]
| ^ Cannot subscript object of type `Literal[4]` with no `__getitem__` method
| ^
|
Found 2 diagnostics
@ -775,20 +775,20 @@ fn exit_code_exit_zero_is_true() -> anyhow::Result<()> {
success: true
exit_code: 0
----- stdout -----
warning: lint:unresolved-reference
warning: lint:unresolved-reference: Name `x` used when not defined
--> <temp_dir>/test.py:2:7
|
2 | print(x) # [unresolved-reference]
| ^ Name `x` used when not defined
| ^
3 | print(4[1]) # [non-subscriptable]
|
error: lint:non-subscriptable
error: lint:non-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method
--> <temp_dir>/test.py:3:7
|
2 | print(x) # [unresolved-reference]
3 | print(4[1]) # [non-subscriptable]
| ^ Cannot subscript object of type `Literal[4]` with no `__getitem__` method
| ^
|
Found 2 diagnostics
@ -844,13 +844,13 @@ fn user_configuration() -> anyhow::Result<()> {
4 | for a in range(0, int(y)):
|
warning: lint:possibly-unresolved-reference
warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined
--> <temp_dir>/project/main.py:7:7
|
5 | x = a
6 |
7 | print(x)
| ^ Name `x` used when possibly not defined
| ^
|
Found 2 diagnostics
@ -886,13 +886,13 @@ fn user_configuration() -> anyhow::Result<()> {
4 | for a in range(0, int(y)):
|
error: lint:possibly-unresolved-reference
error: lint:possibly-unresolved-reference: Name `x` used when possibly not defined
--> <temp_dir>/project/main.py:7:7
|
5 | x = a
6 |
7 | print(x)
| ^ Name `x` used when possibly not defined
| ^
|
Found 2 diagnostics

View file

@ -26,13 +26,13 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/attrib
# Diagnostics
```
warning: lint:possibly-unbound-attribute
warning: lint:possibly-unbound-attribute: Attribute `attr` on type `Literal[C]` is possibly unbound
--> /src/mdtest_snippet.py:6:5
|
4 | attr: int = 0
5 |
6 | C.attr = 1 # error: [possibly-unbound-attribute]
| ^^^^^^ Attribute `attr` on type `Literal[C]` is possibly unbound
| ^^^^^^
7 |
8 | instance = C()
|
@ -40,12 +40,12 @@ warning: lint:possibly-unbound-attribute
```
```
warning: lint:possibly-unbound-attribute
warning: lint:possibly-unbound-attribute: Attribute `attr` on type `C` is possibly unbound
--> /src/mdtest_snippet.py:9:5
|
8 | instance = C()
9 | instance.attr = 1 # error: [possibly-unbound-attribute]
| ^^^^^^^^^^^^^ Attribute `attr` on type `C` is possibly unbound
| ^^^^^^^^^^^^^
|
```

View file

@ -45,13 +45,13 @@ error: lint:not-iterable
```
```
warning: lint:possibly-unresolved-reference
warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined
--> /src/mdtest_snippet.py:16:17
|
14 | # revealed: Unknown
15 | # error: [possibly-unresolved-reference]
16 | reveal_type(x)
| ^ Name `x` used when possibly not defined
| ^
|
```

View file

@ -56,12 +56,12 @@ error: lint:invalid-return-type: Return type does not match returned value
```
```
error: lint:invalid-return-type
error: lint:invalid-return-type: Function can implicitly return `None`, which is not assignable to return type `int`
--> /src/mdtest_snippet.py:7:22
|
6 | # error: [invalid-return-type]
7 | def f(cond: bool) -> int:
| ^^^ Function can implicitly return `None`, which is not assignable to return type `int`
| ^^^
8 | if cond:
9 | return 1
|
@ -69,12 +69,12 @@ error: lint:invalid-return-type
```
```
error: lint:invalid-return-type
error: lint:invalid-return-type: Function can implicitly return `None`, which is not assignable to return type `int`
--> /src/mdtest_snippet.py:12:22
|
11 | # error: [invalid-return-type]
12 | def f(cond: bool) -> int:
| ^^^ Function can implicitly return `None`, which is not assignable to return type `int`
| ^^^
13 | if cond:
14 | raise ValueError()
|
@ -82,12 +82,12 @@ error: lint:invalid-return-type
```
```
error: lint:invalid-return-type
error: lint:invalid-return-type: Function can implicitly return `None`, which is not assignable to return type `int`
--> /src/mdtest_snippet.py:17:22
|
16 | # error: [invalid-return-type]
17 | def f(cond: bool) -> int:
| ^^^ Function can implicitly return `None`, which is not assignable to return type `int`
| ^^^
18 | if cond:
19 | cond = False
|

View file

@ -35,12 +35,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/function/return_ty
# Diagnostics
```
error: lint:invalid-return-type
error: lint:invalid-return-type: Function can implicitly return `None`, which is not assignable to return type `int`
--> /src/mdtest_snippet.py:2:12
|
1 | # error: [invalid-return-type]
2 | def f() -> int:
| ^^^ Function can implicitly return `None`, which is not assignable to return type `int`
| ^^^
3 | 1
|

View file

@ -45,12 +45,12 @@ error: lint:invalid-return-type: Return type does not match returned value
```
```
error: lint:invalid-return-type
error: lint:invalid-return-type: Function can implicitly return `None`, which is not assignable to return type `int`
--> /src/mdtest_snippet.pyi:6:14
|
5 | # error: [invalid-return-type]
6 | def foo() -> int:
| ^^^ Function can implicitly return `None`, which is not assignable to return type `int`
| ^^^
7 | print("...")
8 | ...
|
@ -58,12 +58,12 @@ error: lint:invalid-return-type
```
```
error: lint:invalid-return-type
error: lint:invalid-return-type: Function can implicitly return `None`, which is not assignable to return type `int`
--> /src/mdtest_snippet.pyi:11:14
|
10 | # error: [invalid-return-type]
11 | def foo() -> int:
| ^^^ Function can implicitly return `None`, which is not assignable to return type `int`
| ^^^
12 | f"""{foo} is a function that ..."""
13 | ...
|

View file

@ -1075,14 +1075,13 @@ pub(super) fn report_index_out_of_bounds(
length: usize,
index: i64,
) {
context.report_lint_old(
&INDEX_OUT_OF_BOUNDS,
node,
format_args!(
"Index {index} is out of bounds for {kind} `{}` with length {length}",
tuple_ty.display(context.db())
),
);
let Some(builder) = context.report_lint(&INDEX_OUT_OF_BOUNDS, node) else {
return;
};
builder.into_diagnostic(format_args!(
"Index {index} is out of bounds for {kind} `{}` with length {length}",
tuple_ty.display(context.db())
));
}
/// Emit a diagnostic declaring that a type does not support subscripting.
@ -1092,22 +1091,20 @@ pub(super) fn report_non_subscriptable(
non_subscriptable_ty: Type,
method: &str,
) {
context.report_lint_old(
&NON_SUBSCRIPTABLE,
node,
format_args!(
"Cannot subscript object of type `{}` with no `{method}` method",
non_subscriptable_ty.display(context.db())
),
);
let Some(builder) = context.report_lint(&NON_SUBSCRIPTABLE, node) else {
return;
};
builder.into_diagnostic(format_args!(
"Cannot subscript object of type `{}` with no `{method}` method",
non_subscriptable_ty.display(context.db())
));
}
pub(super) fn report_slice_step_size_zero(context: &InferContext, node: AnyNodeRef) {
context.report_lint_old(
&ZERO_STEPSIZE_IN_SLICE,
node,
format_args!("Slice step size can not be zero"),
);
let Some(builder) = context.report_lint(&ZERO_STEPSIZE_IN_SLICE, node) else {
return;
};
builder.into_diagnostic("Slice step size can not be zero");
}
fn report_invalid_assignment_with_message(
@ -1209,21 +1206,21 @@ pub(super) fn report_implicit_return_type(
range: impl Ranged,
expected_ty: Type,
) {
context.report_lint_old(
&INVALID_RETURN_TYPE,
range,
format_args!(
"Function can implicitly return `None`, which is not assignable to return type `{}`",
expected_ty.display(context.db())
),
);
let Some(builder) = context.report_lint(&INVALID_RETURN_TYPE, range) else {
return;
};
builder.into_diagnostic(format_args!(
"Function can implicitly return `None`, which is not assignable to return type `{}`",
expected_ty.display(context.db())
));
}
pub(super) fn report_invalid_type_checking_constant(context: &InferContext, node: AnyNodeRef) {
context.report_lint_old(
&INVALID_TYPE_CHECKING_CONSTANT,
node,
format_args!("The name TYPE_CHECKING is reserved for use as a flag; only False can be assigned to it.",),
let Some(builder) = context.report_lint(&INVALID_TYPE_CHECKING_CONSTANT, node) else {
return;
};
builder.into_diagnostic(
"The name TYPE_CHECKING is reserved for use as a flag; only False can be assigned to it",
);
}
@ -1231,13 +1228,12 @@ pub(super) fn report_possibly_unresolved_reference(
context: &InferContext,
expr_name_node: &ast::ExprName,
) {
let ast::ExprName { id, .. } = expr_name_node;
let Some(builder) = context.report_lint(&POSSIBLY_UNRESOLVED_REFERENCE, expr_name_node) else {
return;
};
context.report_lint_old(
&POSSIBLY_UNRESOLVED_REFERENCE,
expr_name_node,
format_args!("Name `{id}` used when possibly not defined"),
);
let ast::ExprName { id, .. } = expr_name_node;
builder.into_diagnostic(format_args!("Name `{id}` used when possibly not defined"));
}
pub(super) fn report_possibly_unbound_attribute(
@ -1246,93 +1242,86 @@ pub(super) fn report_possibly_unbound_attribute(
attribute: &str,
object_ty: Type,
) {
context.report_lint_old(
&POSSIBLY_UNBOUND_ATTRIBUTE,
target,
format_args!(
"Attribute `{attribute}` on type `{}` is possibly unbound",
object_ty.display(context.db()),
),
);
let Some(builder) = context.report_lint(&POSSIBLY_UNBOUND_ATTRIBUTE, target) else {
return;
};
builder.into_diagnostic(format_args!(
"Attribute `{attribute}` on type `{}` is possibly unbound",
object_ty.display(context.db()),
));
}
pub(super) fn report_unresolved_reference(context: &InferContext, expr_name_node: &ast::ExprName) {
let ast::ExprName { id, .. } = expr_name_node;
let Some(builder) = context.report_lint(&UNRESOLVED_REFERENCE, expr_name_node) else {
return;
};
context.report_lint_old(
&UNRESOLVED_REFERENCE,
expr_name_node,
format_args!("Name `{id}` used when not defined"),
);
let ast::ExprName { id, .. } = expr_name_node;
builder.into_diagnostic(format_args!("Name `{id}` used when not defined"));
}
pub(super) fn report_invalid_exception_caught(context: &InferContext, node: &ast::Expr, ty: Type) {
context.report_lint_old(
&INVALID_EXCEPTION_CAUGHT,
node,
format_args!(
"Cannot catch object of type `{}` in an exception handler \
let Some(builder) = context.report_lint(&INVALID_EXCEPTION_CAUGHT, node) else {
return;
};
builder.into_diagnostic(format_args!(
"Cannot catch object of type `{}` in an exception handler \
(must be a `BaseException` subclass or a tuple of `BaseException` subclasses)",
ty.display(context.db())
),
);
ty.display(context.db())
));
}
pub(crate) fn report_invalid_exception_raised(context: &InferContext, node: &ast::Expr, ty: Type) {
context.report_lint_old(
&INVALID_RAISE,
node,
format_args!(
"Cannot raise object of type `{}` (must be a `BaseException` subclass or instance)",
ty.display(context.db())
),
);
let Some(builder) = context.report_lint(&INVALID_RAISE, node) else {
return;
};
builder.into_diagnostic(format_args!(
"Cannot raise object of type `{}` (must be a `BaseException` subclass or instance)",
ty.display(context.db())
));
}
pub(crate) fn report_invalid_exception_cause(context: &InferContext, node: &ast::Expr, ty: Type) {
context.report_lint_old(
&INVALID_RAISE,
node,
format_args!(
"Cannot use object of type `{}` as exception cause \
(must be a `BaseException` subclass or instance or `None`)",
ty.display(context.db())
),
);
let Some(builder) = context.report_lint(&INVALID_RAISE, node) else {
return;
};
builder.into_diagnostic(format_args!(
"Cannot use object of type `{}` as exception cause \
(must be a `BaseException` subclass or instance or `None`)",
ty.display(context.db())
));
}
pub(crate) fn report_base_with_incompatible_slots(context: &InferContext, node: &ast::Expr) {
context.report_lint_old(
&INCOMPATIBLE_SLOTS,
node,
format_args!("Class base has incompatible `__slots__`"),
);
let Some(builder) = context.report_lint(&INCOMPATIBLE_SLOTS, node) else {
return;
};
builder.into_diagnostic("Class base has incompatible `__slots__`");
}
pub(crate) fn report_invalid_arguments_to_annotated(
context: &InferContext,
subscript: &ast::ExprSubscript,
) {
context.report_lint_old(
&INVALID_TYPE_FORM,
subscript,
format_args!(
"Special form `{}` expected at least 2 arguments (one type and at least one metadata element)",
KnownInstanceType::Annotated.repr(context.db())
),
);
let Some(builder) = context.report_lint(&INVALID_TYPE_FORM, subscript) else {
return;
};
builder.into_diagnostic(format_args!(
"Special form `{}` expected at least 2 arguments \
(one type and at least one metadata element)",
KnownInstanceType::Annotated.repr(context.db())
));
}
pub(crate) fn report_invalid_arguments_to_callable(
context: &InferContext,
subscript: &ast::ExprSubscript,
) {
context.report_lint_old(
&INVALID_TYPE_FORM,
subscript,
format_args!(
"Special form `{}` expected exactly two arguments (parameter types and return type)",
KnownInstanceType::Callable.repr(context.db())
),
);
let Some(builder) = context.report_lint(&INVALID_TYPE_FORM, subscript) else {
return;
};
builder.into_diagnostic(format_args!(
"Special form `{}` expected exactly two arguments (parameter types and return type)",
KnownInstanceType::Callable.repr(context.db())
));
}