@@ -123,7 +123,17 @@ def _value_to_parameter_types(self, node, v, instance, template, seen, view):
123123 """Get PyTD types for the parameters of an instance of an abstract value."""
124124 if isinstance (v , abstract .CallableClass ):
125125 assert template == (abstract_utils .ARGS , abstract_utils .RET ), template
126- template = list (range (v .num_args )) + [template [1 ]]
126+ should_preserve_paramspec = (
127+ v .has_paramspec ()
128+ and v .num_args == 1
129+ and instance
130+ and isinstance (
131+ instance .get_formal_type_parameter (abstract_utils .ARGS ),
132+ abstract .Unsolvable ,
133+ )
134+ )
135+ if not should_preserve_paramspec :
136+ template = list (range (v .num_args )) + [template [1 ]]
127137 if self ._is_tuple (v , instance ):
128138 if isinstance (v , abstract .TupleClass ):
129139 new_template = range (v .tuple_length )
@@ -176,10 +186,18 @@ def _value_to_parameter_types(self, node, v, instance, template, seen, view):
176186 else :
177187 param_values = {self .ctx .convert .unsolvable : view }
178188 formal_param = v .get_formal_type_parameter (t )
189+ if (
190+ t == abstract_utils .ARGS
191+ and isinstance (v , abstract .CallableClass )
192+ and v .has_paramspec ()
193+ and [* param_values ] == [self .ctx .convert .unsolvable ]
194+ ):
195+ # This is a Callable[P, T] where P is unsolvable.
196+ arg = pytd .AnythingType ()
179197 # If the instance's parameter value is unsolvable or the parameter type
180198 # is recursive, we can get a more precise type from the class. Note that
181199 # we need to be careful not to introduce unbound type parameters.
182- if (
200+ elif (
183201 isinstance (v , abstract .ParameterizedClass )
184202 and not formal_param .formal
185203 and (
@@ -281,7 +299,16 @@ def value_instance_to_pytd_type(self, node, v, instance, seen, view):
281299 if self ._is_tuple (v , instance ):
282300 homogeneous = False
283301 elif v .full_name == "typing.Callable" :
284- homogeneous = not isinstance (v , abstract .CallableClass )
302+ is_callable_with_unsolvable_paramspec = (
303+ isinstance (v , abstract .CallableClass )
304+ and v .has_paramspec ()
305+ and len (type_arguments ) == 2
306+ and isinstance (type_arguments [0 ], pytd .AnythingType )
307+ )
308+ homogeneous = (
309+ not isinstance (v , abstract .CallableClass )
310+ or is_callable_with_unsolvable_paramspec
311+ )
285312 else :
286313 homogeneous = len (type_arguments ) == 1
287314 return pytd_utils .MakeClassOrContainerType (
0 commit comments