1
1
"""Expression type checker. This file is conceptually part of TypeChecker."""
2
2
3
- from typing import cast , Dict , List , Tuple , Callable , Union , Optional
3
+ from typing import cast , Dict , Set , List , Iterable , Tuple , Callable , Union , Optional
4
4
5
5
from mypy .types import (
6
6
Type , AnyType , CallableType , Overloaded , NoneTyp , Void , TypeVarDef ,
16
16
ListComprehension , GeneratorExpr , SetExpr , MypyFile , Decorator ,
17
17
ConditionalExpr , ComparisonExpr , TempNode , SetComprehension ,
18
18
DictionaryComprehension , ComplexExpr , EllipsisExpr , StarExpr ,
19
- TypeAliasExpr , BackquoteExpr , ARG_POS , ARG_NAMED , ARG_STAR2
19
+ TypeAliasExpr , BackquoteExpr , ARG_POS , ARG_NAMED , ARG_STAR2 , MODULE_REF ,
20
20
)
21
21
from mypy .nodes import function_type
22
22
from mypy import nodes
45
45
None ]
46
46
47
47
48
+ def split_module_names (mod_name : str ) -> Iterable [str ]:
49
+ """Yields the module and all parent module names.
50
+
51
+ So, if `mod_name` is 'a.b.c', this function will yield
52
+ ['a.b.c', 'a.b', and 'a']."""
53
+ yield mod_name
54
+ while '.' in mod_name :
55
+ mod_name = mod_name .rsplit ('.' , 1 )[0 ]
56
+ yield mod_name
57
+
58
+
59
+ def extract_refexpr_names (expr : RefExpr ) -> Set [str ]:
60
+ """Recursively extracts all module references from a reference expression.
61
+
62
+ Note that currently, the only two subclasses of RefExpr are NameExpr and
63
+ MemberExpr."""
64
+ output = set () # type: Set[str]
65
+ while expr .kind == MODULE_REF or expr .fullname is not None :
66
+ if expr .kind == MODULE_REF :
67
+ output .add (expr .fullname )
68
+ elif expr .fullname is not None and '.' in expr .fullname :
69
+ output .add (expr .fullname .rsplit ('.' , 1 )[0 ])
70
+
71
+ if isinstance (expr , NameExpr ):
72
+ if expr .info is not None :
73
+ output .update (split_module_names (expr .info .module_name ))
74
+ break
75
+ elif isinstance (expr , MemberExpr ):
76
+ if isinstance (expr .expr , RefExpr ):
77
+ expr = expr .expr
78
+ else :
79
+ break
80
+ else :
81
+ raise AssertionError ("Unknown RefExpr subclass: {}" .format (type (expr )))
82
+ return output
83
+
84
+
48
85
class Finished (Exception ):
49
86
"""Raised if we can terminate overload argument check early (no match)."""
50
87
@@ -70,11 +107,16 @@ def __init__(self,
70
107
self .msg = msg
71
108
self .strfrm_checker = StringFormatterChecker (self , self .chk , self .msg )
72
109
110
+ def _visit_typeinfo (self , info : nodes .TypeInfo ) -> None :
111
+ if info is not None :
112
+ self .chk .module_refs .update (split_module_names (info .module_name ))
113
+
73
114
def visit_name_expr (self , e : NameExpr ) -> Type :
74
115
"""Type check a name expression.
75
116
76
117
It can be of any kind: local, member or global.
77
118
"""
119
+ self .chk .module_refs .update (extract_refexpr_names (e ))
78
120
result = self .analyze_ref_expr (e )
79
121
return self .chk .narrow_type_from_binder (e , result )
80
122
@@ -858,6 +900,7 @@ def apply_generic_arguments2(self, overload: Overloaded, types: List[Type],
858
900
859
901
def visit_member_expr (self , e : MemberExpr ) -> Type :
860
902
"""Visit member expression (of form e.id)."""
903
+ self .chk .module_refs .update (extract_refexpr_names (e ))
861
904
result = self .analyze_ordinary_member_access (e , False )
862
905
return self .chk .narrow_type_from_binder (e , result )
863
906
0 commit comments