@@ -719,10 +719,25 @@ def accept_loop(
719719 # Definitions
720720 #
721721
722+ @contextmanager
723+ def set_recurse_into_functions (self ) -> Iterator [None ]:
724+ """Temporarily set recurse_into_functions to True.
725+
726+ This is used to process top-level functions/methods as a whole.
727+ """
728+ old_recurse_into_functions = self .recurse_into_functions
729+ self .recurse_into_functions = True
730+ try :
731+ yield
732+ finally :
733+ self .recurse_into_functions = old_recurse_into_functions
734+
722735 def visit_overloaded_func_def (self , defn : OverloadedFuncDef ) -> None :
723- if not self .recurse_into_functions :
736+ # If a function/method can infer variable types, it should be processed as part
737+ # of the module top level (i.e. module interface).
738+ if not self .recurse_into_functions and not defn .can_infer_vars :
724739 return
725- with self .tscope .function_scope (defn ):
740+ with self .tscope .function_scope (defn ), self . set_recurse_into_functions () :
726741 self ._visit_overloaded_func_def (defn )
727742
728743 def _visit_overloaded_func_def (self , defn : OverloadedFuncDef ) -> None :
@@ -1196,9 +1211,9 @@ def get_generator_return_type(self, return_type: Type, is_coroutine: bool) -> Ty
11961211 return NoneType ()
11971212
11981213 def visit_func_def (self , defn : FuncDef ) -> None :
1199- if not self .recurse_into_functions :
1214+ if not self .recurse_into_functions and not defn . can_infer_vars :
12001215 return
1201- with self .tscope .function_scope (defn ):
1216+ with self .tscope .function_scope (defn ), self . set_recurse_into_functions () :
12021217 self .check_func_item (defn , name = defn .name )
12031218 if not self .can_skip_diagnostics :
12041219 if defn .info :
@@ -1438,6 +1453,7 @@ def check_func_def(
14381453 or self .options .preserve_asts
14391454 or not isinstance (defn , FuncDef )
14401455 or defn .has_self_attr_def
1456+ or defn .can_infer_vars
14411457 ):
14421458 self .accept (item .body )
14431459 unreachable = self .binder .is_unreachable ()
@@ -5604,8 +5620,8 @@ def visit_decorator(self, e: Decorator) -> None:
56045620 def visit_decorator_inner (
56055621 self , e : Decorator , allow_empty : bool = False , skip_first_item : bool = False
56065622 ) -> None :
5607- if self .recurse_into_functions :
5608- with self .tscope .function_scope (e .func ):
5623+ if self .recurse_into_functions or e . func . can_infer_vars :
5624+ with self .tscope .function_scope (e .func ), self . set_recurse_into_functions () :
56095625 self .check_func_item (e .func , name = e .func .name , allow_empty = allow_empty )
56105626
56115627 # Process decorators from the inside out to determine decorated signature, which
@@ -7718,30 +7734,7 @@ def enter_partial_types(
77187734 partial_types , _ , _ = self .partial_types .pop ()
77197735 if not self .current_node_deferred :
77207736 for var , context in partial_types .items ():
7721- # If we require local partial types, there are a few exceptions where
7722- # we fall back to inferring just "None" as the type from a None initializer:
7723- #
7724- # 1. If all happens within a single function this is acceptable, since only
7725- # the topmost function is a separate target in fine-grained incremental mode.
7726- # We primarily want to avoid "splitting" partial types across targets.
7727- #
7728- # 2. A None initializer in the class body if the attribute is defined in a base
7729- # class is fine, since the attribute is already defined and it's currently okay
7730- # to vary the type of an attribute covariantly. The None type will still be
7731- # checked for compatibility with base classes elsewhere. Without this exception
7732- # mypy could require an annotation for an attribute that already has been
7733- # declared in a base class, which would be bad.
7734- allow_none = (
7735- not self .options .local_partial_types
7736- or is_function
7737- or (is_class and self .is_defined_in_base_class (var ))
7738- )
7739- if (
7740- allow_none
7741- and isinstance (var .type , PartialType )
7742- and var .type .type is None
7743- and not permissive
7744- ):
7737+ if isinstance (var .type , PartialType ) and var .type .type is None and not permissive :
77457738 var .type = NoneType ()
77467739 else :
77477740 if var not in self .partial_reported and not permissive :
@@ -7812,10 +7805,15 @@ def find_partial_types_in_all_scopes(
78127805 # for fine-grained incremental mode).
78137806 disallow_other_scopes = self .options .local_partial_types
78147807
7808+ # There are two exceptions:
78157809 if isinstance (var .type , PartialType ) and var .type .type is not None and var .info :
7816- # This is an ugly hack to make partial generic self attributes behave
7817- # as if --local-partial-types is always on (because it used to be like this) .
7810+ # We always prohibit non-None partial types at class scope
7811+ # for historical reasons .
78187812 disallow_other_scopes = True
7813+ if isinstance (var .type , PartialType ) and var .type .type is None :
7814+ # We always allow None partial types, since this is a common use case.
7815+ # It is special-cased in fine-grained incremental mode.
7816+ disallow_other_scopes = False
78197817
78207818 scope_active = (
78217819 not disallow_other_scopes or scope .is_local == self .partial_types [- 1 ].is_local
0 commit comments