1717 Type ,
1818 TypeOfAny ,
1919 UnboundType ,
20- UninhabitedType ,
2120 get_proper_type ,
2221)
2322
@@ -132,6 +131,9 @@ def partial_new_callback(ctx: mypy.plugin.FunctionContext) -> Type:
132131 if fn_type is None :
133132 return ctx .default_return_type
134133
134+ # We must normalize from the start to have coherent view together with TypeChecker.
135+ fn_type = fn_type .with_unpacked_kwargs ().with_normalized_var_args ()
136+
135137 defaulted = fn_type .copy_modified (
136138 arg_kinds = [
137139 (
@@ -146,10 +148,25 @@ def partial_new_callback(ctx: mypy.plugin.FunctionContext) -> Type:
146148 # Make up a line number if we don't have one
147149 defaulted .set_line (ctx .default_return_type )
148150
149- actual_args = [a for param in ctx .args [1 :] for a in param ]
150- actual_arg_kinds = [a for param in ctx .arg_kinds [1 :] for a in param ]
151- actual_arg_names = [a for param in ctx .arg_names [1 :] for a in param ]
152- actual_types = [a for param in ctx .arg_types [1 :] for a in param ]
151+ # Flatten actual to formal mapping, since this is what check_call() expects.
152+ actual_args = []
153+ actual_arg_kinds = []
154+ actual_arg_names = []
155+ actual_types = []
156+ seen_args = set ()
157+ for i , param in enumerate (ctx .args [1 :], start = 1 ):
158+ for j , a in enumerate (param ):
159+ if a in seen_args :
160+ # Same actual arg can map to multiple formals, but we need to include
161+ # each one only once.
162+ continue
163+ # Here we rely on the fact that expressions are essentially immutable, so
164+ # they can be compared by identity.
165+ seen_args .add (a )
166+ actual_args .append (a )
167+ actual_arg_kinds .append (ctx .arg_kinds [i ][j ])
168+ actual_arg_names .append (ctx .arg_names [i ][j ])
169+ actual_types .append (ctx .arg_types [i ][j ])
153170
154171 # Create a valid context for various ad-hoc inspections in check_call().
155172 call_expr = CallExpr (
@@ -188,7 +205,7 @@ def partial_new_callback(ctx: mypy.plugin.FunctionContext) -> Type:
188205 for i , actuals in enumerate (formal_to_actual ):
189206 if len (bound .arg_types ) == len (fn_type .arg_types ):
190207 arg_type = bound .arg_types [i ]
191- if isinstance ( get_proper_type ( arg_type ), UninhabitedType ):
208+ if not mypy . checker . is_valid_inferred_type ( arg_type ):
192209 arg_type = fn_type .arg_types [i ] # bit of a hack
193210 else :
194211 # TODO: I assume that bound and fn_type have the same arguments. It appears this isn't
@@ -210,7 +227,7 @@ def partial_new_callback(ctx: mypy.plugin.FunctionContext) -> Type:
210227 partial_names .append (fn_type .arg_names [i ])
211228
212229 ret_type = bound .ret_type
213- if isinstance ( get_proper_type ( ret_type ), UninhabitedType ):
230+ if not mypy . checker . is_valid_inferred_type ( ret_type ):
214231 ret_type = fn_type .ret_type # same kind of hack as above
215232
216233 partially_applied = fn_type .copy_modified (
0 commit comments