Start using generic managers, for #1413

This commit is contained in:
Dave Halter
2019-12-08 21:56:30 +01:00
parent 4fca7bd22d
commit 8213d183fb
7 changed files with 81 additions and 56 deletions

View File

@@ -12,8 +12,8 @@ from parso import ParserSyntaxError, parse
from jedi._compatibility import force_unicode, Parameter from jedi._compatibility import force_unicode, Parameter
from jedi.inference.cache import inference_state_method_cache from jedi.inference.cache import inference_state_method_cache
from jedi.inference.base_value import ValueSet, NO_VALUES from jedi.inference.base_value import ValueSet, NO_VALUES
from jedi.inference.gradual.base import LazyGenericClass, \ from jedi.inference.gradual.base import DefineGenericBase, GenericClass
DefineGenericBase, GenericClass from jedi.inference.gradual.generics import TupleGenericManager
from jedi.inference.gradual.typing import TypingClassValueWithIndex from jedi.inference.gradual.typing import TypingClassValueWithIndex
from jedi.inference.gradual.type_var import TypeVar from jedi.inference.gradual.type_var import TypeVar
from jedi.inference.helpers import is_string from jedi.inference.helpers import is_string
@@ -118,13 +118,17 @@ def infer_param(function_value, param, ignore_stars=False):
tuple_ = builtin_from_name(inference_state, 'tuple') tuple_ = builtin_from_name(inference_state, 'tuple')
return ValueSet([GenericClass( return ValueSet([GenericClass(
tuple_, tuple_,
generics=(values,), TupleGenericManager((values,)),
) for c in values]) ) for c in values])
elif param.star_count == 2: elif param.star_count == 2:
dct = builtin_from_name(inference_state, 'dict') dct = builtin_from_name(inference_state, 'dict')
generics = (
ValueSet([builtin_from_name(inference_state, 'str')]),
values
)
return ValueSet([GenericClass( return ValueSet([GenericClass(
dct, dct,
generics=(ValueSet([builtin_from_name(inference_state, 'str')]), values), TupleGenericManager(generics),
) for c in values]) ) for c in values])
pass pass
return values return values
@@ -325,7 +329,7 @@ def _infer_type_vars(annotation_value, value_set, is_class_value=False):
value_set.execute_annotation(), value_set.execute_annotation(),
) )
) )
elif isinstance(annotation_value, LazyGenericClass): elif isinstance(annotation_value, GenericClass):
name = annotation_value.py__name__() name = annotation_value.py__name__()
if name == 'Iterable': if name == 'Iterable':
given = annotation_value.get_generics() given = annotation_value.get_generics()

View File

