From 1c4a2edbdb0493fafa51d0c7a74a46dd722da851 Mon Sep 17 00:00:00 2001 From: Peter Law Date: Sat, 18 Apr 2020 19:43:47 +0100 Subject: [PATCH 1/4] Fix construction of nested generic tuple return types Unfortunately this appears to show up a separate bug. --- jedi/inference/gradual/base.py | 2 +- test/completion/pep0484_generic_parameters.py | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/jedi/inference/gradual/base.py b/jedi/inference/gradual/base.py index 5d7be602..70cfa447 100644 --- a/jedi/inference/gradual/base.py +++ b/jedi/inference/gradual/base.py @@ -99,7 +99,7 @@ class DefineGenericBase(LazyValueWrapper): for generic_set in self.get_generics(): values = NO_VALUES for generic in generic_set: - if isinstance(generic, (GenericClass, TypeVar)): + if isinstance(generic, (DefineGenericBase, TypeVar)): result = generic.define_generics(type_var_dict) values |= result if result != ValueSet({generic}): diff --git a/test/completion/pep0484_generic_parameters.py b/test/completion/pep0484_generic_parameters.py index 89572d99..dabe8d7c 100644 --- a/test/completion/pep0484_generic_parameters.py +++ b/test/completion/pep0484_generic_parameters.py @@ -6,6 +6,7 @@ from typing import ( Iterable, List, Mapping, + Tuple, Type, TypeVar, Union, @@ -59,6 +60,26 @@ for b in list_type_t_to_list_t(list_of_int_type): b +# 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 + + def foo(x: T) -> T: return x From 7ebbf9da447df90e41a655501a09e31cd3c140f7 Mon Sep 17 00:00:00 2001 From: Peter Law Date: Sat, 18 Apr 2020 22:56:46 +0100 Subject: [PATCH 2/4] Make this test case obey typing rules in Python Unfortunately I can't recall exactly what it was that this test case was trying to validate, however on a second look it turns out that it was working by accident and did not represent a valid use of generic type vars in Python (which cannot be used completely unbound as this was). --- test/completion/pep0484_generic_parameters.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/completion/pep0484_generic_parameters.py b/test/completion/pep0484_generic_parameters.py index dabe8d7c..a80d0346 100644 --- a/test/completion/pep0484_generic_parameters.py +++ b/test/completion/pep0484_generic_parameters.py @@ -80,11 +80,11 @@ for c2, in list_t_to_list_tuple_t(list_of_ints): c2 -def foo(x: T) -> T: +def foo(x: int) -> int: 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 adapt(func: Callable[[T], T]) -> Callable[[Type[T]], T]: From 2ac806e39fc969b2bdcb9462807e743de1dc6493 Mon Sep 17 00:00:00 2001 From: Peter Law Date: Sun, 19 Apr 2020 12:50:24 +0100 Subject: [PATCH 3/4] Add test which demonstrates incomplete generic Callable handling --- test/completion/pep0484_generic_parameters.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/completion/pep0484_generic_parameters.py b/test/completion/pep0484_generic_parameters.py index a80d0346..4f0f0d1f 100644 --- a/test/completion/pep0484_generic_parameters.py +++ b/test/completion/pep0484_generic_parameters.py @@ -80,6 +80,7 @@ for c2, in list_t_to_list_tuple_t(list_of_ints): c2 +# Test handling of nested callables def foo(x: int) -> int: return x @@ -99,6 +100,21 @@ for b in list_func_t_to_list_func_type_t(list_of_funcs): 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] # Test that mappings (that have more than one parameter) are handled From f8e7447d3589d791556d81776f9cc1dc1c30ca5d Mon Sep 17 00:00:00 2001 From: Peter Law Date: Sun, 19 Apr 2020 13:12:54 +0100 Subject: [PATCH 4/4] Add handling of nested generic callables Previously tests for these were passing somewhat by accident, however this commit's parent adds a case which showed that the handling was missing. Note that this also relies on the recent fix for nested tuples which changed the `isinstance` check in `define_generics`. --- jedi/inference/gradual/typing.py | 21 ++++++++++++++++--- test/completion/pep0484_generic_mismatches.py | 20 +++++++----------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/jedi/inference/gradual/typing.py b/jedi/inference/gradual/typing.py index ab0b449b..50ab8e83 100644 --- a/jedi/inference/gradual/typing.py +++ b/jedi/inference/gradual/typing.py @@ -217,9 +217,24 @@ class TypingClassValueWithIndex(_TypingClassMixin, TypingValueWithIndex): elif annotation_name == 'Callable': if len(annotation_generics) == 2: - return annotation_generics[1].infer_type_vars( - value_set.execute_annotation(), - ) + if is_class_value: + # 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': tuple_annotation, = self.execute_annotation() diff --git a/test/completion/pep0484_generic_mismatches.py b/test/completion/pep0484_generic_mismatches.py index 47add048..fbd3c55a 100644 --- a/test/completion/pep0484_generic_mismatches.py +++ b/test/completion/pep0484_generic_mismatches.py @@ -206,40 +206,36 @@ for a in list_func_t_to_list_t(12): 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] -#? str() +#? x0 x2 = list_func_t_to_list_t([tpl])[0] -#? tuple() +#? x2 x3 = list_func_t_to_list_t([tpl_typed])[0] -#? tuple() +#? x3 x4 = list_func_t_to_list_t([collection])[0] -#? dict() +#? x4 x5 = list_func_t_to_list_t([collection_typed])[0] -#? dict() +#? x5 x6 = list_func_t_to_list_t([custom_generic])[0] -#? CustomGeneric() +#? x6 x7 = list_func_t_to_list_t([plain_instance])[0] -#? PlainClass() +#? x7 for a in list_func_t_to_list_t([12]): - #? int() + #? a