mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 10:22:24 +00:00
[red-knot] Improved error message for attribute-assignments (#15668)
## Summary Slightly improved error message for attribute assignments.
This commit is contained in:
parent
f349dab4fc
commit
13e7afca42
3 changed files with 56 additions and 24 deletions
|
@ -102,7 +102,7 @@ reveal_type(C.pure_instance_variable) # revealed: str
|
|||
# and pyright allow this.
|
||||
C.pure_instance_variable = "overwritten on class"
|
||||
|
||||
# error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to `str`"
|
||||
# error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to attribute `pure_instance_variable` of type `str`"
|
||||
c_instance.pure_instance_variable = 1
|
||||
```
|
||||
|
||||
|
@ -191,7 +191,7 @@ c_instance.pure_class_variable1 = "value set on instance"
|
|||
|
||||
C.pure_class_variable1 = "overwritten on class"
|
||||
|
||||
# error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to `str`"
|
||||
# error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to attribute `pure_class_variable1` of type `str`"
|
||||
C.pure_class_variable1 = 1
|
||||
|
||||
class Subclass(C):
|
||||
|
@ -448,10 +448,10 @@ import mod
|
|||
reveal_type(mod.global_symbol) # revealed: str
|
||||
mod.global_symbol = "b"
|
||||
|
||||
# error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to `str`"
|
||||
# error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to attribute `global_symbol` of type `str`"
|
||||
mod.global_symbol = 1
|
||||
|
||||
# error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to `str`"
|
||||
# error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to attribute `global_symbol` of type `str`"
|
||||
(_, mod.global_symbol) = (..., 1)
|
||||
|
||||
# TODO: this should be an error, but we do not understand list unpackings yet.
|
||||
|
@ -465,7 +465,7 @@ class IntIterable:
|
|||
def __iter__(self) -> IntIterator:
|
||||
return IntIterator()
|
||||
|
||||
# error: [invalid-assignment] "Object of type `int` is not assignable to `str`"
|
||||
# error: [invalid-assignment] "Object of type `int` is not assignable to attribute `global_symbol` of type `str`"
|
||||
for mod.global_symbol in IntIterable():
|
||||
pass
|
||||
```
|
||||
|
|
|
@ -984,13 +984,13 @@ pub(super) fn report_slice_step_size_zero(context: &InferContext, node: AnyNodeR
|
|||
);
|
||||
}
|
||||
|
||||
pub(super) fn report_invalid_assignment(
|
||||
fn report_invalid_assignment_with_message(
|
||||
context: &InferContext,
|
||||
node: AnyNodeRef,
|
||||
declared_ty: Type,
|
||||
assigned_ty: Type,
|
||||
target_ty: Type,
|
||||
message: std::fmt::Arguments,
|
||||
) {
|
||||
match declared_ty {
|
||||
match target_ty {
|
||||
Type::ClassLiteral(ClassLiteralType { class }) => {
|
||||
context.report_lint(&INVALID_ASSIGNMENT, node, format_args!(
|
||||
"Implicit shadowing of class `{}`; annotate to make it explicit if this is intentional",
|
||||
|
@ -1002,19 +1002,48 @@ pub(super) fn report_invalid_assignment(
|
|||
function.name(context.db())));
|
||||
}
|
||||
_ => {
|
||||
context.report_lint(
|
||||
&INVALID_ASSIGNMENT,
|
||||
node,
|
||||
format_args!(
|
||||
"Object of type `{}` is not assignable to `{}`",
|
||||
assigned_ty.display(context.db()),
|
||||
declared_ty.display(context.db()),
|
||||
),
|
||||
);
|
||||
context.report_lint(&INVALID_ASSIGNMENT, node, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn report_invalid_assignment(
|
||||
context: &InferContext,
|
||||
node: AnyNodeRef,
|
||||
target_ty: Type,
|
||||
source_ty: Type,
|
||||
) {
|
||||
report_invalid_assignment_with_message(
|
||||
context,
|
||||
node,
|
||||
target_ty,
|
||||
format_args!(
|
||||
"Object of type `{}` is not assignable to `{}`",
|
||||
source_ty.display(context.db()),
|
||||
target_ty.display(context.db()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn report_invalid_attribute_assignment(
|
||||
context: &InferContext,
|
||||
node: AnyNodeRef,
|
||||
target_ty: Type,
|
||||
source_ty: Type,
|
||||
attribute_name: &'_ str,
|
||||
) {
|
||||
report_invalid_assignment_with_message(
|
||||
context,
|
||||
node,
|
||||
target_ty,
|
||||
format_args!(
|
||||
"Object of type `{}` is not assignable to attribute `{attribute_name}` of type `{}`",
|
||||
source_ty.display(context.db()),
|
||||
target_ty.display(context.db()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn report_possibly_unresolved_reference(
|
||||
context: &InferContext,
|
||||
expr_name_node: &ast::ExprName,
|
||||
|
|
|
@ -51,11 +51,12 @@ use crate::semantic_index::SemanticIndex;
|
|||
use crate::stdlib::builtins_module_scope;
|
||||
use crate::types::call::{Argument, CallArguments};
|
||||
use crate::types::diagnostic::{
|
||||
report_invalid_arguments_to_annotated, report_invalid_assignment, report_unresolved_module,
|
||||
TypeCheckDiagnostics, CALL_NON_CALLABLE, CALL_POSSIBLY_UNBOUND_METHOD,
|
||||
CONFLICTING_DECLARATIONS, CONFLICTING_METACLASS, CYCLIC_CLASS_DEFINITION, DIVISION_BY_ZERO,
|
||||
DUPLICATE_BASE, INCONSISTENT_MRO, INVALID_ATTRIBUTE_ACCESS, INVALID_BASE,
|
||||
INVALID_CONTEXT_MANAGER, INVALID_DECLARATION, INVALID_PARAMETER_DEFAULT, INVALID_TYPE_FORM,
|
||||
report_invalid_arguments_to_annotated, report_invalid_assignment,
|
||||
report_invalid_attribute_assignment, report_unresolved_module, TypeCheckDiagnostics,
|
||||
CALL_NON_CALLABLE, CALL_POSSIBLY_UNBOUND_METHOD, CONFLICTING_DECLARATIONS,
|
||||
CONFLICTING_METACLASS, CYCLIC_CLASS_DEFINITION, DIVISION_BY_ZERO, DUPLICATE_BASE,
|
||||
INCONSISTENT_MRO, INVALID_ATTRIBUTE_ACCESS, INVALID_BASE, INVALID_CONTEXT_MANAGER,
|
||||
INVALID_DECLARATION, INVALID_PARAMETER_DEFAULT, INVALID_TYPE_FORM,
|
||||
INVALID_TYPE_VARIABLE_CONSTRAINTS, POSSIBLY_UNBOUND_ATTRIBUTE, POSSIBLY_UNBOUND_IMPORT,
|
||||
UNDEFINED_REVEAL, UNRESOLVED_ATTRIBUTE, UNRESOLVED_IMPORT, UNSUPPORTED_OPERATOR,
|
||||
};
|
||||
|
@ -2022,6 +2023,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
ast::Expr::Attribute(
|
||||
lhs_expr @ ast::ExprAttribute {
|
||||
ctx: ExprContext::Store,
|
||||
attr,
|
||||
..
|
||||
},
|
||||
) => {
|
||||
|
@ -2030,11 +2032,12 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
|
||||
if let Some(assigned_ty) = assigned_ty {
|
||||
if !assigned_ty.is_assignable_to(self.db(), attribute_expr_ty) {
|
||||
report_invalid_assignment(
|
||||
report_invalid_attribute_assignment(
|
||||
&self.context,
|
||||
target.into(),
|
||||
attribute_expr_ty,
|
||||
assigned_ty,
|
||||
attr.as_str(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue