66from collections import defaultdict
77from collections .abc import Iterable ,Iterator ,Mapping ,Sequence ,Set as AbstractSet
88from contextlib import ExitStack ,contextmanager
9- from typing import Callable ,Final ,Generic ,NamedTuple ,Optional ,TypeVar ,Union ,cast ,overload
9+ from typing import (
10+ Callable ,
11+ Final ,
12+ Generic ,
13+ Literal ,
14+ NamedTuple ,
15+ Optional ,
16+ TypeVar ,
17+ Union ,
18+ cast ,
19+ overload ,
20+ )
1021from typing_extensions import TypeAlias as _TypeAlias ,TypeGuard
1122
1223import mypy .checkexpr
130141WhileStmt ,
131142WithStmt ,
132143YieldExpr ,
144+ get_func_def ,
133145is_final_node ,
134146)
135147from mypy .operators import flip_ops ,int_op_to_method ,neg_ops
@@ -276,6 +288,26 @@ class PartialTypeScope(NamedTuple):
276288is_local :bool
277289
278290
291+ class LocalTypeMap :
292+ """Store inferred types into a temporary type map (returned).
293+
294+ This can be used to perform type checking "experiments" without
295+ affecting exported types (which are used by mypyc).
296+ """
297+
298+ def __init__ (self ,chk :TypeChecker )-> None :
299+ self .chk = chk
300+
301+ def __enter__ (self )-> dict [Expression ,Type ]:
302+ temp_type_map :dict [Expression ,Type ]= {}
303+ self .chk ._type_maps .append (temp_type_map )
304+ return temp_type_map
305+
306+ def __exit__ (self ,exc_type :object ,exc_val :object ,exc_tb :object )-> Literal [False ]:
307+ self .chk ._type_maps .pop ()
308+ return False
309+
310+
279311class TypeChecker (NodeVisitor [None ],TypeCheckerSharedApi ):
280312"""Mypy type checker.
281313
@@ -401,6 +433,7 @@ def __init__(
401433self .is_typeshed_stub = tree .is_typeshed_file (options )
402434self .inferred_attribute_types = None
403435self .allow_constructor_cache = True
436+ self .local_type_map = LocalTypeMap (self )
404437
405438# If True, process function definitions. If False, don't. This is used
406439# for processing module top levels in fine-grained incremental mode.
@@ -430,6 +463,13 @@ def __init__(
430463self ._expr_checker = mypy .checkexpr .ExpressionChecker (
431464self ,self .msg ,self .plugin ,per_line_checking_time_ns
432465 )
466+
467+ self ._str_type :Instance | None = None
468+ self ._function_type :Instance | None = None
469+ self ._int_type :Instance | None = None
470+ self ._bool_type :Instance | None = None
471+ self ._object_type :Instance | None = None
472+
433473self .pattern_checker = PatternChecker (self ,self .msg ,self .plugin ,options )
434474self ._unique_id = 0
435475
@@ -703,6 +743,12 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
703743# TODO: keep precise type for callables with tricky but valid signatures.
704744setter_type = fallback_setter_type
705745defn .items [0 ].var .setter_type = setter_type
746+ if isinstance (defn .type ,Overloaded ):
747+ # Update legacy property type for decorated properties.
748+ getter_type = self .extract_callable_type (defn .items [0 ].var .type ,defn )
749+ if getter_type is not None :
750+ getter_type .definition = defn .items [0 ]
751+ defn .type .items [0 ]= getter_type
706752for i ,fdef in enumerate (defn .items ):
707753assert isinstance (fdef ,Decorator )
708754if defn .is_property :
@@ -730,7 +776,7 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
730776assert isinstance (item ,Decorator )
731777item_type = self .extract_callable_type (item .var .type ,item )
732778if item_type is not None :
733- item_type .definition = item . func
779+ item_type .definition = item
734780item_types .append (item_type )
735781if item_types :
736782defn .type = Overloaded (item_types )
@@ -2501,8 +2547,9 @@ def check_override(
25012547
25022548override_ids = override .type_var_ids ()
25032549type_name = None
2504- if isinstance (override .definition ,FuncDef ):
2505- type_name = override .definition .info .name
2550+ definition = get_func_def (override )
2551+ if isinstance (definition ,FuncDef ):
2552+ type_name = definition .info .name
25062553
25072554def erase_override (t :Type )-> Type :
25082555return erase_typevars (t ,ids_to_erase = override_ids )
@@ -3509,6 +3556,7 @@ def check_compatibility_all_supers(self, lvalue: RefExpr, rvalue: Expression) ->
35093556continue
35103557
35113558base_type ,base_node = self .node_type_from_base (lvalue_node .name ,base ,lvalue )
3559+ # TODO: if the r.h.s. is a descriptor, we should check setter override as well.
35123560custom_setter = is_custom_settable_property (base_node )
35133561if isinstance (base_type ,PartialType ):
35143562base_type = None
@@ -4494,6 +4542,8 @@ def set_inferred_type(self, var: Var, lvalue: Lvalue, type: Type) -> None:
44944542if isinstance (p_type ,Overloaded ):
44954543# TODO: in theory we can have a property with a deleter only.
44964544var .is_settable_property = True
4545+ assert isinstance (definition ,Decorator ),definition
4546+ var .setter_type = definition .var .setter_type
44974547
44984548def set_inference_error_fallback_type (self ,var :Var ,lvalue :Lvalue ,type :Type )-> None :
44994549"""Store best known type for variable if type inference failed.
@@ -4613,7 +4663,7 @@ def check_simple_assignment(
46134663# may cause some perf impact, plus we want to partially preserve
46144664# the old behavior. This helps with various practical examples, see
46154665# e.g. testOptionalTypeNarrowedByGenericCall.
4616- with self .msg .filter_errors ()as local_errors ,self .local_type_map () as type_map :
4666+ with self .msg .filter_errors ()as local_errors ,self .local_type_map as type_map :
46174667alt_rvalue_type = self .expr_checker .accept (
46184668rvalue ,None ,always_allow_any = always_allow_any
46194669 )
@@ -5356,6 +5406,8 @@ def visit_decorator_inner(
53565406self .check_untyped_after_decorator (sig ,e .func )
53575407self .require_correct_self_argument (sig ,e .func )
53585408sig = set_callable_name (sig ,e .func )
5409+ if isinstance (sig ,CallableType ):
5410+ sig .definition = e
53595411e .var .type = sig
53605412e .var .is_ready = True
53615413if e .func .is_property :
@@ -6218,21 +6270,26 @@ def find_isinstance_check_helper(
62186270attr = try_getting_str_literals (node .args [1 ],self .lookup_type (node .args [1 ]))
62196271if literal (expr )== LITERAL_TYPE and attr and len (attr )== 1 :
62206272return self .hasattr_type_maps (expr ,self .lookup_type (expr ),attr [0 ])
6221- elif isinstance (node .callee ,RefExpr ):
6222- if node .callee .type_guard is not None or node .callee .type_is is not None :
6273+ else :
6274+ type_is ,type_guard = None ,None
6275+ called_type = self .lookup_type_or_none (node .callee )
6276+ if called_type is not None :
6277+ called_type = get_proper_type (called_type )
6278+ # TODO: there are some more cases in check_call() to handle.
6279+ # If the callee is an instance, try to extract TypeGuard/TypeIs from its __call__ method.
6280+ if isinstance (called_type ,Instance ):
6281+ call = find_member ("__call__" ,called_type ,called_type ,is_operator = True )
6282+ if call is not None :
6283+ called_type = get_proper_type (call )
6284+ if isinstance (called_type ,CallableType ):
6285+ type_is ,type_guard = called_type .type_is ,called_type .type_guard
6286+
6287+ # If the callee is a RefExpr, extract TypeGuard/TypeIs directly.
6288+ if isinstance (node .callee ,RefExpr ):
6289+ type_is ,type_guard = node .callee .type_is ,node .callee .type_guard
6290+ if type_guard is not None or type_is is not None :
62236291# TODO: Follow *args, **kwargs
62246292if node .arg_kinds [0 ]!= nodes .ARG_POS :
6225- # the first argument might be used as a kwarg
6226- called_type = get_proper_type (self .lookup_type (node .callee ))
6227-
6228- # TODO: there are some more cases in check_call() to handle.
6229- if isinstance (called_type ,Instance ):
6230- call = find_member (
6231- "__call__" ,called_type ,called_type ,is_operator = True
6232- )
6233- if call is not None :
6234- called_type = get_proper_type (call )
6235-
62366293# *assuming* the overloaded function is correct, there's a couple cases:
62376294# 1) The first argument has different names, but is pos-only. We don't
62386295# care about this case, the argument must be passed positionally.
@@ -6245,9 +6302,7 @@ def find_isinstance_check_helper(
62456302# we want the idx-th variable to be narrowed
62466303expr = collapse_walrus (node .args [idx ])
62476304else :
6248- kind = (
6249- "guard" if node .callee .type_guard is not None else "narrower"
6250- )
6305+ kind = "guard" if type_guard is not None else "narrower"
62516306self .fail (
62526307message_registry .TYPE_GUARD_POS_ARG_REQUIRED .format (kind ),node
62536308 )
@@ -6258,15 +6313,15 @@ def find_isinstance_check_helper(
62586313# considered "always right" (i.e. even if the types are not overlapping).
62596314# Also note that a care must be taken to unwrap this back at read places
62606315# where we use this to narrow down declared type.
6261- if node . callee . type_guard is not None :
6262- return {expr :TypeGuardedType (node . callee . type_guard )}, {}
6316+ if type_guard is not None :
6317+ return {expr :TypeGuardedType (type_guard )}, {}
62636318else :
6264- assert node . callee . type_is is not None
6319+ assert type_is is not None
62656320return conditional_types_to_typemaps (
62666321expr ,
62676322* self .conditional_types_with_intersection (
62686323self .lookup_type (expr ),
6269- [TypeRange (node . callee . type_is ,is_upper_bound = False )],
6324+ [TypeRange (type_is ,is_upper_bound = False )],
62706325expr ,
62716326consider_runtime_isinstance = False ,
62726327 ),
@@ -7353,6 +7408,29 @@ def named_type(self, name: str) -> Instance:
73537408
73547409 For example, named_type('builtins.object') produces the 'object' type.
73557410 """
7411+ if name == "builtins.str" :
7412+ if self ._str_type is None :
7413+ self ._str_type = self ._named_type (name )
7414+ return self ._str_type
7415+ if name == "builtins.function" :
7416+ if self ._function_type is None :
7417+ self ._function_type = self ._named_type (name )
7418+ return self ._function_type
7419+ if name == "builtins.int" :
7420+ if self ._int_type is None :
7421+ self ._int_type = self ._named_type (name )
7422+ return self ._int_type
7423+ if name == "builtins.bool" :
7424+ if self ._bool_type is None :
7425+ self ._bool_type = self ._named_type (name )
7426+ return self ._bool_type
7427+ if name == "builtins.object" :
7428+ if self ._object_type is None :
7429+ self ._object_type = self ._named_type (name )
7430+ return self ._object_type
7431+ return self ._named_type (name )
7432+
7433+ def _named_type (self ,name :str )-> Instance :
73567434# Assume that the name refers to a type.
73577435sym = self .lookup_qualified (name )
73587436node = sym .node
@@ -7412,18 +7490,6 @@ def lookup_type(self, node: Expression) -> Type:
74127490def store_types (self ,d :dict [Expression ,Type ])-> None :
74137491self ._type_maps [- 1 ].update (d )
74147492
7415- @contextmanager
7416- def local_type_map (self )-> Iterator [dict [Expression ,Type ]]:
7417- """Store inferred types into a temporary type map (returned).
7418-
7419- This can be used to perform type checking "experiments" without
7420- affecting exported types (which are used by mypyc).
7421- """
7422- temp_type_map :dict [Expression ,Type ]= {}
7423- self ._type_maps .append (temp_type_map )
7424- yield temp_type_map
7425- self ._type_maps .pop ()
7426-
74277493def in_checked_function (self )-> bool :
74287494"""Should we type-check the current function?
74297495
@@ -8651,17 +8717,21 @@ def visit_type_alias_type(self, t: TypeAliasType) -> Type:
86518717return t .copy_modified (args = [a .accept (self )for a in t .args ])
86528718
86538719
8654- def is_classmethod_node (node :Node | None )-> bool | None :
8720+ def is_classmethod_node (node :SymbolNode | None )-> bool | None :
86558721"""Find out if a node describes a classmethod."""
8722+ if isinstance (node ,Decorator ):
8723+ node = node .func
86568724if isinstance (node ,FuncDef ):
86578725return node .is_class
86588726if isinstance (node ,Var ):
86598727return node .is_classmethod
86608728return None
86618729
86628730
8663- def is_node_static (node :Node | None )-> bool | None :
8731+ def is_node_static (node :SymbolNode | None )-> bool | None :
86648732"""Find out if a node describes a static function method."""
8733+ if isinstance (node ,Decorator ):
8734+ node = node .func
86658735if isinstance (node ,FuncDef ):
86668736return node .is_static
86678737if isinstance (node ,Var ):