mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-07 22:44:27 +08:00
Push fetching of generics into nested function
This slightly simplifies both the calling code and semantics of the nested function.
This commit is contained in:
@@ -356,11 +356,14 @@ def _infer_type_vars(annotation_value, value_set, is_class_value=False):
|
|||||||
type_var_dict = {}
|
type_var_dict = {}
|
||||||
annotation_name = annotation_value.py__name__()
|
annotation_name = annotation_value.py__name__()
|
||||||
|
|
||||||
def merge_pairwise_generics(annotation_generics, actual_generics):
|
def merge_pairwise_generics(annotation_value, annotated_argument_class):
|
||||||
"""
|
"""
|
||||||
Given iterables of the generics immediately within an annotation and
|
Match up the generic parameters from the given argument class to the
|
||||||
within an argument's type, match up the generic parameters with the
|
target annotation.
|
||||||
corrsponding actual types.
|
|
||||||
|
This walks the generic parameters immediately within the annotation and
|
||||||
|
argument's type, in order to determine the concrete values of the
|
||||||
|
annotation's parameters for the current case.
|
||||||
|
|
||||||
For example, given the following code:
|
For example, given the following code:
|
||||||
|
|
||||||
@@ -369,30 +372,28 @@ def _infer_type_vars(annotation_value, value_set, is_class_value=False):
|
|||||||
for val in values({1: 'a'}):
|
for val in values({1: 'a'}):
|
||||||
val
|
val
|
||||||
|
|
||||||
Then in this function we are given `K` & `V` and `int` & `str` in order
|
Then this function should be given representations of `Mapping[K, V]`
|
||||||
to determine that `K` is `int and `V` is `str`.
|
and `Mapping[int, str]`, so that it can determine that `K` is `int and
|
||||||
|
`V` is `str`.
|
||||||
|
|
||||||
|
Note that it is responsibility of the caller to traverse the MRO of the
|
||||||
|
argument type as needed in order to find the type matching the
|
||||||
|
annotation (in this case finding `Mapping[int, str]` as a parent of
|
||||||
|
`Dict[int, str]`).
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
|
||||||
`annotation_generics`: an ordered collection of the immediately nested
|
`annotation_value`: represents the annotation to infer the concrete
|
||||||
generic parameters within the annotation being considered. In the
|
parameter types of.
|
||||||
above example, the caller would be analysing `Mapping[K, V]` and
|
|
||||||
would give us an iterable yileding representations of the parameters
|
|
||||||
`K` and then `V`.
|
|
||||||
|
|
||||||
`actual_generics`: an ordered collection of the immediately nested
|
`annotated_argument_class`: represents the annotated class of the
|
||||||
generic parameters within the type of the argument being considered.
|
argument being passed to the object annotated by `annotation_value`.
|
||||||
These need to be the parameters at the level of the type for which
|
|
||||||
the annotation generics are given, rather than of the actual type of
|
|
||||||
the parameter.
|
|
||||||
In the above example, the caller would be analysing `{1: 'a'}`. The
|
|
||||||
caller must have already determined that this is an instance of a
|
|
||||||
type which implements `Mapping` and should pass us an iterable over
|
|
||||||
representations of the type parameters to that `Mapping`
|
|
||||||
implementation (here, `int` and `str` in that order).
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
annotation_generics = annotation_value.get_generics()
|
||||||
|
actual_generics = annotated_argument_class.get_generics()
|
||||||
|
|
||||||
for annotation_generics_set, actual_generic_set in zip(annotation_generics, actual_generics):
|
for annotation_generics_set, actual_generic_set in zip(annotation_generics, actual_generics):
|
||||||
for nested_annotation_value in annotation_generics_set:
|
for nested_annotation_value in annotation_generics_set:
|
||||||
_merge_type_var_dicts(
|
_merge_type_var_dicts(
|
||||||
@@ -418,10 +419,7 @@ def _infer_type_vars(annotation_value, value_set, is_class_value=False):
|
|||||||
for element in value_set:
|
for element in value_set:
|
||||||
element_name = element.py__name__()
|
element_name = element.py__name__()
|
||||||
if annotation_name == element_name:
|
if annotation_name == element_name:
|
||||||
annotation_generics = annotation_value.get_generics()
|
merge_pairwise_generics(annotation_value, element)
|
||||||
actual_generics = element.get_generics()
|
|
||||||
|
|
||||||
merge_pairwise_generics(annotation_generics, actual_generics)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
for nested_annotation_value in given[0]:
|
for nested_annotation_value in given[0]:
|
||||||
@@ -477,8 +475,7 @@ def _infer_type_vars(annotation_value, value_set, is_class_value=False):
|
|||||||
if not isinstance(py_class, DefineGenericBase):
|
if not isinstance(py_class, DefineGenericBase):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
actual_generics = py_class.get_generics()
|
merge_pairwise_generics(annotation_value, py_class)
|
||||||
merge_pairwise_generics(annotation_generics, actual_generics)
|
|
||||||
|
|
||||||
elif isinstance(annotation_value, GenericClass):
|
elif isinstance(annotation_value, GenericClass):
|
||||||
if annotation_name == 'Iterable' and not is_class_value:
|
if annotation_name == 'Iterable' and not is_class_value:
|
||||||
@@ -511,10 +508,7 @@ def _infer_type_vars(annotation_value, value_set, is_class_value=False):
|
|||||||
if not isinstance(parent_class, DefineGenericBase):
|
if not isinstance(parent_class, DefineGenericBase):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
annotation_generics = annotation_value.get_generics()
|
merge_pairwise_generics(annotation_value, parent_class)
|
||||||
actual_generics = parent_class.get_generics()
|
|
||||||
|
|
||||||
merge_pairwise_generics(annotation_generics, actual_generics)
|
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user