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.
This commit is contained in:
Andrew Gallant 2025-04-16 10:42:47 -04:00 committed by Andrew Gallant
parent 6dc2d29966
commit b8b624d890
4 changed files with 45 additions and 35 deletions

View File

@ -28,12 +28,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/attrib
# Diagnostics
```
error: lint:invalid-assignment
error: lint:invalid-assignment: Invalid assignment to data descriptor attribute `attr` on type `C` with custom `__set__` method
--> /src/mdtest_snippet.py:11:1
|
10 | # TODO: ideally, we would mention why this is an invalid assignment (wrong number of arguments for `__set__`)
11 | instance.attr = 1 # error: [invalid-assignment]
| ^^^^^^^^^^^^^ Invalid assignment to data descriptor attribute `attr` on type `C` with custom `__set__` method
| ^^^^^^^^^^^^^
|
```

View File

@ -29,12 +29,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/attrib
# Diagnostics
```
error: lint:invalid-assignment
error: lint:invalid-assignment: Invalid assignment to data descriptor attribute `attr` on type `C` with custom `__set__` method
--> /src/mdtest_snippet.py:12:1
|
11 | # TODO: ideally, we would mention why this is an invalid assignment (wrong argument type for `value` parameter)
12 | instance.attr = "wrong" # error: [invalid-assignment]
| ^^^^^^^^^^^^^ Invalid assignment to data descriptor attribute `attr` on type `C` with custom `__set__` method
| ^^^^^^^^^^^^^
|
```

View File

@ -37,12 +37,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/attrib
# Diagnostics
```
error: lint:invalid-assignment
error: lint:invalid-assignment: Object of type `Literal[1]` is not assignable to attribute `attr` on type `Literal[C1, C1]`
--> /src/mdtest_snippet.py:11:5
|
10 | # TODO: The error message here could be improved to explain why the assignment fails.
11 | C1.attr = 1 # error: [invalid-assignment]
| ^^^^^^^ Object of type `Literal[1]` is not assignable to attribute `attr` on type `Literal[C1, C1]`
| ^^^^^^^
12 |
13 | class C2:
|

View File

@ -2442,13 +2442,17 @@ impl<'db> TypeInferenceBuilder<'db> {
true
} else {
// TODO: This is not a very helpful error message, as it does not include the underlying reason
// why the assignment is invalid. This would be a good use case for nested diagnostics.
// why the assignment is invalid. This would be a good use case for sub-diagnostics.
if emit_diagnostics {
self.context.report_lint_old(&INVALID_ASSIGNMENT, target, format_args!(
"Object of type `{}` is not assignable to attribute `{attribute}` on type `{}`",
value_ty.display(self.db()),
object_ty.display(self.db()),
));
if let Some(builder) = self.context.report_lint(&INVALID_ASSIGNMENT, target)
{
builder.into_diagnostic(format_args!(
"Object of type `{}` is not assignable \
to attribute `{attribute}` on type `{}`",
value_ty.display(self.db()),
object_ty.display(self.db()),
));
}
}
false
@ -2463,12 +2467,16 @@ impl<'db> TypeInferenceBuilder<'db> {
true
} else {
if emit_diagnostics {
// TODO: same here, see above
self.context.report_lint_old(&INVALID_ASSIGNMENT, target, format_args!(
"Object of type `{}` is not assignable to attribute `{attribute}` on type `{}`",
value_ty.display(self.db()),
object_ty.display(self.db()),
));
if let Some(builder) = self.context.report_lint(&INVALID_ASSIGNMENT, target)
{
// TODO: same here, see above
builder.into_diagnostic(format_args!(
"Object of type `{}` is not assignable \
to attribute `{attribute}` on type `{}`",
value_ty.display(self.db()),
object_ty.display(self.db()),
));
}
}
false
}
@ -2557,15 +2565,16 @@ impl<'db> TypeInferenceBuilder<'db> {
.is_ok();
if !successful_call && emit_diagnostics {
// TODO: Here, it would be nice to emit an additional diagnostic that explains why the call failed
self.context.report_lint_old(
&INVALID_ASSIGNMENT,
target,
format_args!(
"Invalid assignment to data descriptor attribute `{attribute}` on type `{}` with custom `__set__` method",
object_ty.display(db)
),
);
if let Some(builder) =
self.context.report_lint(&INVALID_ASSIGNMENT, target)
{
// TODO: Here, it would be nice to emit an additional diagnostic that explains why the call failed
builder.into_diagnostic(format_args!(
"Invalid assignment to data descriptor attribute \
`{attribute}` on type `{}` with custom `__set__` method",
object_ty.display(db)
));
}
}
successful_call
@ -2695,15 +2704,16 @@ impl<'db> TypeInferenceBuilder<'db> {
.is_ok();
if !successful_call && emit_diagnostics {
// TODO: Here, it would be nice to emit an additional diagnostic that explains why the call failed
self.context.report_lint_old(
&INVALID_ASSIGNMENT,
target,
format_args!(
"Invalid assignment to data descriptor attribute `{attribute}` on type `{}` with custom `__set__` method",
if let Some(builder) =
self.context.report_lint(&INVALID_ASSIGNMENT, target)
{
// TODO: Here, it would be nice to emit an additional diagnostic that explains why the call failed
builder.into_diagnostic(format_args!(
"Invalid assignment to data descriptor attribute \
`{attribute}` on type `{}` with custom `__set__` method",
object_ty.display(db)
),
);
));
}
}
successful_call