Skip to content

Commit f09d531

Browse files
Merge branch 'master' into unwrap-new-types
2 parents 583ac2a + c53367f commit f09d531

File tree

4 files changed

+69
-20
lines changed

4 files changed

+69
-20
lines changed

mypy/checkexpr.py

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5069,31 +5069,56 @@ def fast_container_type(
50695069
module-level constant definitions.
50705070
50715071
Limitations:
5072+
50725073
- no active type context
5074+
- at least one item
50735075
- no star expressions
5074-
- the joined type of all entries must be an Instance or Tuple type
5076+
- not after deferral
5077+
- either exactly one distinct type inside,
5078+
or the joined type of all entries is an Instance or Tuple type,
50755079
"""
50765080
ctx = self.type_context[-1]
5077-
if ctx:
5081+
if ctx or not e.items:
5082+
return None
5083+
if self.chk.current_node_deferred:
5084+
# Guarantees that all items will be Any, we'll reject it anyway.
50785085
return None
50795086
rt = self.resolved_type.get(e, None)
50805087
if rt is not None:
50815088
return rt if isinstance(rt, Instance) else None
50825089
values: list[Type] = []
5090+
# Preserve join order while avoiding O(n) lookups at every iteration
5091+
values_set: set[Type] = set()
50835092
for item in e.items:
50845093
if isinstance(item, StarExpr):
50855094
# fallback to slow path
50865095
self.resolved_type[e] = NoneType()
50875096
return None
5088-
values.append(self.accept(item))
5089-
vt = join.join_type_list(values)
5090-
if not allow_fast_container_literal(vt):
5097+
5098+
typ = self.accept(item)
5099+
if typ not in values_set:
5100+
values.append(typ)
5101+
values_set.add(typ)
5102+
5103+
vt = self._first_or_join_fast_item(values)
5104+
if vt is None:
50915105
self.resolved_type[e] = NoneType()
50925106
return None
50935107
ct = self.chk.named_generic_type(container_fullname, [vt])
50945108
self.resolved_type[e] = ct
50955109
return ct
50965110

5111+
def _first_or_join_fast_item(self, items: list[Type]) -> Type | None:
5112+
if len(items) == 1 and not self.chk.current_node_deferred:
5113+
return items[0]
5114+
typ = join.join_type_list(items)
5115+
if not allow_fast_container_literal(typ):
5116+
# TODO: This is overly strict, many other types can be joined safely here.
5117+
# However, our join implementation isn't bug-free, and some joins may produce
5118+
# undesired `Any`s or even more surprising results.
5119+
return None
5120+
return typ
5121+
50975122
def check_lst_expr(self, e: ListExpr | SetExpr | TupleExpr, fullname: str, tag: str) -> Type:
50985123
# fast path
50995124
t = self.fast_container_type(e, fullname)
@@ -5254,18 +5279,30 @@ def fast_dict_type(self, e: DictExpr) -> Type | None:
52545279
module-level constant definitions.
52555280
52565281
Limitations:
5282+
52575283
- no active type context
5284+
- at least one item
52585285
- only supported star expressions are other dict instances
5259-
- the joined types of all keys and values must be Instance or Tuple types
5286+
- either exactly one distinct type (keys and values separately) inside,
5287+
or the joined type of all entries is an Instance or Tuple type
52605288
"""
52615289
ctx = self.type_context[-1]
5262-
if ctx:
5290+
if ctx or not e.items:
52635291
return None
5292+
5293+
if self.chk.current_node_deferred:
5294+
# Guarantees that all items will be Any, we'll reject it anyway.
5295+
return None
5296+
52645297
rt = self.resolved_type.get(e, None)
52655298
if rt is not None:
52665299
return rt if isinstance(rt, Instance) else None
5300+
52675301
keys: list[Type] = []
52685302
values: list[Type] = []
5303+
# Preserve join order while avoiding O(n) lookups at every iteration
5304+
keys_set: set[Type] = set()
5305+
values_set: set[Type] = set()
52695306
stargs: tuple[Type, Type] | None = None
52705307
for key, value in e.items:
52715308
if key is None:
@@ -5280,13 +5317,25 @@ def fast_dict_type(self, e: DictExpr) -> Type | None:
52805317
self.resolved_type[e] = NoneType()
52815318
return None
52825319
else:
5283-
keys.append(self.accept(key))
5284-
values.append(self.accept(value))
5285-
kt = join.join_type_list(keys)
5286-
vt = join.join_type_list(values)
5287-
if not (allow_fast_container_literal(kt) and allow_fast_container_literal(vt)):
5320+
key_t = self.accept(key)
5321+
if key_t not in keys_set:
5322+
keys.append(key_t)
5323+
keys_set.add(key_t)
5324+
value_t = self.accept(value)
5325+
if value_t not in values_set:
5326+
values.append(value_t)
5327+
values_set.add(value_t)
5328+
5329+
kt = self._first_or_join_fast_item(keys)
5330+
if kt is None:
52885331
self.resolved_type[e] = NoneType()
52895332
return None
5333+
5334+
vt = self._first_or_join_fast_item(values)
5335+
if vt is None:
5336+
self.resolved_type[e] = NoneType()
5337+
return None
5338+
52905339
if stargs and (stargs[0] != kt or stargs[1] != vt):
52915340
self.resolved_type[e] = NoneType()
52925341
return None
@@ -5994,7 +6043,7 @@ def accept(
59946043
# We cannot use cache inside lambdas, because they skip immediate type
59956044
# context, and use enclosing one, see infer_lambda_type_using_context().
59966045
# TODO: consider using cache for more expression kinds.
5997-
elif isinstance(node, (CallExpr, ListExpr, TupleExpr)) and not (
6046+
elif isinstance(node, (CallExpr, ListExpr, TupleExpr, OpExpr)) and not (
59986047
self.in_lambda_expr or self.chk.current_node_deferred
59996048
):
60006049
if (node, type_context) in self.expr_cache:

test-data/unit/check-generics.test

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2929,8 +2929,8 @@ def mix(fs: List[Callable[[S], T]]) -> Callable[[S], List[T]]:
29292929
def id(__x: U) -> U:
29302930
...
29312931
fs = [id, id, id]
2932-
reveal_type(mix(fs)) # N: Revealed type is "def [S] (S`7) -> builtins.list[S`7]"
2933-
reveal_type(mix([id, id, id])) # N: Revealed type is "def [S] (S`9) -> builtins.list[S`9]"
2932+
reveal_type(mix(fs)) # N: Revealed type is "def [S] (S`2) -> builtins.list[S`2]"
2933+
reveal_type(mix([id, id, id])) # N: Revealed type is "def [S] (S`4) -> builtins.list[S`4]"
29342934
[builtins fixtures/list.pyi]
29352935

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

test-data/unit/check-redefine2.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,7 @@ def f() -> None:
10731073
while int():
10741074
x = [x]
10751075

1076-
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]]]]]]]]"
1076+
reveal_type(x) # N: Revealed type is "Union[Any, builtins.list[Any]]"
10771077

10781078
[case testNewRedefinePartialNoneEmptyList]
10791079
# flags: --allow-redefinition-new --local-partial-types

test-data/unit/check-selftype.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2018,7 +2018,7 @@ class Ben(Object):
20182018
}
20192019
@classmethod
20202020
def doit(cls) -> Foo:
2021-
reveal_type(cls.MY_MAP) # N: Revealed type is "builtins.dict[builtins.str, def [Self <: __main__.Foo] (self: Self`4) -> Self`4]"
2021+
reveal_type(cls.MY_MAP) # N: Revealed type is "builtins.dict[builtins.str, def [Self <: __main__.Foo] (self: Self`1) -> Self`1]"
20222022
foo_method = cls.MY_MAP["foo"]
20232023
return foo_method(Foo())
20242024
[builtins fixtures/isinstancelist.pyi]

0 commit comments

Comments
 (0)