@@ -7,7 +7,7 @@ from jedi.inference.value.klass import ClassMixin
from jedi.inference.utils import to_list from jedi.inference.utils import to_list
from jedi.inference.names import AbstractNameDefinition, ValueName from jedi.inference.names import AbstractNameDefinition, ValueName
from jedi.inference.context import ClassContext from jedi.inference.context import ClassContext
from jedi.inference.gradual.generics import iter_over_arguments from jedi.inference.gradual.generics import TupleGenericManager
class BaseTypingValue(Value): class BaseTypingValue(Value):
@@ -149,7 +149,7 @@ class DefineGenericBase(LazyValueWrapper):
return ValueSet([self._get_fixed_generics_cls()( return ValueSet([self._get_fixed_generics_cls()(
self._wrapped_value, self._wrapped_value,
generics=tuple(new_generics) TupleGenericManager(tuple(new_generics))
)]) )])
def is_same_class(self, other): def is_same_class(self, other):
@@ -197,7 +197,7 @@ class _AbstractAnnotatedClass(ClassMixin, DefineGenericBase):
def py__call__(self, arguments): def py__call__(self, arguments):
instance, = super(_AbstractAnnotatedClass, self).py__call__(arguments) instance, = super(_AbstractAnnotatedClass, self).py__call__(arguments)
return ValueSet([InstanceWrapper(instance)]) return ValueSet([_InstanceWrapper(instance)])
def _as_context(self): def _as_context(self):
return AnnotatedClassContext(self) return AnnotatedClassContext(self)
@@ -205,30 +205,20 @@ class _AbstractAnnotatedClass(ClassMixin, DefineGenericBase):
@to_list @to_list
def py__bases__(self): def py__bases__(self):
for base in self._wrapped_value.py__bases__(): for base in self._wrapped_value.py__bases__():
yield LazyAnnotatedBaseClass(self, base) yield _LazyAnnotatedBaseClass(self, base)
class LazyGenericClass(_AbstractAnnotatedClass):
def __init__(self, class_value, index_value, context_of_index):
super(LazyGenericClass, self).__init__(class_value)
self._index_value = index_value
self._context_of_index = context_of_index
@inference_state_method_cache()
def get_generics(self):
return list(iter_over_arguments(self._index_value, self._context_of_index))
class GenericClass(_AbstractAnnotatedClass): class GenericClass(_AbstractAnnotatedClass):
def __init__(self, class_value, generics): def __init__(self, class_value, generics_manager):
super(GenericClass, self).__init__(class_value) super(GenericClass, self).__init__(class_value)
self._generics = generics self._generics_manager = generics_manager
@inference_state_method_cache()
def get_generics(self): def get_generics(self):
return self._generics return self._generics_manager.to_tuple()
class LazyAnnotatedBaseClass(object): class _LazyAnnotatedBaseClass(object):
def __init__(self, class_value, lazy_base_class): def __init__(self, class_value, lazy_base_class):
self._class_value = class_value self._class_value = class_value
self._lazy_base_class = lazy_base_class self._lazy_base_class = lazy_base_class
@@ -241,7 +231,7 @@ class LazyAnnotatedBaseClass(object):
yield GenericClass.create_cached( yield GenericClass.create_cached(
base.inference_state, base.inference_state,
base._wrapped_value, base._wrapped_value,
tuple(self._remap_type_vars(base)), TupleGenericManager(tuple(self._remap_type_vars(base))),
) )
else: else:
yield base yield base
@@ -265,7 +255,7 @@ class LazyAnnotatedBaseClass(object):
yield new yield new
class InstanceWrapper(ValueWrapper): class _InstanceWrapper(ValueWrapper):
def py__stop_iteration_returns(self): def py__stop_iteration_returns(self):
for cls in self._wrapped_value.class_value.py__mro__(): for cls in self._wrapped_value.class_value.py__mro__():
if cls.py__name__() == 'Generator': if cls.py__name__() == 'Generator':

View File

@@ -1,5 +1,10 @@
"""
This module is about generics, like the `int` in `List[int]`. It's not about
the Generic class.
"""
from jedi.cache import memoize_method from jedi.cache import memoize_method
from jedi.inference.utils import to_list from jedi.inference.utils import to_tuple
from jedi.inference.base_value import ValueSet from jedi.inference.base_value import ValueSet
from jedi.inference.value.iterable import SequenceLiteralValue from jedi.inference.value.iterable import SequenceLiteralValue
from jedi.inference.helpers import is_string from jedi.inference.helpers import is_string
@@ -36,39 +41,51 @@ class LazyGenericManager(object):
@memoize_method @memoize_method
def __getitem__(self, index): def __getitem__(self, index):
return self._list()[index]() return self._tuple()[index]()
def __len__(self): def __len__(self):
return len(self._list()) return len(self._tuple())
@memoize_method @memoize_method
@to_list @to_tuple
def _list(self): def _tuple(self):
if isinstance(self._index_value, SequenceLiteralValue): def lambda_scoping_in_for_loop_sucks(lazy_value):
for lazy_value in self._index_value.py__iter__(contextualized_node=None): return lambda: ValueSet(_resolve_forward_references(
yield lambda: _resolve_forward_references(
self._context_of_index, self._context_of_index,
lazy_value.infer() lazy_value.infer()
) ))
if isinstance(self._index_value, SequenceLiteralValue):
for lazy_value in self._index_value.py__iter__(contextualized_node=None):
yield lambda_scoping_in_for_loop_sucks(lazy_value)
else: else:
yield lambda: ValueSet([ yield lambda: ValueSet(_resolve_forward_references(
_resolve_forward_references(self._context_of_index, self._index_value) self._context_of_index,
]) ValueSet([self._index_value])
))
def __iter__(self): @to_tuple
return iter(self._iterate()) def to_tuple(self):
for callable_ in self._tuple():
yield callable_()
#def __iter__(self):
# return iter(self._iterate())
class ListGenericManager(object): class TupleGenericManager(object):
def __init__(self, lst): def __init__(self, tup):
self._lst = lst self._tuple = tup
def __getitem__(self, index): def __getitem__(self, index):
return self._lst[index] return self._tuple[index]
def __len__(self): def __len__(self):
return len(self._lst) return len(self._tuple)
def __iter__(self): #def __iter__(self):
for value_set in self._lst: # for value_set in self._tuple:
yield lambda: value_set # yield lambda: value_set
def to_tuple(self):
return self._tuple

