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 from6 commits
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
28 changes: 22 additions & 6 deletionsmypy/checkexpr.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -5064,11 +5064,16 @@ def fast_container_type(
Limitations:
- no active type context
- no star expressions
- the joined type of all entries must be an Instance or Tuple type
- not after deferral
- either exactly one distinct type inside,
or the joined type of all entries must be an Instance or Tuple type
"""
ctx = self.type_context[-1]
if ctx:
return None
if self.chk.current_node_deferred:
# Guarantees that all items will be Any, we'll reject it anyway.
return None
rt = self.resolved_type.get(e, None)
if rt is not None:
return rt if isinstance(rt, Instance) else None
Expand All@@ -5078,11 +5083,22 @@ def fast_container_type(
# fallback to slow path
self.resolved_type[e] = NoneType()
return None
values.append(self.accept(item))
vt = join.join_type_list(values)
if not allow_fast_container_literal(vt):
self.resolved_type[e] = NoneType()
return None

typ = self.accept(item)
if typ not in values:
values.append(typ)

if len(values) == 1 and not self.chk.current_node_deferred:
Copy link
Collaborator

@hauntsaninjahauntsaninjaJul 10, 2025
edited
Loading

Choose a reason for hiding this comment

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

second half of clause is now always true. also dumb question: what is the "inference cycle" in the else branch?

Copy link
CollaboratorAuthor

Choose a reason for hiding this comment

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

second half of clause is now always true

Huh, why? We hadself.accept after previous check, it might have changed

what is the "inference cycle" in the else branch

Do you mean what happens when this method returnsNone? We run a full typecheck oncontainer_type.__init__(*args), which is significantly slower than this happy path where all arguments are already "good enough".

# 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
ct = self.chk.named_generic_type(container_fullname, [vt])
self.resolved_type[e] = ct
return ct
Expand Down
3 changes: 3 additions & 0 deletionsmypy/constraints.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -251,6 +251,7 @@ def infer_constraints_for_callable(
)
c = infer_constraints(callee.arg_types[i], actual_type, SUPERTYPE_OF)
constraints.extend(c)

if (
param_spec
and not any(c.type_var == param_spec.id for c in constraints)
Expand All@@ -270,6 +271,8 @@ def infer_constraints_for_callable(
),
)
)

constraints = [c for i, c in enumerate(constraints) if c not in constraints[:i]]
if any(isinstance(v, ParamSpecType) for v in callee.variables):
# As a perf optimization filter imprecise constraints only when we can have them.
constraints = filter_imprecise_kinds(constraints)
Expand Down
10 changes: 5 additions & 5 deletionstest-data/unit/check-generics.test
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2929,8 +2929,8 @@ def mix(fs: List[Callable[[S], T]]) -> Callable[[S], List[T]]:
def id(__x: U) -> U:
...
fs = [id, id, id]
reveal_type(mix(fs)) # N: Revealed type is "def [S] (S`11) -> builtins.list[S`11]"
reveal_type(mix([id, id, id])) # N: Revealed type is "def [S] (S`13) -> builtins.list[S`13]"
reveal_type(mix(fs)) # N: Revealed type is "def [S] (S`2) -> builtins.list[S`2]"
reveal_type(mix([id, id, id])) # N: Revealed type is "def [S] (S`4) -> builtins.list[S`4]"
[builtins fixtures/list.pyi]

[case testInferenceAgainstGenericCurry]
Expand DownExpand Up@@ -3118,11 +3118,11 @@ def dec4_bound(f: Callable[[I], List[T]]) -> Callable[[I], T]:
reveal_type(dec1(lambda x: x)) # N: Revealed type is "def [T] (T`3) -> builtins.list[T`3]"
reveal_type(dec2(lambda x: x)) # N: Revealed type is "def [S] (S`5) -> builtins.list[S`5]"
reveal_type(dec3(lambda x: x[0])) # N: Revealed type is "def [S] (S`8) -> S`8"
reveal_type(dec4(lambda x: [x])) # N: Revealed type is "def [S] (S`12) -> S`12"
reveal_type(dec4(lambda x: [x])) # N: Revealed type is "def [S] (S`11) -> S`11"
reveal_type(dec1(lambda x: 1)) # N: Revealed type is "def (builtins.int) -> builtins.list[builtins.int]"
reveal_type(dec5(lambda x: x)) # N: Revealed type is "def (builtins.int) -> builtins.list[builtins.int]"
reveal_type(dec3(lambda x: x)) # N: Revealed type is "def [S] (S`20) -> builtins.list[S`20]"
reveal_type(dec4(lambda x: x)) # N: Revealed type is "def [T] (builtins.list[T`24]) -> T`24"
reveal_type(dec3(lambda x: x)) # N: Revealed type is "def [S] (S`19) -> builtins.list[S`19]"
reveal_type(dec4(lambda x: x)) # N: Revealed type is "def [T] (builtins.list[T`23]) -> T`23"
dec4_bound(lambda x: x) # E: Value of type variable "I" of "dec4_bound" cannot be "list[T]"
[builtins fixtures/list.pyi]

Expand Down
2 changes: 1 addition & 1 deletiontest-data/unit/check-redefine2.test
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1073,7 +1073,7 @@ def f() -> None:
while int():
x = [x]

reveal_type(x) # N: Revealed type is "Union[Any, builtins.list[Any], builtins.list[Union[Any, builtins.list[Any]]], builtins.list[Union[Any, builtins.list[Any], builtins.list[Union[Any, builtins.list[Any]]]]], builtins.list[Union[Any, builtins.list[Any], builtins.list[Union[Any, builtins.list[Any]]], builtins.list[Union[Any, builtins.list[Any], builtins.list[Union[Any, builtins.list[Any]]]]]]]]"
reveal_type(x) # N: Revealed type is "Union[Any, builtins.list[Any]]"

[case testNewRedefinePartialNoneEmptyList]
# flags: --allow-redefinition-new --local-partial-types
Expand Down
19 changes: 9 additions & 10 deletionstest-data/unit/check-typeddict.test
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1164,22 +1164,21 @@ fc(b) # E: Argument 1 to "fc" has incompatible type "B"; expected "C"
from typing import TypedDict, TypeVar
A = TypedDict('A', {'x': int})
B = TypedDict('B', {'x': int}, total=False)
B2 = TypedDict('B2', {'x': int}, total=False)
C = TypedDict('C', {'x': int, 'y': str}, total=False)
C2 = TypedDict('C2', {'x': int, 'y': str}, total=False)
T = TypeVar('T')
def j(x: T, y: T) -> T: return x
a: A
b: B
b2: B2
c: C
reveal_type(j(a, b)) \
# N: Revealed type is "TypedDict({})"
reveal_type(j(b, b)) \
# N: Revealed type is "TypedDict({'x'?: builtins.int})"
reveal_type(j(c, c)) \
# N: Revealed type is "TypedDict({'x'?: builtins.int, 'y'?: builtins.str})"
reveal_type(j(b, c)) \
# N: Revealed type is "TypedDict({'x'?: builtins.int})"
reveal_type(j(c, b)) \
# N: Revealed type is "TypedDict({'x'?: builtins.int})"
c2: C2
reveal_type(j(a, b)) # N: Revealed type is "TypedDict({})"
reveal_type(j(b, b2)) # N: Revealed type is "TypedDict({'x'?: builtins.int})"
reveal_type(j(c, c2)) # N: Revealed type is "TypedDict({'x'?: builtins.int, 'y'?: builtins.str})"
reveal_type(j(b, c)) # N: Revealed type is "TypedDict({'x'?: builtins.int})"
reveal_type(j(c, b)) # N: Revealed type is "TypedDict({'x'?: builtins.int})"
[builtins fixtures/dict.pyi]
[typing fixtures/typing-typeddict.pyi]

Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp