diff --git a/jedi/inference/gradual/annotation.py b/jedi/inference/gradual/annotation.py index b4caeb5e..9f53a267 100644 --- a/jedi/inference/gradual/annotation.py +++ b/jedi/inference/gradual/annotation.py @@ -222,6 +222,18 @@ def infer_return_types(function, arguments): match.group(1).strip() ).execute_annotation() + elif annotation.type == 'string': + annotation = _get_forward_reference_node( + context, + context.inference_state.compiled_subprocess.safe_literal_eval( + annotation.value, + ), + ) + # The forward reference tree has an additional root node ('eval_input') + # that we don't want. Extract the node we do want, that is equivalent to + # the nodes returned by `py__annotations__` for a non-quoted annotation. + annotation = annotation.children[0] + unknown_type_vars = find_unknown_type_vars(context, annotation) annotation_values = infer_annotation(context, annotation) if not unknown_type_vars: diff --git a/test/completion/pep0484_generic_passthroughs.py b/test/completion/pep0484_generic_passthroughs.py index 49b133a8..e250b1a4 100644 --- a/test/completion/pep0484_generic_passthroughs.py +++ b/test/completion/pep0484_generic_passthroughs.py @@ -58,6 +58,12 @@ def typed_bound_generic_passthrough(x: TList) -> TList: return x +# Forward references are more likely with custom types, however this aims to +# test just the handling of the quoted type rather than any other part of the +# machinery. +def typed_quoted_generic_passthrough(x: T) -> 'List[T]': + return [x] + for a in untyped_passthrough(untyped_list_str): #? str() @@ -146,6 +152,16 @@ for q in typed_bound_generic_passthrough(typed_list_str): q +for r in typed_quoted_generic_passthrough("something"): + #? str() + r + +for s in typed_quoted_generic_passthrough(42): + #? int() + s + + + class CustomList(List): def get_first(self): return self[0]