View File

@@ -21,6 +21,12 @@ def to_list(func):
return wrapper return wrapper
def to_tuple(func):
def wrapper(*args, **kwargs):
return tuple(func(*args, **kwargs))
return wrapper
def unite(iterable): def unite(iterable):
"""Turns a two dimensional array into a one dimensional.""" """Turns a two dimensional array into a one dimensional."""
return set(typ for types in iterable for typ in types) return set(typ for types in iterable for typ in types)

View File

@@ -21,6 +21,7 @@ from jedi.inference.value import iterable
from jedi import parser_utils from jedi import parser_utils
from jedi.inference.parser_cache import get_yield_exprs from jedi.inference.parser_cache import get_yield_exprs
from jedi.inference.helpers import values_from_qualified_names from jedi.inference.helpers import values_from_qualified_names
from jedi.inference.gradual.generics import TupleGenericManager
class LambdaName(AbstractNameDefinition): class LambdaName(AbstractNameDefinition):
@@ -297,7 +298,7 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
generics = (yield_values.py__class__(), NO_VALUES) generics = (yield_values.py__class__(), NO_VALUES)
return ValueSet( return ValueSet(
# In Python 3.6 AsyncGenerator is still a class. # In Python 3.6 AsyncGenerator is still a class.
GenericClass(c, generics) GenericClass(c, TupleGenericManager(generics))
for c in async_generator_classes for c in async_generator_classes
).execute_annotation() ).execute_annotation()
else: else:
@@ -308,7 +309,7 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
# Only the first generic is relevant. # Only the first generic is relevant.
generics = (return_values.py__class__(), NO_VALUES, NO_VALUES) generics = (return_values.py__class__(), NO_VALUES, NO_VALUES)
return ValueSet( return ValueSet(
GenericClass(c, generics) for c in async_classes GenericClass(c, TupleGenericManager(generics)) for c in async_classes
).execute_annotation() ).execute_annotation()
else: else:
if is_generator: if is_generator:

View File

@@ -195,8 +195,12 @@ class Sequence(LazyAttributeOverwrite, IterableMixin):
def _get_wrapped_value(self): def _get_wrapped_value(self):
from jedi.inference.gradual.base import GenericClass from jedi.inference.gradual.base import GenericClass
from jedi.inference.gradual.generics import TupleGenericManager
klass = compiled.builtin_from_name(self.inference_state, self.array_type) klass = compiled.builtin_from_name(self.inference_state, self.array_type)
c, = GenericClass(klass, self._get_generics()).execute_annotation() c, = GenericClass(
klass,
TupleGenericManager(self._get_generics())
).execute_annotation()
return c return c
def py__bool__(self): def py__bool__(self):

View File

@@ -50,6 +50,7 @@ from jedi.inference.base_value import ValueSet, iterator_to_value_set, \
NO_VALUES NO_VALUES
from jedi.inference.context import ClassContext from jedi.inference.context import ClassContext
from jedi.inference.value.function import FunctionAndClassBase from jedi.inference.value.function import FunctionAndClassBase
from jedi.inference.gradual.generics import LazyGenericManager, TupleGenericManager
from jedi.plugins import plugin_manager from jedi.plugins import plugin_manager
@@ -266,14 +267,16 @@ class ClassValue(use_metaclass(CachedMetaClass, ClassMixin, FunctionAndClassBase
)] )]
def py__getitem__(self, index_value_set, contextualized_node): def py__getitem__(self, index_value_set, contextualized_node):
from jedi.inference.gradual.base import LazyGenericClass from jedi.inference.gradual.base import GenericClass
if not index_value_set: if not index_value_set:
return ValueSet([self]) return ValueSet([self])
return ValueSet( return ValueSet(
LazyGenericClass( GenericClass(
self, self,
index_value, LazyGenericManager(
context_of_index=contextualized_node.context, context_of_index=contextualized_node.context,
index_value=index_value,
)
) )
for index_value in index_value_set for index_value in index_value_set
) )
@@ -297,7 +300,7 @@ class ClassValue(use_metaclass(CachedMetaClass, ClassMixin, FunctionAndClassBase
if type_var_dict: if type_var_dict:
return ValueSet([GenericClass( return ValueSet([GenericClass(
self, self,
generics=tuple(remap_type_vars()) TupleGenericManager(tuple(remap_type_vars()))
)]) )])
return ValueSet({self}) return ValueSet({self})