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
Couple fixes
  • Loading branch information
Ivan Levkivskyi committed Aug 10, 2023
commit 2d210324dabaac9d315e1dabe0a92e30d8284654
34 changes: 32 additions & 2 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -1606,7 +1606,7 @@ def check_callable_call(
lambda i: self.accept(args[i]),
)
callee = self.infer_function_type_arguments(
callee, args, arg_kinds, formal_to_actual, context
callee, args, arg_kinds, arg_names, formal_to_actual, need_refresh, context
)
if need_refresh:
formal_to_actual = map_actuals_to_formals(
Expand Down Expand Up @@ -1896,7 +1896,9 @@ def infer_function_type_arguments(
callee_type: CallableType,
args: list[Expression],
arg_kinds: list[ArgKind],
arg_names: Sequence[str | None] | None,
formal_to_actual: list[list[int]],
need_refresh: bool,
context: Context,
) -> CallableType:
"""Infer the type arguments for a generic callee type.
Expand Down Expand Up @@ -1938,7 +1940,14 @@ def infer_function_type_arguments(
if 2 in arg_pass_nums:
# Second pass of type inference.
(callee_type, inferred_args) = self.infer_function_type_arguments_pass2(
callee_type, args, arg_kinds, formal_to_actual, inferred_args, context
callee_type,
args,
arg_kinds,
arg_names,
formal_to_actual,
inferred_args,
need_refresh,
context,
)

if (
Expand All @@ -1964,6 +1973,17 @@ def infer_function_type_arguments(
or set(get_type_vars(a)) & set(callee_type.variables)
for a in inferred_args
):
if need_refresh:
# Technically we need to refresh formal_to_actual after *each* inference pass,
# since each pass can expand ParamSpec or TypeVarTuple. Although such situations
# are very rare, not doing this can cause crashes.
formal_to_actual = map_actuals_to_formals(
arg_kinds,
arg_names,
callee_type.arg_kinds,
callee_type.arg_names,
lambda a: self.accept(args[a]),
)
# If the regular two-phase inference didn't work, try inferring type
# variables while allowing for polymorphic solutions, i.e. for solutions
# potentially involving free variables.
Expand Down Expand Up @@ -2011,8 +2031,10 @@ def infer_function_type_arguments_pass2(
callee_type: CallableType,
args: list[Expression],
arg_kinds: list[ArgKind],
arg_names: Sequence[str | None] | None,
formal_to_actual: list[list[int]],
old_inferred_args: Sequence[Type | None],
need_refresh: bool,
context: Context,
) -> tuple[CallableType, list[Type | None]]:
"""Perform second pass of generic function type argument inference.
Expand All @@ -2034,6 +2056,14 @@ def infer_function_type_arguments_pass2(
if isinstance(arg, (NoneType, UninhabitedType)) or has_erased_component(arg):
inferred_args[i] = None
callee_type = self.apply_generic_arguments(callee_type, inferred_args, context)
if need_refresh:
formal_to_actual = map_actuals_to_formals(
arg_kinds,
arg_names,
callee_type.arg_kinds,
callee_type.arg_names,
lambda a: self.accept(args[a]),
)

arg_types = self.infer_arg_types_in_context(callee_type, args, arg_kinds, formal_to_actual)

Expand Down
1 change: 0 additions & 1 deletion mypy/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,6 @@ def visit_callable_type(self, template: CallableType) -> list[Constraint]:
if (
type_state.infer_polymorphic
and cactual.variables
and cactual.param_spec() is None
and not self.skip_neg_op
# Technically, the correct inferred type for application of e.g.
# Callable[..., T] -> Callable[..., T] (with literal ellipsis), to a generic
Expand Down