Skip to content

Commit 0f560b3

Browse files
committed
Avoid quadratic deduplication
1 parent 8882c80 commit 0f560b3

File tree

1 file changed

+20
-7
lines changed

1 file changed

+20
-7
lines changed

mypy/checkexpr.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5066,14 +5066,16 @@ def fast_container_type(
50665066
module-level constant definitions.
50675067
50685068
Limitations:
5069+
50695070
- no active type context
5071+
- at least one item
50705072
- no star expressions
50715073
- not after deferral
50725074
- either exactly one distinct type inside,
5073-
or the joined type of all entries must be an Instance or Tuple type
5075+
or the joined type of all entries is an Instance or Tuple type,
50745076
"""
50755077
ctx = self.type_context[-1]
5076-
if ctx:
5078+
if ctx or not e.items:
50775079
return None
50785080
if self.chk.current_node_deferred:
50795081
# Guarantees that all items will be Any, we'll reject it anyway.
@@ -5082,15 +5084,18 @@ def fast_container_type(
50825084
if rt is not None:
50835085
return rt if isinstance(rt, Instance) else None
50845086
values: list[Type] = []
5087+
# Preserve join order while avoiding O(n) lookups at every iteration
5088+
values_set: set[Type] = set()
50855089
for item in e.items:
50865090
if isinstance(item, StarExpr):
50875091
# fallback to slow path
50885092
self.resolved_type[e] = NoneType()
50895093
return None
50905094

50915095
typ = self.accept(item)
5092-
if typ not in values:
5096+
if typ not in values_set:
50935097
values.append(typ)
5098+
values_set.add(typ)
50945099

50955100
vt = self._first_or_join_fast_item(values)
50965101
if vt is None:
@@ -5268,12 +5273,15 @@ def fast_dict_type(self, e: DictExpr) -> Type | None:
52685273
module-level constant definitions.
52695274
52705275
Limitations:
5276+
52715277
- no active type context
5278+
- at least one item
52725279
- only supported star expressions are other dict instances
5273-
- the joined types of all keys and values must be Instance or Tuple types
5280+
- either exactly one distinct type (keys and values separately) inside,
5281+
or the joined type of all entries is an Instance or Tuple type
52745282
"""
52755283
ctx = self.type_context[-1]
5276-
if ctx:
5284+
if ctx or not e.items:
52775285
return None
52785286

52795287
if self.chk.current_node_deferred:
@@ -5286,6 +5294,9 @@ def fast_dict_type(self, e: DictExpr) -> Type | None:
52865294

52875295
keys: list[Type] = []
52885296
values: list[Type] = []
5297+
# Preserve join order while avoiding O(n) lookups at every iteration
5298+
keys_set: set[Type] = set()
5299+
values_set: set[Type] = set()
52895300
stargs: tuple[Type, Type] | None = None
52905301
for key, value in e.items:
52915302
if key is None:
@@ -5301,11 +5312,13 @@ def fast_dict_type(self, e: DictExpr) -> Type | None:
53015312
return None
53025313
else:
53035314
key_t = self.accept(key)
5304-
if key_t not in keys:
5315+
if key_t not in keys_set:
53055316
keys.append(key_t)
5317+
keys_set.add(key_t)
53065318
value_t = self.accept(value)
5307-
if value_t not in values:
5319+
if value_t not in values_set:
53085320
values.append(value_t)
5321+
values_set.add(value_t)
53095322

53105323
kt = self._first_or_join_fast_item(keys)
53115324
if kt is None:

0 commit comments

Comments
 (0)