@@ -93,11 +93,12 @@ def __init__(
9393 original_type : Type ,
9494 context : Context ,
9595 chk : mypy .checker .TypeChecker ,
96- self_type : Type | None ,
96+ self_type : Type | None = None ,
9797 module_symbol_table : SymbolTable | None = None ,
9898 no_deferral : bool = False ,
9999 is_self : bool = False ,
100100 rvalue : Expression | None = None ,
101+ suppress_errors : bool = False ,
101102 ) -> None :
102103 self .is_lvalue = is_lvalue
103104 self .is_super = is_super
@@ -113,13 +114,18 @@ def __init__(
113114 if rvalue is not None :
114115 assert is_lvalue
115116 self .rvalue = rvalue
117+ self .suppress_errors = suppress_errors
116118
117119 def named_type (self , name : str ) -> Instance :
118120 return self .chk .named_type (name )
119121
120122 def not_ready_callback (self , name : str , context : Context ) -> None :
121123 self .chk .handle_cannot_determine_type (name , context )
122124
125+ def fail (self , msg : str ) -> None :
126+ if not self .suppress_errors :
127+ self .msg .fail (msg , self .context )
128+
123129 def copy_modified (
124130 self ,
125131 * ,
@@ -138,6 +144,7 @@ def copy_modified(
138144 module_symbol_table = self .module_symbol_table ,
139145 no_deferral = self .no_deferral ,
140146 rvalue = self .rvalue ,
147+ suppress_errors = self .suppress_errors ,
141148 )
142149 if self_type is not None :
143150 mx .self_type = self_type
@@ -165,6 +172,7 @@ def analyze_member_access(
165172 no_deferral : bool = False ,
166173 is_self : bool = False ,
167174 rvalue : Expression | None = None ,
175+ suppress_errors : bool = False ,
168176) -> Type :
169177 """Return the type of attribute 'name' of 'typ'.
170178
@@ -191,6 +199,11 @@ def analyze_member_access(
191199
192200 'rvalue' can be provided optionally to infer better setter type when is_lvalue is True,
193201 most notably this helps for descriptors with overloaded __set__() method.
202+
203+ 'suppress_errors' will skip any logic that is only needed to generate error messages.
204+ Note that this more of a performance optimization, one should not rely on this to not
205+ show any messages, as some may be show e.g. by callbacks called here,
206+ use msg.filter_errors(), if needed.
194207 """
195208 mx = MemberContext (
196209 is_lvalue = is_lvalue ,
@@ -204,6 +217,7 @@ def analyze_member_access(
204217 no_deferral = no_deferral ,
205218 is_self = is_self ,
206219 rvalue = rvalue ,
220+ suppress_errors = suppress_errors ,
207221 )
208222 result = _analyze_member_access (name , typ , mx , override_info )
209223 possible_literal = get_proper_type (result )
@@ -251,7 +265,8 @@ def _analyze_member_access(
251265 )
252266 return _analyze_member_access (name , typ .upper_bound , mx , override_info )
253267 elif isinstance (typ , DeletedType ):
254- mx .msg .deleted_as_rvalue (typ , mx .context )
268+ if not mx .suppress_errors :
269+ mx .msg .deleted_as_rvalue (typ , mx .context )
255270 return AnyType (TypeOfAny .from_error )
256271 return report_missing_attribute (mx .original_type , typ , name , mx )
257272
@@ -280,6 +295,8 @@ def report_missing_attribute(
280295 mx : MemberContext ,
281296 override_info : TypeInfo | None = None ,
282297) -> Type :
298+ if mx .suppress_errors :
299+ return AnyType (TypeOfAny .from_error )
283300 error_code = mx .msg .has_no_attr (original_type , typ , name , mx .context , mx .module_symbol_table )
284301 if not mx .msg .prefer_simple_messages ():
285302 if may_be_awaitable_attribute (name , typ , mx , override_info ):
@@ -297,7 +314,7 @@ def analyze_instance_member_access(
297314 if name == "__init__" and not mx .is_super :
298315 # Accessing __init__ in statically typed code would compromise
299316 # type safety unless used via super().
300- mx .msg . fail (message_registry .CANNOT_ACCESS_INIT , mx . context )
317+ mx .fail (message_registry .CANNOT_ACCESS_INIT )
301318 return AnyType (TypeOfAny .from_error )
302319
303320 # The base object has an instance type.
@@ -310,13 +327,14 @@ def analyze_instance_member_access(
310327 state .find_occurrences
311328 and info .name == state .find_occurrences [0 ]
312329 and name == state .find_occurrences [1 ]
330+ and not mx .suppress_errors
313331 ):
314332 mx .msg .note ("Occurrence of '{}.{}'" .format (* state .find_occurrences ), mx .context )
315333
316334 # Look up the member. First look up the method dictionary.
317335 method = info .get_method (name )
318336 if method and not isinstance (method , Decorator ):
319- if mx .is_super :
337+ if mx .is_super and not mx . suppress_errors :
320338 validate_super_call (method , mx )
321339
322340 if method .is_property :
@@ -327,7 +345,7 @@ def analyze_instance_member_access(
327345 mx .chk .warn_deprecated (items [1 ], mx .context )
328346 return analyze_var (name , getter .var , typ , mx )
329347
330- if mx .is_lvalue :
348+ if mx .is_lvalue and not mx . suppress_errors :
331349 mx .msg .cant_assign_to_method (mx .context )
332350 if not isinstance (method , OverloadedFuncDef ):
333351 signature = function_type (method , mx .named_type ("builtins.function" ))
@@ -361,7 +379,6 @@ def validate_super_call(node: FuncBase, mx: MemberContext) -> None:
361379 unsafe_super = False
362380 if isinstance (node , FuncDef ) and node .is_trivial_body :
363381 unsafe_super = True
364- impl = node
365382 elif isinstance (node , OverloadedFuncDef ):
366383 if node .impl :
367384 impl = node .impl if isinstance (node .impl , FuncDef ) else node .impl .func
@@ -505,7 +522,7 @@ def analyze_member_var_access(
505522 if isinstance (vv , Decorator ):
506523 # The associated Var node of a decorator contains the type.
507524 v = vv .var
508- if mx .is_super :
525+ if mx .is_super and not mx . suppress_errors :
509526 validate_super_call (vv .func , mx )
510527
511528 if isinstance (vv , TypeInfo ):
@@ -603,7 +620,7 @@ def analyze_member_var_access(
603620 if not itype .extra_attrs .mod_name :
604621 return itype .extra_attrs .attrs [name ]
605622
606- if mx .is_super :
623+ if mx .is_super and not mx . suppress_errors :
607624 mx .msg .undefined_in_superclass (name , mx .context )
608625 return AnyType (TypeOfAny .from_error )
609626 else :
@@ -669,11 +686,10 @@ def analyze_descriptor_access(descriptor_type: Type, mx: MemberContext) -> Type:
669686
670687 dunder_get = descriptor_type .type .get_method ("__get__" )
671688 if dunder_get is None :
672- mx .msg . fail (
689+ mx .fail (
673690 message_registry .DESCRIPTOR_GET_NOT_CALLABLE .format (
674691 descriptor_type .str_with_options (mx .msg .options )
675- ),
676- mx .context ,
692+ )
677693 )
678694 return AnyType (TypeOfAny .from_error )
679695
@@ -732,11 +748,10 @@ def analyze_descriptor_access(descriptor_type: Type, mx: MemberContext) -> Type:
732748 return inferred_dunder_get_type
733749
734750 if not isinstance (inferred_dunder_get_type , CallableType ):
735- mx .msg . fail (
751+ mx .fail (
736752 message_registry .DESCRIPTOR_GET_NOT_CALLABLE .format (
737753 descriptor_type .str_with_options (mx .msg .options )
738- ),
739- mx .context ,
754+ )
740755 )
741756 return AnyType (TypeOfAny .from_error )
742757
@@ -747,11 +762,10 @@ def analyze_descriptor_assign(descriptor_type: Instance, mx: MemberContext) -> T
747762 instance_type = get_proper_type (mx .self_type )
748763 dunder_set = descriptor_type .type .get_method ("__set__" )
749764 if dunder_set is None :
750- mx .chk . fail (
765+ mx .fail (
751766 message_registry .DESCRIPTOR_SET_NOT_CALLABLE .format (
752767 descriptor_type .str_with_options (mx .msg .options )
753- ),
754- mx .context ,
768+ ).value
755769 )
756770 return AnyType (TypeOfAny .from_error )
757771
@@ -851,11 +865,11 @@ def analyze_var(
851865 if typ :
852866 if isinstance (typ , PartialType ):
853867 return mx .chk .handle_partial_var_type (typ , mx .is_lvalue , var , mx .context )
854- if mx .is_lvalue and var . is_property and not var . is_settable_property :
855- # TODO allow setting attributes in subclass (although it is probably an error)
856- mx .msg .read_only_property (name , itype .type , mx .context )
857- if mx . is_lvalue and var .is_classvar :
858- mx .msg .cant_assign_to_classvar (name , mx .context )
868+ if mx .is_lvalue and not mx . suppress_errors :
869+ if var . is_property and not var . is_settable_property :
870+ mx .msg .read_only_property (name , itype .type , mx .context )
871+ if var .is_classvar :
872+ mx .msg .cant_assign_to_classvar (name , mx .context )
859873 t = freshen_all_functions_type_vars (typ )
860874 t = expand_self_type_if_needed (t , mx , var , original_itype )
861875 t = expand_type_by_instance (t , itype )
@@ -875,11 +889,10 @@ def analyze_var(
875889 call_type = typ
876890
877891 if isinstance (call_type , FunctionLike ) and not call_type .is_type_obj ():
878- if mx .is_lvalue :
879- if var .is_property :
880- if not var .is_settable_property :
881- mx .msg .read_only_property (name , itype .type , mx .context )
882- else :
892+ if mx .is_lvalue and not mx .suppress_errors :
893+ if var .is_property and not var .is_settable_property :
894+ mx .msg .read_only_property (name , itype .type , mx .context )
895+ elif not var .is_property :
883896 mx .msg .cant_assign_to_method (mx .context )
884897
885898 if not var .is_staticmethod :
@@ -1073,22 +1086,20 @@ def analyze_class_attribute_access(
10731086
10741087 is_decorated = isinstance (node .node , Decorator )
10751088 is_method = is_decorated or isinstance (node .node , FuncBase )
1076- if mx .is_lvalue :
1089+ if mx .is_lvalue and not mx . suppress_errors :
10771090 if is_method :
10781091 mx .msg .cant_assign_to_method (mx .context )
10791092 if isinstance (node .node , TypeInfo ):
1080- mx .msg . fail (message_registry .CANNOT_ASSIGN_TO_TYPE , mx . context )
1093+ mx .fail (message_registry .CANNOT_ASSIGN_TO_TYPE )
10811094
10821095 # Refuse class attribute access if slot defined
10831096 if info .slots and name in info .slots :
1084- mx .msg . fail (message_registry .CLASS_VAR_CONFLICTS_SLOTS .format (name ), mx . context )
1097+ mx .fail (message_registry .CLASS_VAR_CONFLICTS_SLOTS .format (name ))
10851098
10861099 # If a final attribute was declared on `self` in `__init__`, then it
10871100 # can't be accessed on the class object.
10881101 if node .implicit and isinstance (node .node , Var ) and node .node .is_final :
1089- mx .msg .fail (
1090- message_registry .CANNOT_ACCESS_FINAL_INSTANCE_ATTR .format (node .node .name ), mx .context
1091- )
1102+ mx .fail (message_registry .CANNOT_ACCESS_FINAL_INSTANCE_ATTR .format (node .node .name ))
10921103
10931104 # An assignment to final attribute on class object is also always an error,
10941105 # independently of types.
@@ -1146,7 +1157,7 @@ def analyze_class_attribute_access(
11461157 message = message_registry .GENERIC_CLASS_VAR_ACCESS
11471158 else :
11481159 message = message_registry .GENERIC_INSTANCE_VAR_CLASS_ACCESS
1149- mx .msg . fail (message , mx . context )
1160+ mx .fail (message )
11501161 t = expand_self_type_if_needed (t , mx , node .node , itype , is_class = True )
11511162 # Erase non-mapped variables, but keep mapped ones, even if there is an error.
11521163 # In the above example this means that we infer following types:
@@ -1176,9 +1187,7 @@ def analyze_class_attribute_access(
11761187 return AnyType (TypeOfAny .special_form )
11771188
11781189 if isinstance (node .node , TypeVarExpr ):
1179- mx .msg .fail (
1180- message_registry .CANNOT_USE_TYPEVAR_AS_EXPRESSION .format (info .name , name ), mx .context
1181- )
1190+ mx .fail (message_registry .CANNOT_USE_TYPEVAR_AS_EXPRESSION .format (info .name , name ))
11821191 return AnyType (TypeOfAny .from_error )
11831192
11841193 # TODO: some logic below duplicates analyze_ref_expr in checkexpr.py
@@ -1267,7 +1276,7 @@ def analyze_typeddict_access(
12671276 typ , mx .context .index , setitem = True
12681277 )
12691278 assigned_readonly_keys = typ .readonly_keys & key_names
1270- if assigned_readonly_keys :
1279+ if assigned_readonly_keys and not mx . suppress_errors :
12711280 mx .msg .readonly_keys_mutated (assigned_readonly_keys , context = mx .context )
12721281 else :
12731282 # It can also be `a.__setitem__(...)` direct call.
0 commit comments