Skip to content

Commit 88aed94

Browse files
authored
checker: simplify check_simple_assignment error handling (#13549)
Let it only take an ErrorMessage. The default error now gets an error code as well, which closes up some code paths where we were getting code "misc".
1 parent c97d7e3 commit 88aed94

File tree

5 files changed

+25
-39
lines changed

5 files changed

+25
-39
lines changed

mypy/checker.py

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,10 +1255,9 @@ def check_default_args(self, item: FuncItem, body_is_trivial: bool) -> None:
12551255
arg.variable.type,
12561256
arg.initializer,
12571257
context=arg.initializer,
1258-
msg=msg,
1258+
msg=ErrorMessage(msg, code=codes.ASSIGNMENT),
12591259
lvalue_name="argument",
12601260
rvalue_name="default",
1261-
code=codes.ASSIGNMENT,
12621261
)
12631262

12641263
def is_forward_op_method(self, method_name: str) -> bool:
@@ -2427,8 +2426,8 @@ def check_import(self, node: ImportBase) -> None:
24272426
if lvalue_type is None:
24282427
# TODO: This is broken.
24292428
lvalue_type = AnyType(TypeOfAny.special_form)
2430-
message = '{} "{}"'.format(
2431-
message_registry.INCOMPATIBLE_IMPORT_OF, cast(NameExpr, assign.rvalue).name
2429+
message = message_registry.INCOMPATIBLE_IMPORT_OF.format(
2430+
cast(NameExpr, assign.rvalue).name
24322431
)
24332432
self.check_simple_assignment(
24342433
lvalue_type,
@@ -2692,9 +2691,7 @@ def check_assignment(
26922691
lvalue_type = make_optional_type(lvalue_type)
26932692
self.set_inferred_type(lvalue.node, lvalue, lvalue_type)
26942693

2695-
rvalue_type = self.check_simple_assignment(
2696-
lvalue_type, rvalue, context=rvalue, code=codes.ASSIGNMENT
2697-
)
2694+
rvalue_type = self.check_simple_assignment(lvalue_type, rvalue, context=rvalue)
26982695

26992696
# Special case: only non-abstract non-protocol classes can be assigned to
27002697
# variables with explicit type Type[A], where A is protocol or abstract.
@@ -2923,7 +2920,6 @@ def check_compatibility_super(
29232920
message_registry.INCOMPATIBLE_TYPES_IN_ASSIGNMENT,
29242921
"expression has type",
29252922
f'base class "{base.name}" defined the type as',
2926-
code=codes.ASSIGNMENT,
29272923
)
29282924
return True
29292925

@@ -3711,11 +3707,9 @@ def check_simple_assignment(
37113707
lvalue_type: Type | None,
37123708
rvalue: Expression,
37133709
context: Context,
3714-
msg: str = message_registry.INCOMPATIBLE_TYPES_IN_ASSIGNMENT,
3710+
msg: ErrorMessage = message_registry.INCOMPATIBLE_TYPES_IN_ASSIGNMENT,
37153711
lvalue_name: str = "variable",
37163712
rvalue_name: str = "expression",
3717-
*,
3718-
code: ErrorCode | None = None,
37193713
) -> Type:
37203714
if self.is_stub and isinstance(rvalue, EllipsisExpr):
37213715
# '...' is always a valid initializer in a stub.
@@ -3740,7 +3734,6 @@ def check_simple_assignment(
37403734
msg,
37413735
f"{rvalue_name} has type",
37423736
f"{lvalue_name} has type",
3743-
code=code,
37443737
)
37453738
return rvalue_type
37463739

@@ -3764,16 +3757,12 @@ def check_member_assignment(
37643757
if (isinstance(instance_type, FunctionLike) and instance_type.is_type_obj()) or isinstance(
37653758
instance_type, TypeType
37663759
):
3767-
rvalue_type = self.check_simple_assignment(
3768-
attribute_type, rvalue, context, code=codes.ASSIGNMENT
3769-
)
3760+
rvalue_type = self.check_simple_assignment(attribute_type, rvalue, context)
37703761
return rvalue_type, attribute_type, True
37713762

37723763
if not isinstance(attribute_type, Instance):
37733764
# TODO: support __set__() for union types.
3774-
rvalue_type = self.check_simple_assignment(
3775-
attribute_type, rvalue, context, code=codes.ASSIGNMENT
3776-
)
3765+
rvalue_type = self.check_simple_assignment(attribute_type, rvalue, context)
37773766
return rvalue_type, attribute_type, True
37783767

37793768
mx = MemberContext(
@@ -3792,9 +3781,7 @@ def check_member_assignment(
37923781
# the return type of __get__. This doesn't match the python semantics,
37933782
# (which allow you to override the descriptor with any value), but preserves
37943783
# the type of accessing the attribute (even after the override).
3795-
rvalue_type = self.check_simple_assignment(
3796-
get_type, rvalue, context, code=codes.ASSIGNMENT
3797-
)
3784+
rvalue_type = self.check_simple_assignment(get_type, rvalue, context)
37983785
return rvalue_type, get_type, True
37993786

38003787
dunder_set = attribute_type.type.get_method("__set__")
@@ -3861,9 +3848,7 @@ def check_member_assignment(
38613848
# and '__get__' type is narrower than '__set__', then we invoke the binder to narrow type
38623849
# by this assignment. Technically, this is not safe, but in practice this is
38633850
# what a user expects.
3864-
rvalue_type = self.check_simple_assignment(
3865-
set_type, rvalue, context, code=codes.ASSIGNMENT
3866-
)
3851+
rvalue_type = self.check_simple_assignment(set_type, rvalue, context)
38673852
infer = is_subtype(rvalue_type, get_type) and is_subtype(get_type, set_type)
38683853
return rvalue_type if infer else set_type, get_type, infer
38693854

mypy/checkexpr.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -821,10 +821,11 @@ def check_typeddict_call_with_kwargs(
821821
lvalue_type=item_expected_type,
822822
rvalue=item_value,
823823
context=item_value,
824-
msg=message_registry.INCOMPATIBLE_TYPES.value,
824+
msg=ErrorMessage(
825+
message_registry.INCOMPATIBLE_TYPES.value, code=codes.TYPEDDICT_ITEM
826+
),
825827
lvalue_name=f'TypedDict item "{item_name}"',
826828
rvalue_name="expression",
827-
code=codes.TYPEDDICT_ITEM,
828829
)
829830

830831
return orig_ret_type

mypy/errorcodes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def __str__(self) -> str:
4646
RETURN_VALUE: Final[ErrorCode] = ErrorCode(
4747
"return-value", "Check that return value is compatible with signature", "General"
4848
)
49-
ASSIGNMENT: Final = ErrorCode(
49+
ASSIGNMENT: Final[ErrorCode] = ErrorCode(
5050
"assignment", "Check that assigned value is compatible with target", "General"
5151
)
5252
TYPE_ARG: Final = ErrorCode("type-arg", "Check that generic type arguments are present", "General")

mypy/message_registry.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ def with_additional_msg(self, info: str) -> ErrorMessage:
5151
)
5252
YIELD_VALUE_EXPECTED: Final = ErrorMessage("Yield value expected")
5353
INCOMPATIBLE_TYPES: Final = ErrorMessage("Incompatible types")
54-
INCOMPATIBLE_TYPES_IN_ASSIGNMENT: Final = "Incompatible types in assignment"
54+
INCOMPATIBLE_TYPES_IN_ASSIGNMENT: Final = ErrorMessage(
55+
"Incompatible types in assignment", code=codes.ASSIGNMENT
56+
)
5557
INCOMPATIBLE_TYPES_IN_AWAIT: Final = ErrorMessage('Incompatible types in "await"')
5658
INCOMPATIBLE_REDEFINITION: Final = ErrorMessage("Incompatible redefinition")
5759
INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AENTER: Final = (
@@ -97,7 +99,7 @@ def with_additional_msg(self, info: str) -> ErrorMessage:
9799
FUNCTION_PARAMETER_CANNOT_BE_COVARIANT: Final = ErrorMessage(
98100
"Cannot use a covariant type variable as a parameter"
99101
)
100-
INCOMPATIBLE_IMPORT_OF: Final = "Incompatible import of"
102+
INCOMPATIBLE_IMPORT_OF: Final = ErrorMessage('Incompatible import of "{}"', code=codes.ASSIGNMENT)
101103
FUNCTION_TYPE_EXPECTED: Final = ErrorMessage(
102104
"Function is missing a type annotation", codes.NO_UNTYPED_DEF
103105
)

mypy/messages.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -582,20 +582,18 @@ def incompatible_argument(
582582
)
583583
return codes.INDEX
584584
else:
585-
msg = "{} (expression has type {}, target has type {})"
586585
arg_type_str, callee_type_str = format_type_distinctly(
587586
arg_type, callee.arg_types[n - 1]
588587
)
589-
self.fail(
590-
msg.format(
591-
message_registry.INCOMPATIBLE_TYPES_IN_ASSIGNMENT,
592-
arg_type_str,
593-
callee_type_str,
594-
),
595-
context,
596-
code=codes.ASSIGNMENT,
588+
info = (
589+
f" (expression has type {arg_type_str}, "
590+
f"target has type {callee_type_str})"
591+
)
592+
error_msg = (
593+
message_registry.INCOMPATIBLE_TYPES_IN_ASSIGNMENT.with_additional_msg(info)
597594
)
598-
return codes.ASSIGNMENT
595+
self.fail(error_msg.value, context, code=error_msg.code)
596+
return error_msg.code
599597

600598
target = f"to {name} "
601599

0 commit comments

Comments
 (0)