@@ -355,7 +355,7 @@ def has_no_attr(
355355 member : str ,
356356 context : Context ,
357357 module_symbol_table : SymbolTable | None = None ,
358- ) -> Type :
358+ ) -> ErrorCode | None :
359359 """Report a missing or non-accessible member.
360360
361361 original_type is the top-level type on which the error occurred.
@@ -370,44 +370,49 @@ def has_no_attr(
370370 directly available on original_type
371371
372372 If member corresponds to an operator, use the corresponding operator
373- name in the messages. Return type Any .
373+ name in the messages. Return the error code that was produced, if any .
374374 """
375375 original_type = get_proper_type (original_type )
376376 typ = get_proper_type (typ )
377377
378378 if isinstance (original_type , Instance ) and original_type .type .has_readable_member (member ):
379379 self .fail (f'Member "{ member } " is not assignable' , context )
380+ return None
380381 elif member == "__contains__" :
381382 self .fail (
382383 f"Unsupported right operand type for in ({ format_type (original_type , self .options )} )" ,
383384 context ,
384385 code = codes .OPERATOR ,
385386 )
387+ return codes .OPERATOR
386388 elif member in op_methods .values ():
387389 # Access to a binary operator member (e.g. _add). This case does
388390 # not handle indexing operations.
389391 for op , method in op_methods .items ():
390392 if method == member :
391393 self .unsupported_left_operand (op , original_type , context )
392- break
394+ return codes . OPERATOR
393395 elif member == "__neg__" :
394396 self .fail (
395397 f"Unsupported operand type for unary - ({ format_type (original_type , self .options )} )" ,
396398 context ,
397399 code = codes .OPERATOR ,
398400 )
401+ return codes .OPERATOR
399402 elif member == "__pos__" :
400403 self .fail (
401404 f"Unsupported operand type for unary + ({ format_type (original_type , self .options )} )" ,
402405 context ,
403406 code = codes .OPERATOR ,
404407 )
408+ return codes .OPERATOR
405409 elif member == "__invert__" :
406410 self .fail (
407411 f"Unsupported operand type for ~ ({ format_type (original_type , self .options )} )" ,
408412 context ,
409413 code = codes .OPERATOR ,
410414 )
415+ return codes .OPERATOR
411416 elif member == "__getitem__" :
412417 # Indexed get.
413418 # TODO: Fix this consistently in format_type
@@ -418,12 +423,14 @@ def has_no_attr(
418423 ),
419424 context ,
420425 )
426+ return None
421427 else :
422428 self .fail (
423429 f"Value of type { format_type (original_type , self .options )} is not indexable" ,
424430 context ,
425431 code = codes .INDEX ,
426432 )
433+ return codes .INDEX
427434 elif member == "__setitem__" :
428435 # Indexed set.
429436 self .fail (
@@ -433,19 +440,22 @@ def has_no_attr(
433440 context ,
434441 code = codes .INDEX ,
435442 )
443+ return codes .INDEX
436444 elif member == "__call__" :
437445 if isinstance (original_type , Instance ) and (
438446 original_type .type .fullname == "builtins.function"
439447 ):
440448 # "'function' not callable" is a confusing error message.
441449 # Explain that the problem is that the type of the function is not known.
442450 self .fail ("Cannot call function of unknown type" , context , code = codes .OPERATOR )
451+ return codes .OPERATOR
443452 else :
444453 self .fail (
445454 message_registry .NOT_CALLABLE .format (format_type (original_type , self .options )),
446455 context ,
447456 code = codes .OPERATOR ,
448457 )
458+ return codes .OPERATOR
449459 else :
450460 # The non-special case: a missing ordinary attribute.
451461 extra = ""
@@ -501,6 +511,7 @@ def has_no_attr(
501511 context ,
502512 code = codes .ATTR_DEFINED ,
503513 )
514+ return codes .ATTR_DEFINED
504515 elif isinstance (original_type , UnionType ):
505516 # The checker passes "object" in lieu of "None" for attribute
506517 # checks, so we manually convert it back.
@@ -518,6 +529,7 @@ def has_no_attr(
518529 context ,
519530 code = codes .UNION_ATTR ,
520531 )
532+ return codes .UNION_ATTR
521533 elif isinstance (original_type , TypeVarType ):
522534 bound = get_proper_type (original_type .upper_bound )
523535 if isinstance (bound , UnionType ):
@@ -531,6 +543,7 @@ def has_no_attr(
531543 context ,
532544 code = codes .UNION_ATTR ,
533545 )
546+ return codes .UNION_ATTR
534547 else :
535548 self .fail (
536549 '{} has no attribute "{}"{}' .format (
@@ -539,7 +552,8 @@ def has_no_attr(
539552 context ,
540553 code = codes .ATTR_DEFINED ,
541554 )
542- return AnyType (TypeOfAny .from_error )
555+ return codes .ATTR_DEFINED
556+ return None
543557
544558 def unsupported_operand_types (
545559 self ,
@@ -1107,8 +1121,8 @@ def unpacking_strings_disallowed(self, context: Context) -> None:
11071121 def type_not_iterable (self , type : Type , context : Context ) -> None :
11081122 self .fail (f"{ format_type (type , self .options )} object is not iterable" , context )
11091123
1110- def possible_missing_await (self , context : Context ) -> None :
1111- self .note ('Maybe you forgot to use "await"?' , context )
1124+ def possible_missing_await (self , context : Context , code : ErrorCode | None ) -> None :
1125+ self .note ('Maybe you forgot to use "await"?' , context , code = code )
11121126
11131127 def incompatible_operator_assignment (self , op : str , context : Context ) -> None :
11141128 self .fail (f"Result type of { op } incompatible in assignment" , context )
0 commit comments