@@ -2320,8 +2320,8 @@ def process_type_annotation(self, s: AssignmentStmt) -> None:
2320
2320
if isinstance (lvalue .node , Var ):
2321
2321
lvalue .node .is_abstract_var = True
2322
2322
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 ()):
2325
2325
self .fail ('All protocol members must have explicitly declared types' , s )
2326
2326
# Set the type if the rvalue is a simple literal (even if the above error occurred).
2327
2327
if len (s .lvalues ) == 1 and isinstance (s .lvalues [0 ], RefExpr ):
@@ -2332,6 +2332,19 @@ def process_type_annotation(self, s: AssignmentStmt) -> None:
2332
2332
for lvalue in s .lvalues :
2333
2333
self .store_declared_types (lvalue , s .type )
2334
2334
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
+
2335
2348
def analyze_simple_literal_type (self , rvalue : Expression , is_final : bool ) -> Optional [Type ]:
2336
2349
"""Return builtins.int if rvalue is an int literal, etc.
2337
2350
0 commit comments