1212from mypy .server .trigger import make_trigger
1313from mypy .types import Instance , Type , TypeVarId , get_proper_type
1414
15+ MAX_NEGATIVE_CACHE_TYPES : Final = 1000
16+ MAX_NEGATIVE_CACHE_ENTRIES : Final = 10000
17+
1518# Represents that the 'left' instance is a subtype of the 'right' instance
1619SubtypeRelationship : _TypeAlias = Tuple [Instance , Instance ]
1720
@@ -42,6 +45,9 @@ class TypeState:
4245 # We need the caches, since subtype checks for structural types are very slow.
4346 _subtype_caches : Final [SubtypeCache ]
4447
48+ # Same as above but for negative subtyping results.
49+ _negative_subtype_caches : Final [SubtypeCache ]
50+
4551 # This contains protocol dependencies generated after running a full build,
4652 # or after an update. These dependencies are special because:
4753 # * They are a global property of the program; i.e. some dependencies for imported
@@ -95,6 +101,7 @@ class TypeState:
95101
96102 def __init__ (self ) -> None :
97103 self ._subtype_caches = {}
104+ self ._negative_subtype_caches = {}
98105 self .proto_deps = {}
99106 self ._attempted_protocols = {}
100107 self ._checked_against_members = {}
@@ -128,11 +135,14 @@ def get_assumptions(self, is_proper: bool) -> list[tuple[Type, Type]]:
128135 def reset_all_subtype_caches (self ) -> None :
129136 """Completely reset all known subtype caches."""
130137 self ._subtype_caches .clear ()
138+ self ._negative_subtype_caches .clear ()
131139
132140 def reset_subtype_caches_for (self , info : TypeInfo ) -> None :
133141 """Reset subtype caches (if any) for a given supertype TypeInfo."""
134142 if info in self ._subtype_caches :
135143 self ._subtype_caches [info ].clear ()
144+ if info in self ._negative_subtype_caches :
145+ self ._negative_subtype_caches [info ].clear ()
136146
137147 def reset_all_subtype_caches_for (self , info : TypeInfo ) -> None :
138148 """Reset subtype caches (if any) for a given supertype TypeInfo and its MRO."""
@@ -154,6 +164,23 @@ def is_cached_subtype_check(self, kind: SubtypeKind, left: Instance, right: Inst
154164 return False
155165 return (left , right ) in subcache
156166
167+ def is_cached_negative_subtype_check (
168+ self , kind : SubtypeKind , left : Instance , right : Instance
169+ ) -> bool :
170+ if left .last_known_value is not None or right .last_known_value is not None :
171+ # If there is a literal last known value, give up. There
172+ # will be an unbounded number of potential types to cache,
173+ # making caching less effective.
174+ return False
175+ info = right .type
176+ cache = self ._negative_subtype_caches .get (info )
177+ if cache is None :
178+ return False
179+ subcache = cache .get (kind )
180+ if subcache is None :
181+ return False
182+ return (left , right ) in subcache
183+
157184 def record_subtype_cache_entry (
158185 self , kind : SubtypeKind , left : Instance , right : Instance
159186 ) -> None :
@@ -164,6 +191,21 @@ def record_subtype_cache_entry(
164191 cache = self ._subtype_caches .setdefault (right .type , dict ())
165192 cache .setdefault (kind , set ()).add ((left , right ))
166193
194+ def record_negative_subtype_cache_entry (
195+ self , kind : SubtypeKind , left : Instance , right : Instance
196+ ) -> None :
197+ if left .last_known_value is not None or right .last_known_value is not None :
198+ # These are unlikely to match, due to the large space of
199+ # possible values. Avoid uselessly increasing cache sizes.
200+ return
201+ if len (self ._negative_subtype_caches ) > MAX_NEGATIVE_CACHE_TYPES :
202+ self ._negative_subtype_caches .clear ()
203+ cache = self ._negative_subtype_caches .setdefault (right .type , dict ())
204+ subcache = cache .setdefault (kind , set ())
205+ if len (subcache ) > MAX_NEGATIVE_CACHE_ENTRIES :
206+ subcache .clear ()
207+ cache .setdefault (kind , set ()).add ((left , right ))
208+
167209 def reset_protocol_deps (self ) -> None :
168210 """Reset dependencies after a full run or before a daemon shutdown."""
169211 self .proto_deps = {}
0 commit comments