@@ -623,7 +623,7 @@ def accept_loop(
623623 if on_enter_body is not None :
624624 on_enter_body ()
625625
626- with IterationErrorWatcher (self .msg .errors , iter_errors ) as watcher :
626+ with IterationErrorWatcher (self .msg .errors , iter_errors ):
627627 self .accept (body )
628628
629629 partials_new = sum (len (pts .map ) for pts in self .partial_types )
@@ -646,10 +646,7 @@ def accept_loop(
646646 if iter == 20 :
647647 raise RuntimeError ("Too many iterations when checking a loop" )
648648
649- for error_info in watcher .yield_error_infos ():
650- self .msg .fail (* error_info [:2 ], code = error_info [2 ])
651- for note_info in watcher .yield_note_infos (self .options ):
652- self .note (* note_info )
649+ self .msg .iteration_dependent_errors (iter_errors )
653650
654651 # If exit_condition is set, assume it must be False on exit from the loop:
655652 if exit_condition :
@@ -2964,7 +2961,11 @@ def check_metaclass_compatibility(self, typ: TypeInfo) -> None:
29642961 "Metaclass conflict: the metaclass of a derived class must be "
29652962 "a (non-strict) subclass of the metaclasses of all its bases" ,
29662963 typ ,
2964+ code = codes .METACLASS ,
29672965 )
2966+ explanation = typ .explain_metaclass_conflict ()
2967+ if explanation :
2968+ self .note (explanation , typ , code = codes .METACLASS )
29682969
29692970 def visit_import_from (self , node : ImportFrom ) -> None :
29702971 for name , _ in node .names :
@@ -3042,7 +3043,7 @@ def is_noop_for_reachability(self, s: Statement) -> bool:
30423043 if isinstance (s .expr , EllipsisExpr ):
30433044 return True
30443045 elif isinstance (s .expr , CallExpr ):
3045- with self .expr_checker .msg .filter_errors ():
3046+ with self .expr_checker .msg .filter_errors (filter_revealed_type = True ):
30463047 typ = get_proper_type (
30473048 self .expr_checker .accept (
30483049 s .expr , allow_none_return = True , always_allow_any = True
@@ -3142,7 +3143,7 @@ def check_assignment(
31423143 else :
31433144 self .check_getattr_method (signature , lvalue , name )
31443145
3145- if name == "__slots__" :
3146+ if name == "__slots__" and self . scope . active_class () is not None :
31463147 typ = lvalue_type or self .expr_checker .accept (rvalue )
31473148 self .check_slots_definition (typ , lvalue )
31483149 if name == "__match_args__" and inferred is not None :
@@ -3321,6 +3322,12 @@ def get_variable_type_context(self, inferred: Var, rvalue: Expression) -> Type |
33213322 type_contexts .append (base_type )
33223323 # Use most derived supertype as type context if available.
33233324 if not type_contexts :
3325+ if inferred .name == "__slots__" and self .scope .active_class () is not None :
3326+ str_type = self .named_type ("builtins.str" )
3327+ return self .named_generic_type ("typing.Iterable" , [str_type ])
3328+ if inferred .name == "__all__" and self .scope .is_top_level ():
3329+ str_type = self .named_type ("builtins.str" )
3330+ return self .named_generic_type ("typing.Sequence" , [str_type ])
33243331 return None
33253332 candidate = type_contexts [0 ]
33263333 for other in type_contexts :
@@ -4970,7 +4977,7 @@ def visit_try_stmt(self, s: TryStmt) -> None:
49704977 if s .finally_body :
49714978 # First we check finally_body is type safe on all abnormal exit paths
49724979 iter_errors = IterationDependentErrors ()
4973- with IterationErrorWatcher (self .msg .errors , iter_errors ) as watcher :
4980+ with IterationErrorWatcher (self .msg .errors , iter_errors ):
49744981 self .accept (s .finally_body )
49754982
49764983 if s .finally_body :
@@ -4987,13 +4994,9 @@ def visit_try_stmt(self, s: TryStmt) -> None:
49874994 # that follows the try statement.)
49884995 assert iter_errors is not None
49894996 if not self .binder .is_unreachable ():
4990- with IterationErrorWatcher (self .msg .errors , iter_errors ) as watcher :
4997+ with IterationErrorWatcher (self .msg .errors , iter_errors ):
49914998 self .accept (s .finally_body )
4992-
4993- for error_info in watcher .yield_error_infos ():
4994- self .msg .fail (* error_info [:2 ], code = error_info [2 ])
4995- for note_info in watcher .yield_note_infos (self .options ):
4996- self .msg .note (* note_info )
4999+ self .msg .iteration_dependent_errors (iter_errors )
49975000
49985001 def visit_try_without_finally (self , s : TryStmt , try_frame : bool ) -> None :
49995002 """Type check a try statement, ignoring the finally block.
@@ -7303,7 +7306,7 @@ def named_type(self, name: str) -> Instance:
73037306 if isinstance (node , TypeAlias ):
73047307 assert isinstance (node .target , Instance ) # type: ignore[misc]
73057308 node = node .target .type
7306- assert isinstance (node , TypeInfo )
7309+ assert isinstance (node , TypeInfo ), node
73077310 any_type = AnyType (TypeOfAny .from_omitted_generics )
73087311 return Instance (node , [any_type ] * len (node .defn .type_vars ))
73097312
@@ -7322,7 +7325,7 @@ def lookup_typeinfo(self, fullname: str) -> TypeInfo:
73227325 # Assume that the name refers to a class.
73237326 sym = self .lookup_qualified (fullname )
73247327 node = sym .node
7325- assert isinstance (node , TypeInfo )
7328+ assert isinstance (node , TypeInfo ), node
73267329 return node
73277330
73287331 def type_type (self ) -> Instance :
@@ -7913,6 +7916,9 @@ def has_valid_attribute(self, typ: Type, name: str) -> bool:
79137916 def get_expression_type (self , node : Expression , type_context : Type | None = None ) -> Type :
79147917 return self .expr_checker .accept (node , type_context = type_context )
79157918
7919+ def is_defined_in_stub (self , typ : Instance , / ) -> bool :
7920+ return self .modules [typ .type .module_name ].is_stub
7921+
79167922 def check_deprecated (self , node : Node | None , context : Context ) -> None :
79177923 """Warn if deprecated and not directly imported with a `from` statement."""
79187924 if isinstance (node , Decorator ):
0 commit comments