Merge pull request #1553 from PeterJCLaw/generic-tuple-return

Fix construction of nested generic tuple return types
This commit is contained in:
Dave Halter
2020-04-26 01:28:51 +02:00
committed by GitHub
4 changed files with 66 additions and 18 deletions

View File

@@ -99,7 +99,7 @@ class DefineGenericBase(LazyValueWrapper):
for generic_set in self.get_generics(): for generic_set in self.get_generics():
values = NO_VALUES values = NO_VALUES
for generic in generic_set: for generic in generic_set:
if isinstance(generic, (GenericClass, TypeVar)): if isinstance(generic, (DefineGenericBase, TypeVar)):
result = generic.define_generics(type_var_dict) result = generic.define_generics(type_var_dict)
values |= result values |= result
if result != ValueSet({generic}): if result != ValueSet({generic}):

View File

@@ -217,9 +217,24 @@ class TypingClassValueWithIndex(_TypingClassMixin, TypingValueWithIndex):
elif annotation_name == 'Callable': elif annotation_name == 'Callable':
if len(annotation_generics) == 2: if len(annotation_generics) == 2:
return annotation_generics[1].infer_type_vars( if is_class_value:
value_set.execute_annotation(), # This only applies if we are comparing something like
) # List[Callable[..., T]] with Iterable[Callable[..., T]].
# First, Jedi tries to match List/Iterable. After that we
# will land here, because is_class_value will be True at
# that point. Obviously we also compare below that both
# sides are `Callable`.
for element in value_set:
element_name = element.py__name__()
if element_name == 'Callable':
merge_type_var_dicts(
type_var_dict,
merge_pairwise_generics(self, element),
)
else:
return annotation_generics[1].infer_type_vars(
value_set.execute_annotation(),
)
elif annotation_name == 'Tuple': elif annotation_name == 'Tuple':
tuple_annotation, = self.execute_annotation() tuple_annotation, = self.execute_annotation()

View File

@@ -206,40 +206,36 @@ for a in list_func_t_to_list_t(12):
a a
# The following are all actually wrong, however we're mainly testing here that
# we don't error when processing invalid values, rather than that we get the
# right output.
x0 = list_func_t_to_list_t(["abc"])[0] x0 = list_func_t_to_list_t(["abc"])[0]
#? str() #?
x0 x0
x2 = list_func_t_to_list_t([tpl])[0] x2 = list_func_t_to_list_t([tpl])[0]
#? tuple() #?
x2 x2
x3 = list_func_t_to_list_t([tpl_typed])[0] x3 = list_func_t_to_list_t([tpl_typed])[0]
#? tuple() #?
x3 x3
x4 = list_func_t_to_list_t([collection])[0] x4 = list_func_t_to_list_t([collection])[0]
#? dict() #?
x4 x4
x5 = list_func_t_to_list_t([collection_typed])[0] x5 = list_func_t_to_list_t([collection_typed])[0]
#? dict() #?
x5 x5
x6 = list_func_t_to_list_t([custom_generic])[0] x6 = list_func_t_to_list_t([custom_generic])[0]
#? CustomGeneric() #?
x6 x6
x7 = list_func_t_to_list_t([plain_instance])[0] x7 = list_func_t_to_list_t([plain_instance])[0]
#? PlainClass() #?
x7 x7
for a in list_func_t_to_list_t([12]): for a in list_func_t_to_list_t([12]):
#? int() #?
a a

View File

@@ -6,6 +6,7 @@ from typing import (
Iterable, Iterable,
List, List,
Mapping, Mapping,
Tuple,
Type, Type,
TypeVar, TypeVar,
Union, Union,
@@ -59,11 +60,32 @@ for b in list_type_t_to_list_t(list_of_int_type):
b b
def foo(x: T) -> T: # Test construction of nested generic tuple return parameters
def list_t_to_list_tuple_t(the_list: List[T]) -> List[Tuple[T]]:
return [(x,) for x in the_list]
x1t = list_t_to_list_tuple_t(list_of_ints)[0][0]
#? int()
x1t
for c1 in list_t_to_list_tuple_t(list_of_ints):
#? int()
c1[0]
for c2, in list_t_to_list_tuple_t(list_of_ints):
#? int()
c2
# Test handling of nested callables
def foo(x: int) -> int:
return x return x
list_of_funcs = [foo] # type: List[Callable[[T], T]] list_of_funcs = [foo] # type: List[Callable[[int], int]]
def list_func_t_to_list_func_type_t(the_list: List[Callable[[T], T]]) -> List[Callable[[Type[T]], T]]: def list_func_t_to_list_func_type_t(the_list: List[Callable[[T], T]]) -> List[Callable[[Type[T]], T]]:
def adapt(func: Callable[[T], T]) -> Callable[[Type[T]], T]: def adapt(func: Callable[[T], T]) -> Callable[[Type[T]], T]:
@@ -78,6 +100,21 @@ for b in list_func_t_to_list_func_type_t(list_of_funcs):
b(int) b(int)
def bar(*a, **k) -> int:
return len(a) + len(k)
list_of_funcs_2 = [bar] # type: List[Callable[..., int]]
def list_func_t_passthrough(the_list: List[Callable[..., T]]) -> List[Callable[..., T]]:
return the_list
for b in list_func_t_passthrough(list_of_funcs_2):
#? int()
b(None, x="x")
mapping_int_str = {42: 'a'} # type: Dict[int, str] mapping_int_str = {42: 'a'} # type: Dict[int, str]
# Test that mappings (that have more than one parameter) are handled # Test that mappings (that have more than one parameter) are handled