85
85
from mypy import join
86
86
from mypy .util import get_prefix , correct_relative_import
87
87
from mypy .semanal_shared import PRIORITY_FALLBACKS
88
+ from mypy .scope import Scope
88
89
89
90
90
91
T = TypeVar ('T' )
@@ -255,6 +256,7 @@ def __init__(self,
255
256
# If True, process function definitions. If False, don't. This is used
256
257
# for processing module top levels in fine-grained incremental mode.
257
258
self .recurse_into_functions = True
259
+ self .scope = Scope ()
258
260
259
261
def visit_file (self , file_node : MypyFile , fnam : str , options : Options ,
260
262
patches : List [Tuple [int , Callable [[], None ]]]) -> None :
@@ -287,8 +289,10 @@ def visit_file(self, file_node: MypyFile, fnam: str, options: Options,
287
289
v .is_ready = True
288
290
289
291
defs = file_node .defs
292
+ self .scope .enter_file (file_node .fullname ())
290
293
for d in defs :
291
294
self .accept (d )
295
+ self .scope .leave ()
292
296
293
297
if self .cur_mod_id == 'builtins' :
294
298
remove_imported_names_from_symtable (self .globals , 'builtins' )
@@ -305,11 +309,13 @@ def visit_file(self, file_node: MypyFile, fnam: str, options: Options,
305
309
306
310
def refresh_partial (self , node : Union [MypyFile , FuncItem , OverloadedFuncDef ]) -> None :
307
311
"""Refresh a stale target in fine-grained incremental mode."""
312
+ self .scope .enter_file (self .cur_mod_id )
308
313
if isinstance (node , MypyFile ):
309
314
self .refresh_top_level (node )
310
315
else :
311
316
self .recurse_into_functions = True
312
317
self .accept (node )
318
+ self .scope .leave ()
313
319
314
320
def refresh_top_level (self , file_node : MypyFile ) -> None :
315
321
"""Reanalyze a stale module top-level in fine-grained incremental mode."""
@@ -591,15 +597,19 @@ def analyze_property_with_multi_part_definition(self, defn: OverloadedFuncDef) -
591
597
592
598
def analyze_function (self , defn : FuncItem ) -> None :
593
599
is_method = self .is_class_scope ()
600
+ self .scope .enter_function (defn )
594
601
with self .tvar_scope_frame (self .tvar_scope .method_frame ()):
595
602
if defn .type :
596
603
self .check_classvar_in_signature (defn .type )
597
604
assert isinstance (defn .type , CallableType )
598
605
# Signature must be analyzed in the surrounding scope so that
599
606
# class-level imported names and type variables are in scope.
600
- defn .type = self .type_analyzer ().visit_callable_type (defn .type , nested = False )
607
+ analyzer = self .type_analyzer ()
608
+ defn .type = analyzer .visit_callable_type (defn .type , nested = False )
609
+ self .add_type_alias_deps (analyzer .aliases_used )
601
610
self .check_function_signature (defn )
602
611
if isinstance (defn , FuncDef ):
612
+ assert isinstance (defn .type , CallableType )
603
613
defn .type = set_callable_name (defn .type , defn )
604
614
for arg in defn .arguments :
605
615
if arg .initializer :
@@ -633,6 +643,7 @@ def analyze_function(self, defn: FuncItem) -> None:
633
643
634
644
self .leave ()
635
645
self .function_stack .pop ()
646
+ self .scope .leave ()
636
647
637
648
def check_classvar_in_signature (self , typ : Type ) -> None :
638
649
if isinstance (typ , Overloaded ):
@@ -660,10 +671,12 @@ def check_function_signature(self, fdef: FuncItem) -> None:
660
671
self .fail ('Type signature has too many arguments' , fdef , blocker = True )
661
672
662
673
def visit_class_def (self , defn : ClassDef ) -> None :
674
+ self .scope .enter_class (defn .info )
663
675
with self .analyze_class_body (defn ) as should_continue :
664
676
if should_continue :
665
677
# Analyze class body.
666
678
defn .defs .accept (self )
679
+ self .scope .leave ()
667
680
668
681
@contextmanager
669
682
def analyze_class_body (self , defn : ClassDef ) -> Iterator [bool ]:
@@ -1679,7 +1692,24 @@ def anal_type(self, t: Type, *,
1679
1692
aliasing = aliasing ,
1680
1693
allow_tuple_literal = allow_tuple_literal ,
1681
1694
third_pass = third_pass )
1682
- return t .accept (a )
1695
+ typ = t .accept (a )
1696
+ self .add_type_alias_deps (a .aliases_used )
1697
+ return typ
1698
+
1699
+ def add_type_alias_deps (self , aliases_used : Iterable [str ],
1700
+ target : Optional [str ] = None ) -> None :
1701
+ """Add full names of type aliases on which the current node depends.
1702
+
1703
+ This is used by fine-grained incremental mode to re-check the corresponding nodes.
1704
+ If `target` is None, then the target node used will be the current scope.
1705
+ """
1706
+ if not aliases_used :
1707
+ # A basic optimization to avoid adding targets with no dependencies to
1708
+ # the `alias_deps` dict.
1709
+ return
1710
+ if target is None :
1711
+ target = self .scope .current_target ()
1712
+ self .cur_mod_node .alias_deps [target ].update (aliases_used )
1683
1713
1684
1714
def visit_assignment_stmt (self , s : AssignmentStmt ) -> None :
1685
1715
for lval in s .lvalues :
@@ -1755,10 +1785,17 @@ def alias_fallback(self, tp: Type) -> Instance:
1755
1785
return Instance (fb_info , [])
1756
1786
1757
1787
def analyze_alias (self , rvalue : Expression ,
1758
- warn_bound_tvar : bool = False ) -> Tuple [Optional [Type ], List [str ]]:
1759
- """Check if 'rvalue' represents a valid type allowed for aliasing
1760
- (e.g. not a type variable). If yes, return the corresponding type and a list of
1761
- qualified type variable names for generic aliases.
1788
+ warn_bound_tvar : bool = False ) -> Tuple [Optional [Type ], List [str ],
1789
+ Set [str ], List [str ]]:
1790
+ """Check if 'rvalue' is a valid type allowed for aliasing (e.g. not a type variable).
1791
+
1792
+ If yes, return the corresponding type, a list of
1793
+ qualified type variable names for generic aliases, a set of names the alias depends on,
1794
+ and a list of type variables if the alias is generic.
1795
+ An schematic example for the dependencies:
1796
+ A = int
1797
+ B = str
1798
+ analyze_alias(Dict[A, B])[2] == {'__main__.A', '__main__.B'}
1762
1799
"""
1763
1800
dynamic = bool (self .function_stack and self .function_stack [- 1 ].is_dynamic ())
1764
1801
global_scope = not self .type and not self .function_stack
@@ -1775,15 +1812,21 @@ def analyze_alias(self, rvalue: Expression,
1775
1812
in_dynamic_func = dynamic ,
1776
1813
global_scope = global_scope ,
1777
1814
warn_bound_tvar = warn_bound_tvar )
1815
+ typ = None # type: Optional[Type]
1778
1816
if res :
1779
- alias_tvars = [name for (name , _ ) in
1780
- res .accept (TypeVariableQuery (self .lookup_qualified , self .tvar_scope ))]
1817
+ typ , depends_on = res
1818
+ found_type_vars = typ .accept (TypeVariableQuery (self .lookup_qualified , self .tvar_scope ))
1819
+ alias_tvars = [name for (name , node ) in found_type_vars ]
1820
+ qualified_tvars = [node .fullname () for (name , node ) in found_type_vars ]
1781
1821
else :
1782
1822
alias_tvars = []
1783
- return res , alias_tvars
1823
+ depends_on = set ()
1824
+ qualified_tvars = []
1825
+ return typ , alias_tvars , depends_on , qualified_tvars
1784
1826
1785
1827
def check_and_set_up_type_alias (self , s : AssignmentStmt ) -> None :
1786
1828
"""Check if assignment creates a type alias and set it up as needed.
1829
+
1787
1830
For simple aliases like L = List we use a simpler mechanism, just copying TypeInfo.
1788
1831
For subscripted (including generic) aliases the resulting types are stored
1789
1832
in rvalue.analyzed.
@@ -1809,11 +1852,20 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> None:
1809
1852
# annotations (see the second rule).
1810
1853
return
1811
1854
rvalue = s .rvalue
1812
- res , alias_tvars = self .analyze_alias (rvalue , warn_bound_tvar = True )
1855
+ res , alias_tvars , depends_on , qualified_tvars = self .analyze_alias (rvalue ,
1856
+ warn_bound_tvar = True )
1813
1857
if not res :
1814
1858
return
1859
+ s .is_alias_def = True
1815
1860
node = self .lookup (lvalue .name , lvalue )
1816
1861
assert node is not None
1862
+ if lvalue .fullname is not None :
1863
+ node .alias_name = lvalue .fullname
1864
+ self .add_type_alias_deps (depends_on )
1865
+ self .add_type_alias_deps (qualified_tvars )
1866
+ # The above are only direct deps on other aliases.
1867
+ # For subscripted aliases, type deps from expansion are added in deps.py
1868
+ # (because the type is stored)
1817
1869
if not lvalue .is_inferred_def :
1818
1870
# Type aliases can't be re-defined.
1819
1871
if node and (node .kind == TYPE_ALIAS or isinstance (node .node , TypeInfo )):
@@ -1830,7 +1882,14 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> None:
1830
1882
# For simple (on-generic) aliases we use aliasing TypeInfo's
1831
1883
# to allow using them in runtime context where it makes sense.
1832
1884
node .node = res .type
1885
+ node .is_aliasing = True
1833
1886
if isinstance (rvalue , RefExpr ):
1887
+ # For non-subscripted aliases we add type deps right here
1888
+ # (because the node is stored, not type)
1889
+ # TODO: currently subscripted and unsubscripted aliases are processed differently
1890
+ # This leads to duplication of most of the logic with small variations.
1891
+ # Fix this.
1892
+ self .add_type_alias_deps ({node .node .fullname ()})
1834
1893
sym = self .lookup_type_node (rvalue )
1835
1894
if sym :
1836
1895
node .normalized = sym .normalized
@@ -3445,12 +3504,15 @@ def visit_index_expr(self, expr: IndexExpr) -> None:
3445
3504
elif isinstance (expr .base , RefExpr ) and expr .base .kind == TYPE_ALIAS :
3446
3505
# Special form -- subscripting a generic type alias.
3447
3506
# Perform the type substitution and create a new alias.
3448
- res , alias_tvars = self .analyze_alias (expr )
3507
+ res , alias_tvars , depends_on , _ = self .analyze_alias (expr )
3449
3508
assert res is not None , "Failed analyzing already defined alias"
3450
3509
expr .analyzed = TypeAliasExpr (res , alias_tvars , fallback = self .alias_fallback (res ),
3451
3510
in_runtime = True )
3452
3511
expr .analyzed .line = expr .line
3453
3512
expr .analyzed .column = expr .column
3513
+ # We also store fine-grained dependencies to correctly re-process nodes
3514
+ # with situations like `L = LongGeneric; x = L[int]()`.
3515
+ self .add_type_alias_deps (depends_on )
3454
3516
elif refers_to_class_or_function (expr .base ):
3455
3517
# Special form -- type application.
3456
3518
# Translate index to an unanalyzed type.
0 commit comments