diff --git a/jedi/inference/gradual/annotation.py b/jedi/inference/gradual/annotation.py index 29ad95d0..2a9e3d73 100644 --- a/jedi/inference/gradual/annotation.py +++ b/jedi/inference/gradual/annotation.py @@ -438,14 +438,12 @@ def _infer_type_vars(annotation_value, value_set, is_class_value=False): else: py_class = element - # TODO: what about things like 'str', which likely aren't - # generic, but do implement 'Iterable[str]'? - if not isinstance(py_class, DefineGenericBase): - continue - for klass in py_class.py__mro__(): class_name = klass.py__name__() if annotation_name == class_name: + if not isinstance(klass, DefineGenericBase): + continue + annotation_generics = annotation_value.get_generics() actual_generics = klass.get_generics() diff --git a/test/completion/pep0484_generic_parameters.py b/test/completion/pep0484_generic_parameters.py index 98522b7a..4f8a33b9 100644 --- a/test/completion/pep0484_generic_parameters.py +++ b/test/completion/pep0484_generic_parameters.py @@ -86,6 +86,14 @@ def first(iterable: Iterable[T]) -> T: #? int() first(mapping_int_str) +# Test inference of str as an iterable of str. +#? str() +first("abc") + +some_str = NotImplemented # type: str +#? str() +first(some_str) + # Test that the right type is chosen when a partially realised mapping is expected def values(mapping: Mapping[int, T]) -> List[T]: @@ -177,3 +185,57 @@ x8 for x9 in unwrap_custom2(custom_instance_list_int): #? int() x9 + + +# Test that classes which have gneeric parents but are not generic themselves +# are still inferred correctly. +class Specialised(Mapping[int, str]): + pass + + +specialised_instance = NotImplemented # type: Specialised + +#? int() +first(specialised_instance) + +#? str() +values(specialised_instance)[0] + + +# Test that unbound generics are inferred as much as possible +class CustomPartialGeneric1(Mapping[str, T]): + pass + + +custom_partial1_instance = NotImplemented # type: CustomPartialGeneric1[int] + +#? str() +first(custom_partial1_instance) + + +custom_partial1_unbound_instance = NotImplemented # type: CustomPartialGeneric1 + +#? str() +first(custom_partial1_unbound_instance) + + +class CustomPartialGeneric2(Mapping[T, str]): + pass + + +custom_partial2_instance = NotImplemented # type: CustomPartialGeneric2[int] + +#? int() +first(custom_partial2_instance) + +#? str() +values(custom_partial2_instance)[0] + + +custom_partial2_unbound_instance = NotImplemented # type: CustomPartialGeneric2 + +#? [] +first(custom_partial2_unbound_instance) + +#? str() +values(custom_partial2_unbound_instance)[0]