@@ -359,6 +359,9 @@ def __init__(
359359 ] = {}
360360 self .in_lambda_expr = False
361361
362+ self ._literal_true : Instance | None = None
363+ self ._literal_false : Instance | None = None
364+
362365 def reset (self ) -> None :
363366 self .resolved_type = {}
364367 self .expr_cache .clear ()
@@ -1071,7 +1074,7 @@ def check_typeddict_call_with_kwargs(
10711074
10721075 # We don't show any errors, just infer types in a generic TypedDict type,
10731076 # a custom error message will be given below, if there are errors.
1074- with self .msg .filter_errors (), self .chk .local_type_map () :
1077+ with self .msg .filter_errors (), self .chk .local_type_map :
10751078 orig_ret_type , _ = self .check_callable_call (
10761079 infer_callee ,
10771080 # We use first expression for each key to infer type variables of a generic
@@ -1436,7 +1439,7 @@ def is_generic_decorator_overload_call(
14361439 return None
14371440 if not isinstance (get_proper_type (callee_type .ret_type ), CallableType ):
14381441 return None
1439- with self .chk .local_type_map () :
1442+ with self .chk .local_type_map :
14401443 with self .msg .filter_errors ():
14411444 arg_type = get_proper_type (self .accept (args [0 ], type_context = None ))
14421445 if isinstance (arg_type , Overloaded ):
@@ -2718,6 +2721,7 @@ def check_overload_call(
27182721 # for example, when we have a fallback alternative that accepts an unrestricted
27192722 # typevar. See https://github.com/python/mypy/issues/4063 for related discussion.
27202723 erased_targets : list [CallableType ] | None = None
2724+ inferred_types : list [Type ] | None = None
27212725 unioned_result : tuple [Type , Type ] | None = None
27222726
27232727 # Determine whether we need to encourage union math. This should be generally safe,
@@ -2745,13 +2749,14 @@ def check_overload_call(
27452749 # Record if we succeeded. Next we need to see if maybe normal procedure
27462750 # gives a narrower type.
27472751 if unioned_return :
2748- returns , inferred_types = zip (* unioned_return )
2752+ returns = [u [0 ] for u in unioned_return ]
2753+ inferred_types = [u [1 ] for u in unioned_return ]
27492754 # Note that we use `combine_function_signatures` instead of just returning
27502755 # a union of inferred callables because for example a call
27512756 # Union[int -> int, str -> str](Union[int, str]) is invalid and
27522757 # we don't want to introduce internal inconsistencies.
27532758 unioned_result = (
2754- make_simplified_union (list ( returns ) , context .line , context .column ),
2759+ make_simplified_union (returns , context .line , context .column ),
27552760 self .combine_function_signatures (get_proper_types (inferred_types )),
27562761 )
27572762
@@ -2766,19 +2771,26 @@ def check_overload_call(
27662771 object_type ,
27672772 context ,
27682773 )
2769- # If any of checks succeed, stop early.
2774+ # If any of checks succeed, perform deprecation tests and stop early.
27702775 if inferred_result is not None and unioned_result is not None :
27712776 # Both unioned and direct checks succeeded, choose the more precise type.
27722777 if (
27732778 is_subtype (inferred_result [0 ], unioned_result [0 ])
27742779 and not isinstance (get_proper_type (inferred_result [0 ]), AnyType )
27752780 and not none_type_var_overlap
27762781 ):
2777- return inferred_result
2778- return unioned_result
2779- elif unioned_result is not None :
2782+ unioned_result = None
2783+ else :
2784+ inferred_result = None
2785+ if unioned_result is not None :
2786+ if inferred_types is not None :
2787+ for inferred_type in inferred_types :
2788+ if isinstance (c := get_proper_type (inferred_type ), CallableType ):
2789+ self .chk .warn_deprecated (c .definition , context )
27802790 return unioned_result
2781- elif inferred_result is not None :
2791+ if inferred_result is not None :
2792+ if isinstance (c := get_proper_type (inferred_result [1 ]), CallableType ):
2793+ self .chk .warn_deprecated (c .definition , context )
27822794 return inferred_result
27832795
27842796 # Step 4: Failure. At this point, we know there is no match. We fall back to trying
@@ -2916,7 +2928,7 @@ def infer_overload_return_type(
29162928 for typ in plausible_targets :
29172929 assert self .msg is self .chk .msg
29182930 with self .msg .filter_errors () as w :
2919- with self .chk .local_type_map () as m :
2931+ with self .chk .local_type_map as m :
29202932 ret_type , infer_type = self .check_call (
29212933 callee = typ ,
29222934 args = args ,
@@ -2932,8 +2944,6 @@ def infer_overload_return_type(
29322944 # check for ambiguity due to 'Any' below.
29332945 if not args_contain_any :
29342946 self .chk .store_types (m )
2935- if isinstance (infer_type , ProperType ) and isinstance (infer_type , CallableType ):
2936- self .chk .warn_deprecated (infer_type .definition , context )
29372947 return ret_type , infer_type
29382948 p_infer_type = get_proper_type (infer_type )
29392949 if isinstance (p_infer_type , CallableType ):
@@ -2970,11 +2980,6 @@ def infer_overload_return_type(
29702980 else :
29712981 # Success! No ambiguity; return the first match.
29722982 self .chk .store_types (type_maps [0 ])
2973- inferred_callable = inferred_types [0 ]
2974- if isinstance (inferred_callable , ProperType ) and isinstance (
2975- inferred_callable , CallableType
2976- ):
2977- self .chk .warn_deprecated (inferred_callable .definition , context )
29782983 return return_types [0 ], inferred_types [0 ]
29792984
29802985 def overload_erased_call_targets (
@@ -3427,11 +3432,19 @@ def infer_literal_expr_type(self, value: LiteralValue, fallback_name: str) -> Ty
34273432 if self .is_literal_context ():
34283433 return LiteralType (value = value , fallback = typ )
34293434 else :
3430- return typ .copy_modified (
3431- last_known_value = LiteralType (
3432- value = value , fallback = typ , line = typ .line , column = typ .column
3433- )
3434- )
3435+ if value is True :
3436+ if self ._literal_true is None :
3437+ self ._literal_true = typ .copy_modified (
3438+ last_known_value = LiteralType (value = value , fallback = typ )
3439+ )
3440+ return self ._literal_true
3441+ if value is False :
3442+ if self ._literal_false is None :
3443+ self ._literal_false = typ .copy_modified (
3444+ last_known_value = LiteralType (value = value , fallback = typ )
3445+ )
3446+ return self ._literal_false
3447+ return typ .copy_modified (last_known_value = LiteralType (value = value , fallback = typ ))
34353448
34363449 def concat_tuples (self , left : TupleType , right : TupleType ) -> TupleType :
34373450 """Concatenate two fixed length tuples."""
@@ -5349,20 +5362,21 @@ def visit_dict_expr(self, e: DictExpr) -> Type:
53495362 # an error, but returns the TypedDict type that matches the literal it found
53505363 # that would cause a second error when that TypedDict type is returned upstream
53515364 # to avoid the second error, we always return TypedDict type that was requested
5352- typeddict_contexts = self .find_typeddict_context (self .type_context [- 1 ], e )
5365+ typeddict_contexts , exhaustive = self .find_typeddict_context (self .type_context [- 1 ], e )
53535366 if typeddict_contexts :
5354- if len (typeddict_contexts ) == 1 :
5367+ if len (typeddict_contexts ) == 1 and exhaustive :
53555368 return self .check_typeddict_literal_in_context (e , typeddict_contexts [0 ])
53565369 # Multiple items union, check if at least one of them matches cleanly.
53575370 for typeddict_context in typeddict_contexts :
5358- with self .msg .filter_errors () as err , self .chk .local_type_map () as tmap :
5371+ with self .msg .filter_errors () as err , self .chk .local_type_map as tmap :
53595372 ret_type = self .check_typeddict_literal_in_context (e , typeddict_context )
53605373 if err .has_new_errors ():
53615374 continue
53625375 self .chk .store_types (tmap )
53635376 return ret_type
53645377 # No item matched without an error, so we can't unambiguously choose the item.
5365- self .msg .typeddict_context_ambiguous (typeddict_contexts , e )
5378+ if exhaustive :
5379+ self .msg .typeddict_context_ambiguous (typeddict_contexts , e )
53665380
53675381 # fast path attempt
53685382 dt = self .fast_dict_type (e )
@@ -5424,22 +5438,29 @@ def visit_dict_expr(self, e: DictExpr) -> Type:
54245438
54255439 def find_typeddict_context (
54265440 self , context : Type | None , dict_expr : DictExpr
5427- ) -> list [TypedDictType ]:
5441+ ) -> tuple [list [TypedDictType ], bool ]:
5442+ """Extract `TypedDict` members of the enclosing context.
5443+
5444+ Returns:
5445+ a 2-tuple, (found_candidates, is_exhaustive)
5446+ """
54285447 context = get_proper_type (context )
54295448 if isinstance (context , TypedDictType ):
5430- return [context ]
5449+ return [context ], True
54315450 elif isinstance (context , UnionType ):
54325451 items = []
5452+ exhaustive = True
54335453 for item in context .items :
5434- item_contexts = self .find_typeddict_context (item , dict_expr )
5454+ item_contexts , item_exhaustive = self .find_typeddict_context (item , dict_expr )
54355455 for item_context in item_contexts :
54365456 if self .match_typeddict_call_with_dict (
54375457 item_context , dict_expr .items , dict_expr
54385458 ):
54395459 items .append (item_context )
5440- return items
5460+ exhaustive = exhaustive and item_exhaustive
5461+ return items , exhaustive
54415462 # No TypedDict type in context.
5442- return []
5463+ return [], False
54435464
54445465 def visit_lambda_expr (self , e : LambdaExpr ) -> Type :
54455466 """Type check lambda expression."""
@@ -6038,15 +6059,12 @@ def accept(
60386059
60396060 def accept_maybe_cache (self , node : Expression , type_context : Type | None = None ) -> Type :
60406061 binder_version = self .chk .binder .version
6041- # Micro-optimization: inline local_type_map() as it is somewhat slow in mypyc.
6042- type_map : dict [Expression , Type ] = {}
6043- self .chk ._type_maps .append (type_map )
60446062 with self .msg .filter_errors (filter_errors = True , save_filtered_errors = True ) as msg :
6045- typ = node .accept (self )
6063+ with self .chk .local_type_map as type_map :
6064+ typ = node .accept (self )
60466065 messages = msg .filtered_errors ()
60476066 if binder_version == self .chk .binder .version and not self .chk .current_node_deferred :
60486067 self .expr_cache [(node , type_context )] = (binder_version , typ , messages , type_map )
6049- self .chk ._type_maps .pop ()
60506068 self .chk .store_types (type_map )
60516069 self .msg .add_errors (messages )
60526070 return typ
0 commit comments