216216
217217T = TypeVar ("T" )
218218
219- DEFAULT_LAST_PASS : Final = 1 # Pass numbers start at 0
219+ DEFAULT_LAST_PASS : Final = 2 # Pass numbers start at 0
220220
221221# Maximum length of fixed tuple types inferred when narrowing from variadic tuples.
222222MAX_PRECISE_TUPLE_SIZE : Final = 8
223223
224- DeferredNodeType : _TypeAlias = Union [FuncDef , LambdaExpr , OverloadedFuncDef , Decorator ]
224+ DeferredNodeType : _TypeAlias = Union [FuncDef , OverloadedFuncDef , Decorator ]
225225FineGrainedDeferredNodeType : _TypeAlias = Union [FuncDef , MypyFile , OverloadedFuncDef ]
226226
227227
228228# A node which is postponed to be processed during the next pass.
229229# In normal mode one can defer functions and methods (also decorated and/or overloaded)
230- # and lambda expressions. Nested functions can't be deferred -- only top-level functions
230+ # but not lambda expressions. Nested functions can't be deferred -- only top-level functions
231231# and methods of classes not defined within a function can be deferred.
232232class DeferredNode (NamedTuple ):
233233 node : DeferredNodeType
234- # And its TypeInfo (for semantic analysis self type handling
234+ # And its TypeInfo (for semantic analysis self type handling)
235235 active_typeinfo : TypeInfo | None
236236
237237
@@ -528,10 +528,7 @@ def check_partial(self, node: DeferredNodeType | FineGrainedDeferredNodeType) ->
528528 else :
529529 self .recurse_into_functions = True
530530 with self .binder .top_frame_context ():
531- if isinstance (node , LambdaExpr ):
532- self .expr_checker .accept (node )
533- else :
534- self .accept (node )
531+ self .accept (node )
535532
536533 def check_top_level (self , node : MypyFile ) -> None :
537534 """Check only the top-level of a module, skipping function definitions."""
@@ -558,13 +555,13 @@ def defer_node(self, node: DeferredNodeType, enclosing_class: TypeInfo | None) -
558555 self .deferred_nodes .append (DeferredNode (node , enclosing_class ))
559556
560557 def handle_cannot_determine_type (self , name : str , context : Context ) -> None :
561- node = self .scope .top_non_lambda_function ()
558+ node = self .scope .top_level_function ()
562559 if self .pass_num < self .last_pass and isinstance (node , FuncDef ):
563560 # Don't report an error yet. Just defer. Note that we don't defer
564561 # lambdas because they are coupled to the surrounding function
565562 # through the binder and the inferred type of the lambda, so it
566563 # would get messy.
567- enclosing_class = self .scope .enclosing_class ()
564+ enclosing_class = self .scope .enclosing_class (node )
568565 self .defer_node (node , enclosing_class )
569566 # Set a marker so that we won't infer additional types in this
570567 # function. Any inferred types could be bogus, because there's at
@@ -1111,6 +1108,7 @@ def check_func_item(
11111108 """
11121109 self .dynamic_funcs .append (defn .is_dynamic () and not type_override )
11131110
1111+ enclosing_node_deferred = self .current_node_deferred
11141112 with self .enter_partial_types (is_function = True ):
11151113 typ = self .function_type (defn )
11161114 if type_override :
@@ -1122,7 +1120,7 @@ def check_func_item(
11221120 raise RuntimeError ("Not supported" )
11231121
11241122 self .dynamic_funcs .pop ()
1125- self .current_node_deferred = False
1123+ self .current_node_deferred = enclosing_node_deferred
11261124
11271125 if name == "__exit__" :
11281126 self .check__exit__return_type (defn )
@@ -2156,7 +2154,14 @@ def check_method_override_for_base_with_name(
21562154 if self .pass_num < self .last_pass :
21572155 # If there are passes left, defer this node until next pass,
21582156 # otherwise try reconstructing the method type from available information.
2159- self .defer_node (defn , defn .info )
2157+ # For consistency, defer an enclosing top-level function (if any).
2158+ top_level = self .scope .top_level_function ()
2159+ if isinstance (top_level , FuncDef ):
2160+ self .defer_node (top_level , self .scope .enclosing_class (top_level ))
2161+ else :
2162+ # Specify enclosing class explicitly, as we check type override before
2163+ # entering e.g. decorators or overloads.
2164+ self .defer_node (defn , defn .info )
21602165 return True
21612166 elif isinstance (original_node , (FuncDef , OverloadedFuncDef )):
21622167 original_type = self .function_type (original_node )
@@ -4767,7 +4772,7 @@ def visit_return_stmt(self, s: ReturnStmt) -> None:
47674772 self .binder .unreachable ()
47684773
47694774 def check_return_stmt (self , s : ReturnStmt ) -> None :
4770- defn = self .scope .top_function ()
4775+ defn = self .scope .current_function ()
47714776 if defn is not None :
47724777 if defn .is_generator :
47734778 return_type = self .get_generator_return_type (
@@ -4779,7 +4784,7 @@ def check_return_stmt(self, s: ReturnStmt) -> None:
47794784 return_type = self .return_types [- 1 ]
47804785 return_type = get_proper_type (return_type )
47814786
4782- is_lambda = isinstance (self . scope . top_function () , LambdaExpr )
4787+ is_lambda = isinstance (defn , LambdaExpr )
47834788 if isinstance (return_type , UninhabitedType ):
47844789 # Avoid extra error messages for failed inference in lambdas
47854790 if not is_lambda and not return_type .ambiguous :
@@ -5337,6 +5342,7 @@ def check_for_untyped_decorator(
53375342 self .options .disallow_untyped_decorators
53385343 and is_typed_callable (func .type )
53395344 and is_untyped_decorator (dec_type )
5345+ and not self .current_node_deferred
53405346 ):
53415347 self .msg .typed_function_untyped_decorator (func .name , dec_expr )
53425348
@@ -8554,14 +8560,15 @@ class CheckerScope:
85548560 def __init__ (self , module : MypyFile ) -> None :
85558561 self .stack = [module ]
85568562
8557- def top_function (self ) -> FuncItem | None :
8563+ def current_function (self ) -> FuncItem | None :
85588564 for e in reversed (self .stack ):
85598565 if isinstance (e , FuncItem ):
85608566 return e
85618567 return None
85628568
8563- def top_non_lambda_function (self ) -> FuncItem | None :
8564- for e in reversed (self .stack ):
8569+ def top_level_function (self ) -> FuncItem | None :
8570+ """Return top-level non-lambda function."""
8571+ for e in self .stack :
85658572 if isinstance (e , FuncItem ) and not isinstance (e , LambdaExpr ):
85668573 return e
85678574 return None
@@ -8571,11 +8578,11 @@ def active_class(self) -> TypeInfo | None:
85718578 return self .stack [- 1 ]
85728579 return None
85738580
8574- def enclosing_class (self ) -> TypeInfo | None :
8581+ def enclosing_class (self , func : FuncItem | None = None ) -> TypeInfo | None :
85758582 """Is there a class *directly* enclosing this function?"""
8576- top = self .top_function ()
8577- assert top , "This method must be called from inside a function"
8578- index = self .stack .index (top )
8583+ func = func or self .current_function ()
8584+ assert func , "This method must be called from inside a function"
8585+ index = self .stack .index (func )
85798586 assert index , "CheckerScope stack must always start with a module"
85808587 enclosing = self .stack [index - 1 ]
85818588 if isinstance (enclosing , TypeInfo ):
@@ -8589,7 +8596,7 @@ def active_self_type(self) -> Instance | TupleType | None:
85898596 In particular, inside a function nested in method this returns None.
85908597 """
85918598 info = self .active_class ()
8592- if not info and self .top_function ():
8599+ if not info and self .current_function ():
85938600 info = self .enclosing_class ()
85948601 if info :
85958602 return fill_typevars (info )
0 commit comments