@@ -2320,8 +2320,8 @@ def process_type_annotation(self, s: AssignmentStmt) -> None:
23202320 if isinstance (lvalue .node , Var ):
23212321 lvalue .node .is_abstract_var = True
23222322 else :
2323- if (any ( isinstance ( lv , NameExpr ) and lv . is_inferred_def for lv in s . lvalues ) and
2324- self .type and self . type . is_protocol and not self .is_func_scope ()):
2323+ if (self . type and self . type . is_protocol and
2324+ self .is_annotated_protocol_member ( s ) and not self .is_func_scope ()):
23252325 self .fail ('All protocol members must have explicitly declared types' , s )
23262326 # Set the type if the rvalue is a simple literal (even if the above error occurred).
23272327 if len (s .lvalues ) == 1 and isinstance (s .lvalues [0 ], RefExpr ):
@@ -2332,6 +2332,19 @@ def process_type_annotation(self, s: AssignmentStmt) -> None:
23322332 for lvalue in s .lvalues :
23332333 self .store_declared_types (lvalue , s .type )
23342334
2335+ def is_annotated_protocol_member (self , s : AssignmentStmt ) -> bool :
2336+ """Check whether a protocol member is annotated.
2337+
2338+ There are some exceptions that can be left unannotated, like ``__slots__``."""
2339+ return any (
2340+ (
2341+ isinstance (lv , NameExpr )
2342+ and lv .name != '__slots__'
2343+ and lv .is_inferred_def
2344+ )
2345+ for lv in s .lvalues
2346+ )
2347+
23352348 def analyze_simple_literal_type (self , rvalue : Expression , is_final : bool ) -> Optional [Type ]:
23362349 """Return builtins.int if rvalue is an int literal, etc.
23372350
0 commit comments