@@ -190,7 +190,10 @@ def visit_func_def(self, o: FuncDef) -> None:
190
190
self .add_dependency (trigger , target = make_trigger (target ))
191
191
if o .info :
192
192
for base in non_trivial_bases (o .info ):
193
- self .add_dependency (make_trigger (base .fullname () + '.' + o .name ()))
193
+ # Base class __init__/__new__ doesn't generate a logical
194
+ # dependency since the override can be incompatible.
195
+ if not self .use_logical_deps () or o .name () not in ('__init__' , '__new__' ):
196
+ self .add_dependency (make_trigger (base .fullname () + '.' + o .name ()))
194
197
self .add_type_alias_deps (self .scope .current_target ())
195
198
super ().visit_func_def (o )
196
199
variants = set (o .expanded ) - {o }
@@ -295,24 +298,32 @@ def process_type_info(self, info: TypeInfo) -> None:
295
298
# doesn't affect precision of Liskov checking.
296
299
if name not in info .names :
297
300
continue
301
+ # __init__ and __new__ can be overridden with different signatures, so no
302
+ # logical depedency.
303
+ if name in ('__init__' , '__new__' ):
304
+ continue
298
305
self .add_dependency (make_trigger (base_info .fullname () + '.' + name ),
299
306
target = make_trigger (info .fullname () + '.' + name ))
300
- self .add_dependency (make_trigger (base_info .fullname () + '.__init__' ),
301
- target = make_trigger (info .fullname () + '.__init__' ))
302
- self .add_dependency (make_trigger (base_info .fullname () + '.__new__' ),
303
- target = make_trigger (info .fullname () + '.__new__' ))
304
- # If the set of abstract attributes change, this may invalidate class
305
- # instantiation, or change the generated error message, since Python checks
306
- # class abstract status when creating an instance.
307
- #
308
- # TODO: We should probably add this dependency only from the __init__ of the
309
- # current class, and independent of bases (to trigger changes in message
310
- # wording, as errors may enumerate all abstract attributes).
311
- self .add_dependency (make_trigger (base_info .fullname () + '.(abstract)' ),
312
- target = make_trigger (info .fullname () + '.__init__' ))
313
- # If the base class abstract attributes change, subclass abstract
314
- # attributes need to be recalculated.
315
- self .add_dependency (make_trigger (base_info .fullname () + '.(abstract)' ))
307
+ if not self .use_logical_deps ():
308
+ # These dependencies are only useful for propagating changes --
309
+ # they aren't logical dependencies since __init__ and __new__ can be
310
+ # overridden with a different signature.
311
+ self .add_dependency (make_trigger (base_info .fullname () + '.__init__' ),
312
+ target = make_trigger (info .fullname () + '.__init__' ))
313
+ self .add_dependency (make_trigger (base_info .fullname () + '.__new__' ),
314
+ target = make_trigger (info .fullname () + '.__new__' ))
315
+ # If the set of abstract attributes change, this may invalidate class
316
+ # instantiation, or change the generated error message, since Python checks
317
+ # class abstract status when creating an instance.
318
+ #
319
+ # TODO: We should probably add this dependency only from the __init__ of the
320
+ # current class, and independent of bases (to trigger changes in message
321
+ # wording, as errors may enumerate all abstract attributes).
322
+ self .add_dependency (make_trigger (base_info .fullname () + '.(abstract)' ),
323
+ target = make_trigger (info .fullname () + '.__init__' ))
324
+ # If the base class abstract attributes change, subclass abstract
325
+ # attributes need to be recalculated.
326
+ self .add_dependency (make_trigger (base_info .fullname () + '.(abstract)' ))
316
327
317
328
def visit_import (self , o : Import ) -> None :
318
329
for id , as_id in o .ids :
0 commit comments