diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 128ca4129f76..54c8fb517c2c 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -5715,6 +5715,11 @@ def visit_type_alias_type(self, t: TypeAliasType) -> Type: def visit_instance(self, t: Instance) -> Type: if t.type.has_param_spec_type: + # We need this special-casing to preserve the possibility to store a + # generic function in an instance type. Things like + # forall T . Foo[[x: T], T] + # are not really expressible in current type system, but this looks like + # a useful feature, so let's keep it. param_spec_index = next( i for (i, tv) in enumerate(t.type.defn.type_vars) if isinstance(tv, ParamSpecType) ) diff --git a/mypy/constraints.py b/mypy/constraints.py index 837f47dedcdc..6c9ef198fa0d 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -960,15 +960,12 @@ def visit_callable_type(self, template: CallableType) -> list[Constraint]: for t, a, tk, ak in zip( template_args, cactual_args, template.arg_kinds, cactual.arg_kinds ): - # Unpack may have shifted indices. - if not unpack_present: - # This avoids bogus constraints like T <: P.args - if ( - tk == ARG_STAR - and ak != ARG_STAR - or tk == ARG_STAR2 - and ak != ARG_STAR2 - ): + # This avoids bogus constraints like T <: P.args + if (tk == ARG_STAR and ak != ARG_STAR) or ( + tk == ARG_STAR2 and ak != ARG_STAR2 + ): + # Unpack may have shifted indices. + if not unpack_present: continue if isinstance(a, ParamSpecType): # TODO: can we infer something useful for *T vs P? diff --git a/mypy/solve.py b/mypy/solve.py index 0c2b71f60d35..4b2b899c2a8d 100644 --- a/mypy/solve.py +++ b/mypy/solve.py @@ -6,7 +6,7 @@ from typing import Iterable, Sequence from typing_extensions import TypeAlias as _TypeAlias -from mypy.constraints import SUBTYPE_OF, SUPERTYPE_OF, Constraint, infer_constraints, neg_op +from mypy.constraints import SUBTYPE_OF, SUPERTYPE_OF, Constraint, infer_constraints from mypy.expandtype import expand_type from mypy.graph_utils import prepare_sccs, strongly_connected_components, topsort from mypy.join import join_types @@ -27,7 +27,6 @@ UninhabitedType, UnionType, get_proper_type, - remove_dups, ) from mypy.typestate import type_state @@ -63,10 +62,6 @@ def solve_constraints( for c in constraints: extra_vars.extend([v.id for v in c.extra_tvars if v.id not in vars + extra_vars]) originals.update({v.id: v for v in c.extra_tvars if v.id not in originals}) - if allow_polymorphic: - # Constraints like T :> S and S <: T are semantically the same, but they are - # represented differently. Normalize the constraint list w.r.t this equivalence. - constraints = normalize_constraints(constraints, vars + extra_vars) # Collect a list of constraints for each type variable. cmap: dict[TypeVarId, list[Constraint]] = {tv: [] for tv in vars + extra_vars} @@ -335,29 +330,6 @@ def is_trivial_bound(tp: ProperType) -> bool: return isinstance(tp, Instance) and tp.type.fullname == "builtins.object" -def normalize_constraints( - # TODO: delete this function? - constraints: list[Constraint], - vars: list[TypeVarId], -) -> list[Constraint]: - """Normalize list of constraints (to simplify life for the non-linear solver). - - This includes two things currently: - * Complement T :> S by S <: T - * Remove strict duplicates - * Remove constrains for unrelated variables - """ - res = constraints.copy() - for c in constraints: - if ( - isinstance(c.target, TypeVarType) - or isinstance(c.target, ParamSpecType) - and not c.target.prefix.arg_types - ): - res.append(Constraint(c.target, neg_op(c.op), c.origin_type_var)) - return [c for c in remove_dups(constraints) if c.type_var in vars] - - def transitive_closure( tvars: list[TypeVarId], constraints: list[Constraint] ) -> tuple[Graph, Bounds, Bounds]: