Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

perf: deduplicatefast_container_type andfast_dict_type items before joining#19409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from1 commit
Commits
Show all changes
14 commits
Select commitHold shift + click to select a range
2f2c391
Only do this for collection literals
sterliakovJul 8, 2025
48cb9e1
Sync tests
sterliakovJul 8, 2025
19f0260
Fix interaction with deferrals
sterliakovJul 10, 2025
7d9dcb6
Merge branch 'master' into feature/st-deduplicate-join-list
sterliakovJul 10, 2025
0cc75eb
Deduplicate constraints before solving
sterliakovJul 10, 2025
48bc430
Sync test
sterliakovJul 10, 2025
ff26ebf
Use hash-based deduplication for constraints
sterliakovJul 10, 2025
b608a66
Revert constraint deduplication
sterliakovJul 18, 2025
46f7825
Merge remote-tracking branch 'upstream/master' into feature/st-dedupl…
sterliakovJul 18, 2025
3aa9472
Apply same treatment to dict literals
sterliakovJul 18, 2025
8882c80
Return early for dict if already deferred
sterliakovJul 28, 2025
0f560b3
Avoid quadratic deduplication
sterliakovJul 29, 2025
c2fd9fa
Add a todo
sterliakovJul 29, 2025
af92439
Merge remote-tracking branch 'upstream/master' into feature/st-dedupl…
sterliakovJul 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
PrevPrevious commit
NextNext commit
Apply same treatment to dict literals
  • Loading branch information
@sterliakov
sterliakov committedJul 18, 2025
commit3aa947215415700fbe270cec6e71973e2c28e8fe
43 changes: 27 additions & 16 deletionsmypy/checkexpr.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -5092,21 +5092,22 @@ def fast_container_type(
if typ not in values:
values.append(typ)

if len(values) == 1 and not self.chk.current_node_deferred:
# If only one non-duplicate item remains, there's no need to run the whole
# inference cycle over it. This helps in pathological cases where items
# are complex overloads.
# https://github.com/python/mypy/issues/14718
vt = values[0]
else:
vt = join.join_type_list(values)
if not allow_fast_container_literal(vt):
self.resolved_type[e] = NoneType()
return None
vt = self._first_or_join_fast_item(values)
if vt is None:
self.resolved_type[e] = NoneType()
return None
ct = self.chk.named_generic_type(container_fullname, [vt])
self.resolved_type[e] = ct
return ct

def _first_or_join_fast_item(self, items: list[Type]) -> Type | None:
if len(items) == 1 and not self.chk.current_node_deferred:
return items[0]
typ = join.join_type_list(items)
if not allow_fast_container_literal(typ):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This feels a bit restrictive together with the aboveif. For example, if there is more than one callable type (like in the original example in the issue) this will not apply. Should we also proceed with fast path if each expression is aRefExpr (so that its type doesn't depend on the context).

Copy link
CollaboratorAuthor

@sterliakovsterliakovJul 29, 2025
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

We could, but our join implementation for callables is horribly broken, so this will produce invalid results: e.g. we can confidently join two callables with named args with different names into one of them.

defleft(*,x:str): ...defright(*,y:str): ...

thenjoin(left, right) isdef (*, y: str).

I'm not sure if there are other similarly terrifying bugs there, so I'd really prefer to not expand this logic now. This is not related to expression source ([left, right] contains toRefExprs). I added a relevant todo here.

mypy/mypy/join.py

Lines 797 to 803 in2996c91

defcombine_similar_callables(t:CallableType,s:CallableType)->CallableType:
t,s=match_generic_callables(t,s)
arg_types:list[Type]= []
foriinrange(len(t.arg_types)):
arg_types.append(safe_join(t.arg_types[i],s.arg_types[i]))
# TODO kinds and argument names

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

OK, I see, makes sense.

return None
return typ

def check_lst_expr(self, e: ListExpr | SetExpr | TupleExpr, fullname: str, tag: str) -> Type:
# fast path
t = self.fast_container_type(e, fullname)
Expand DownExpand Up@@ -5293,13 +5294,23 @@ def fast_dict_type(self, e: DictExpr) -> Type | None:
self.resolved_type[e] = NoneType()
return None
else:
keys.append(self.accept(key))
values.append(self.accept(value))
kt = join.join_type_list(keys)
vt = join.join_type_list(values)
if not (allow_fast_container_literal(kt) and allow_fast_container_literal(vt)):
key_t = self.accept(key)
if key_t not in keys:
keys.append(key_t)
value_t = self.accept(value)
if value_t not in values:
values.append(value_t)

kt = self._first_or_join_fast_item(keys)
if kt is None:
self.resolved_type[e] = NoneType()
return None

vt = self._first_or_join_fast_item(values)
if vt is None:
self.resolved_type[e] = NoneType()
return None

if stargs and (stargs[0] != kt or stargs[1] != vt):
self.resolved_type[e] = NoneType()
return None
Expand Down
2 changes: 1 addition & 1 deletiontest-data/unit/check-selftype.test
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2018,7 +2018,7 @@ class Ben(Object):
}
@classmethod
def doit(cls) -> Foo:
reveal_type(cls.MY_MAP) # N: Revealed type is "builtins.dict[builtins.str, def [Self <: __main__.Foo] (self: Self`4) -> Self`4]"
reveal_type(cls.MY_MAP) # N: Revealed type is "builtins.dict[builtins.str, def [Self <: __main__.Foo] (self: Self`1) -> Self`1]"
foo_method = cls.MY_MAP["foo"]
return foo_method(Foo())
[builtins fixtures/isinstancelist.pyi]
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp