1
1
"""Semantic analysis of types"""
2
2
3
3
from collections import OrderedDict
4
- from typing import Callable , List , Optional , Set , Tuple , Iterator , TypeVar , Iterable , Dict
4
+ from typing import Callable , List , Optional , Set , Tuple , Iterator , TypeVar , Iterable , Dict , Union
5
5
from itertools import chain
6
6
7
7
from contextlib import contextmanager
14
14
Type , UnboundType , TypeVarType , TupleType , TypedDictType , UnionType , Instance , AnyType ,
15
15
CallableType , NoneTyp , DeletedType , TypeList , TypeVarDef , TypeVisitor , SyntheticTypeVisitor ,
16
16
StarType , PartialType , EllipsisType , UninhabitedType , TypeType , get_typ_args , set_typ_args ,
17
- CallableArgument , get_type_vars , TypeQuery , union_items , TypeOfAny , ForwardRef , Overloaded
17
+ CallableArgument , get_type_vars , TypeQuery , union_items , TypeOfAny , ForwardRef , Overloaded ,
18
+ TypeTranslator
18
19
)
19
20
20
21
from mypy .nodes import (
21
22
TVAR , TYPE_ALIAS , UNBOUND_IMPORTED , TypeInfo , Context , SymbolTableNode , Var , Expression ,
22
23
IndexExpr , RefExpr , nongen_builtins , check_arg_names , check_arg_kinds , ARG_POS , ARG_NAMED ,
23
24
ARG_OPT , ARG_NAMED_OPT , ARG_STAR , ARG_STAR2 , TypeVarExpr , FuncDef , CallExpr , NameExpr ,
24
- Decorator
25
+ Decorator , Node
25
26
)
26
27
from mypy .tvar_scope import TypeVarScope
27
28
from mypy .sametypes import is_same_type
@@ -656,7 +657,8 @@ def __init__(self,
656
657
plugin : Plugin ,
657
658
options : Options ,
658
659
is_typeshed_stub : bool ,
659
- indicator : Dict [str , bool ]) -> None :
660
+ indicator : Dict [str , bool ],
661
+ patches : List [Tuple [int , Callable [[], None ]]]) -> None :
660
662
self .lookup_func = lookup_func
661
663
self .lookup_fqn_func = lookup_fqn_func
662
664
self .fail = fail_func
@@ -665,6 +667,7 @@ def __init__(self,
665
667
self .plugin = plugin
666
668
self .is_typeshed_stub = is_typeshed_stub
667
669
self .indicator = indicator
670
+ self .patches = patches
668
671
669
672
def visit_instance (self , t : Instance ) -> None :
670
673
info = t .type
@@ -707,64 +710,21 @@ def visit_instance(self, t: Instance) -> None:
707
710
t .args = [AnyType (TypeOfAny .from_error ) for _ in info .type_vars ]
708
711
t .invalid = True
709
712
elif info .defn .type_vars :
710
- # Check type argument values.
711
- # TODO: Calling is_subtype and is_same_types in semantic analysis is a bad idea
712
- for (i , arg ), tvar in zip (enumerate (t .args ), info .defn .type_vars ):
713
- if tvar .values :
714
- if isinstance (arg , TypeVarType ):
715
- arg_values = arg .values
716
- if not arg_values :
717
- self .fail ('Type variable "{}" not valid as type '
718
- 'argument value for "{}"' .format (
719
- arg .name , info .name ()), t )
720
- continue
721
- else :
722
- arg_values = [arg ]
723
- self .check_type_var_values (info , arg_values , tvar .name , tvar .values , i + 1 , t )
724
- # TODO: These hacks will be not necessary when this will be moved to later stage.
725
- arg = self .resolve_type (arg )
726
- bound = self .resolve_type (tvar .upper_bound )
727
- if not is_subtype (arg , bound ):
728
- self .fail ('Type argument "{}" of "{}" must be '
729
- 'a subtype of "{}"' .format (
730
- arg , info .name (), bound ), t )
713
+ # Check type argument values. This is postponed to the end of semantic analysis
714
+ # since we need full MROs and resolved forward references.
715
+ for tvar in info .defn .type_vars :
716
+ if (tvar .values
717
+ or not isinstance (tvar .upper_bound , Instance )
718
+ or tvar .upper_bound .type .fullname () != 'builtins.object' ):
719
+ # Some restrictions on type variable. These can only be checked later
720
+ # after we have final MROs and forward references have been resolved.
721
+ self .indicator ['typevar' ] = True
731
722
for arg in t .args :
732
723
arg .accept (self )
733
724
if info .is_newtype :
734
725
for base in info .bases :
735
726
base .accept (self )
736
727
737
- def check_type_var_values (self , type : TypeInfo , actuals : List [Type ], arg_name : str ,
738
- valids : List [Type ], arg_number : int , context : Context ) -> None :
739
- for actual in actuals :
740
- actual = self .resolve_type (actual )
741
- if (not isinstance (actual , AnyType ) and
742
- not any (is_same_type (actual , self .resolve_type (value ))
743
- for value in valids )):
744
- if len (actuals ) > 1 or not isinstance (actual , Instance ):
745
- self .fail ('Invalid type argument value for "{}"' .format (
746
- type .name ()), context )
747
- else :
748
- class_name = '"{}"' .format (type .name ())
749
- actual_type_name = '"{}"' .format (actual .type .name ())
750
- self .fail (messages .INCOMPATIBLE_TYPEVAR_VALUE .format (
751
- arg_name , class_name , actual_type_name ), context )
752
-
753
- def resolve_type (self , tp : Type ) -> Type :
754
- # This helper is only needed while is_subtype and is_same_type are
755
- # called in third pass. This can be removed when TODO in visit_instance is fixed.
756
- if isinstance (tp , ForwardRef ):
757
- if tp .resolved is None :
758
- return tp .unbound
759
- tp = tp .resolved
760
- if isinstance (tp , Instance ) and tp .type .replaced :
761
- replaced = tp .type .replaced
762
- if replaced .tuple_type :
763
- tp = replaced .tuple_type
764
- if replaced .typeddict_type :
765
- tp = replaced .typeddict_type
766
- return tp
767
-
768
728
def visit_callable_type (self , t : CallableType ) -> None :
769
729
t .ret_type .accept (self )
770
730
for arg_type in t .arg_types :
@@ -1036,3 +996,58 @@ def make_optional_type(t: Type) -> Type:
1036
996
return UnionType (items + [NoneTyp ()], t .line , t .column )
1037
997
else :
1038
998
return UnionType ([t , NoneTyp ()], t .line , t .column )
999
+
1000
+
1001
+ class TypeVariableChecker (TypeTranslator ):
1002
+ """Visitor that checks that type variables in generic types have valid values.
1003
+
1004
+ Note: This must be run at the end of semantic analysis when MROs are
1005
+ complete and forward references have been resolved.
1006
+
1007
+ This does two things:
1008
+
1009
+ - If type variable in C has a value restriction, check that X in C[X] conforms
1010
+ to the restriction.
1011
+ - If type variable in C has a non-default upper bound, check that X in C[X]
1012
+ conforms to the upper bound.
1013
+
1014
+ (This doesn't need to be a type translator, but it simplifies the implementation.)
1015
+ """
1016
+
1017
+ def __init__ (self , fail : Callable [[str , Context ], None ]) -> None :
1018
+ self .fail = fail
1019
+
1020
+ def visit_instance (self , t : Instance ) -> Type :
1021
+ info = t .type
1022
+ for (i , arg ), tvar in zip (enumerate (t .args ), info .defn .type_vars ):
1023
+ if tvar .values :
1024
+ if isinstance (arg , TypeVarType ):
1025
+ arg_values = arg .values
1026
+ if not arg_values :
1027
+ self .fail ('Type variable "{}" not valid as type '
1028
+ 'argument value for "{}"' .format (
1029
+ arg .name , info .name ()), t )
1030
+ continue
1031
+ else :
1032
+ arg_values = [arg ]
1033
+ self .check_type_var_values (info , arg_values , tvar .name , tvar .values , i + 1 , t )
1034
+ if not is_subtype (arg , tvar .upper_bound ):
1035
+ self .fail ('Type argument "{}" of "{}" must be '
1036
+ 'a subtype of "{}"' .format (
1037
+ arg , info .name (), tvar .upper_bound ), t )
1038
+ return t
1039
+
1040
+ def check_type_var_values (self , type : TypeInfo , actuals : List [Type ], arg_name : str ,
1041
+ valids : List [Type ], arg_number : int , context : Context ) -> None :
1042
+ for actual in actuals :
1043
+ if (not isinstance (actual , AnyType ) and
1044
+ not any (is_same_type (actual , value )
1045
+ for value in valids )):
1046
+ if len (actuals ) > 1 or not isinstance (actual , Instance ):
1047
+ self .fail ('Invalid type argument value for "{}"' .format (
1048
+ type .name ()), context )
1049
+ else :
1050
+ class_name = '"{}"' .format (type .name ())
1051
+ actual_type_name = '"{}"' .format (actual .type .name ())
1052
+ self .fail (messages .INCOMPATIBLE_TYPEVAR_VALUE .format (
1053
+ arg_name , class_name , actual_type_name ), context )
0 commit comments