23
23
"""
24
24
25
25
from typing import (
26
- List , Optional , Tuple , Dict , Callable , Union , NamedTuple , TypeVar , Iterator ,
26
+ List , Optional , Tuple , Dict , Callable , Union , NamedTuple , TypeVar , Iterator , cast ,
27
27
)
28
28
from typing_extensions import TypedDict
29
29
30
30
from mypy .state import strict_optional_set
31
31
from mypy .types import (
32
32
Type , AnyType , TypeOfAny , CallableType , UnionType , NoneType , Instance , TupleType ,
33
- TypeVarType , FunctionLike ,
33
+ TypeVarType , FunctionLike , UninhabitedType ,
34
34
TypeStrVisitor , TypeTranslator ,
35
35
is_optional , remove_optional , ProperType , get_proper_type ,
36
36
TypedDictType , TypeAliasType
@@ -282,17 +282,19 @@ def with_export_types(self) -> Iterator[None]:
282
282
283
283
def get_trivial_type (self , fdef : FuncDef ) -> CallableType :
284
284
"""Generate a trivial callable type from a func def, with all Anys"""
285
+ # The Anys are marked as being from the suggestion engine
286
+ # since they need some special treatment (specifically,
287
+ # constraint generation ignores them.)
285
288
return CallableType (
286
- [AnyType (TypeOfAny .unannotated ) for a in fdef .arg_kinds ],
289
+ [AnyType (TypeOfAny .suggestion_engine ) for a in fdef .arg_kinds ],
287
290
fdef .arg_kinds ,
288
291
fdef .arg_names ,
289
- # We call this a special form so that has_any_type doesn't consider it to be a real any
290
- AnyType (TypeOfAny .special_form ),
292
+ AnyType (TypeOfAny .suggestion_engine ),
291
293
self .builtin_type ('builtins.function' ))
292
294
293
295
def get_starting_type (self , fdef : FuncDef ) -> CallableType :
294
296
if isinstance (fdef .type , CallableType ):
295
- return fdef .type
297
+ return make_suggestion_anys ( fdef .type )
296
298
else :
297
299
return self .get_trivial_type (fdef )
298
300
@@ -304,9 +306,8 @@ def get_args(self, is_method: bool,
304
306
types = [] # type: List[List[Type]]
305
307
for i in range (len (base .arg_kinds )):
306
308
# Make self args Any but this will get overriden somewhere in the checker
307
- # We call this a special form so that has_any_type doesn't consider it to be a real any
308
309
if i == 0 and is_method :
309
- types .append ([AnyType (TypeOfAny .special_form )])
310
+ types .append ([AnyType (TypeOfAny .suggestion_engine )])
310
311
continue
311
312
312
313
all_arg_types = []
@@ -383,13 +384,16 @@ def get_callsites(self, func: FuncDef) -> Tuple[List[Callsite], List[str]]:
383
384
384
385
return collector_plugin .mystery_hits , errors
385
386
386
- def filter_options (self , guesses : List [CallableType ], is_method : bool ) -> List [CallableType ]:
387
+ def filter_options (
388
+ self , guesses : List [CallableType ], is_method : bool , ignore_return : bool
389
+ ) -> List [CallableType ]:
387
390
"""Apply any configured filters to the possible guesses.
388
391
389
392
Currently the only option is filtering based on Any prevalance."""
390
393
return [
391
394
t for t in guesses
392
- if self .flex_any is None or any_score_callable (t , is_method ) >= self .flex_any
395
+ if self .flex_any is None
396
+ or any_score_callable (t , is_method , ignore_return ) >= self .flex_any
393
397
]
394
398
395
399
def find_best (self , func : FuncDef , guesses : List [CallableType ]) -> Tuple [CallableType , int ]:
@@ -426,7 +430,7 @@ def get_suggestion(self, mod: str, node: FuncDef) -> PyAnnotateSignature:
426
430
callsites ,
427
431
uses ,
428
432
)
429
- guesses = self .filter_options (guesses , is_method )
433
+ guesses = self .filter_options (guesses , is_method , ignore_return = True )
430
434
best , _ = self .find_best (node , guesses )
431
435
432
436
# Now try to find the return type!
@@ -439,7 +443,7 @@ def get_suggestion(self, mod: str, node: FuncDef) -> PyAnnotateSignature:
439
443
ret_types = [NoneType ()]
440
444
441
445
guesses = [best .copy_modified (ret_type = refine_type (best .ret_type , t )) for t in ret_types ]
442
- guesses = self .filter_options (guesses , is_method )
446
+ guesses = self .filter_options (guesses , is_method , ignore_return = False )
443
447
best , errors = self .find_best (node , guesses )
444
448
445
449
if self .no_errors and errors :
@@ -710,7 +714,7 @@ def any_score_type(ut: Type, arg_pos: bool) -> float:
710
714
Higher is better, 1.0 is max
711
715
"""
712
716
t = get_proper_type (ut )
713
- if isinstance (t , AnyType ) and t .type_of_any != TypeOfAny .special_form :
717
+ if isinstance (t , AnyType ) and t .type_of_any != TypeOfAny .suggestion_engine :
714
718
return 0
715
719
if isinstance (t , NoneType ) and arg_pos :
716
720
return 0.5
@@ -727,14 +731,14 @@ def any_score_type(ut: Type, arg_pos: bool) -> float:
727
731
return 1.0
728
732
729
733
730
- def any_score_callable (t : CallableType , is_method : bool ) -> float :
734
+ def any_score_callable (t : CallableType , is_method : bool , ignore_return : bool ) -> float :
731
735
# Ignore the first argument of methods
732
736
scores = [any_score_type (x , arg_pos = True ) for x in t .arg_types [int (is_method ):]]
733
737
# Return type counts twice (since it spreads type information), unless it is
734
738
# None in which case it does not count at all. (Though it *does* still count
735
739
# if there are no arguments.)
736
740
if not isinstance (get_proper_type (t .ret_type ), NoneType ) or not scores :
737
- ret = any_score_type (t .ret_type , arg_pos = False )
741
+ ret = 1.0 if ignore_return else any_score_type (t .ret_type , arg_pos = False )
738
742
scores += [ret , ret ]
739
743
740
744
return sum (scores ) / len (scores )
@@ -796,6 +800,9 @@ def visit_tuple_type(self, t: TupleType) -> str:
796
800
s = self .list_str (t .items )
797
801
return 'Tuple[{}]' .format (s )
798
802
803
+ def visit_uninhabited_type (self , t : UninhabitedType ) -> str :
804
+ return "Any"
805
+
799
806
def visit_typeddict_type (self , t : TypedDictType ) -> str :
800
807
return t .fallback .accept (self )
801
808
@@ -837,6 +844,26 @@ def visit_instance(self, t: Instance) -> Type:
837
844
return super ().visit_instance (t )
838
845
839
846
847
+ TType = TypeVar ('TType' , bound = Type )
848
+
849
+
850
+ def make_suggestion_anys (t : TType ) -> TType :
851
+ """Make all anys in the type as coming from the suggestion engine.
852
+
853
+ This keeps those Anys from influencing constraint generation,
854
+ which allows us to do better when refining types.
855
+ """
856
+ return cast (TType , t .accept (MakeSuggestionAny ()))
857
+
858
+
859
+ class MakeSuggestionAny (TypeTranslator ):
860
+ def visit_any (self , t : AnyType ) -> Type :
861
+ return t .copy_modified (type_of_any = TypeOfAny .suggestion_engine )
862
+
863
+ def visit_type_alias_type (self , t : TypeAliasType ) -> Type :
864
+ return t .copy_modified (args = [a .accept (self ) for a in t .args ])
865
+
866
+
840
867
def generate_type_combinations (types : List [Type ]) -> List [Type ]:
841
868
"""Generate possible combinations of a list of types.
842
869
0 commit comments