Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polymorphic inference: support for parameter specifications and lambdas #15837

Merged
merged 15 commits into from
Aug 15, 2023
Prev Previous commit
Next Next commit
Some cleanups
  • Loading branch information
Ivan Levkivskyi committed Aug 9, 2023
commit c5c1b76f89a6cc6f2b16b8bdfa4b82411833f65a
5 changes: 5 additions & 0 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)
Expand Down
15 changes: 6 additions & 9 deletions mypy/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down
30 changes: 1 addition & 29 deletions mypy/solve.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -27,7 +27,6 @@
UninhabitedType,
UnionType,
get_proper_type,
remove_dups,
)
from mypy.typestate import type_state

Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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]:
Expand Down