diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 8223ccfe4ca0..863c43e4bb4e 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -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 @@ -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: + # 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 diff --git a/mypy/constraints.py b/mypy/constraints.py index 9eeea3cb2c26..e9d970a0371e 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -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) @@ -270,6 +271,8 @@ def infer_constraints_for_callable( ), ) ) + + constraints = list(dict.fromkeys(constraints)) 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) diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index 0be9d918c69f..abeb5face26f 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -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] @@ -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] diff --git a/test-data/unit/check-redefine2.test b/test-data/unit/check-redefine2.test index 3523772611aa..1abe957240b5 100644 --- a/test-data/unit/check-redefine2.test +++ b/test-data/unit/check-redefine2.test @@ -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 diff --git a/test-data/unit/check-typeddict.test b/test-data/unit/check-typeddict.test index a068a63274ca..d28782bfba45 100644 --- a/test-data/unit/check-typeddict.test +++ b/test-data/unit/check-typeddict.test @@ -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]