@@ -1789,16 +1789,38 @@ def check_callable_call(
17891789 callee = freshen_function_type_vars (callee )
17901790 self .freshen_cache [(context , original_callee )] = callee
17911791
1792+ formal_to_actual : list [list [int ]] | None = None
17921793 if callee .is_generic ():
1794+ callee_before_context = callee
17931795 callee = self .infer_function_type_arguments_using_context (callee , context )
1796+ if callee != callee_before_context :
1797+ formal_to_actual = map_actuals_to_formals (
1798+ arg_kinds ,
1799+ arg_names ,
1800+ callee .arg_kinds ,
1801+ callee .arg_names ,
1802+ lambda i : self .accept (args [i ]),
1803+ )
1804+ if self .should_infer_args_without_context (
1805+ callee_before_context ,
1806+ callee ,
1807+ args ,
1808+ arg_kinds ,
1809+ arg_names ,
1810+ formal_to_actual ,
1811+ context ,
1812+ ):
1813+ callee = callee_before_context
1814+ formal_to_actual = None
17941815
1795- formal_to_actual = map_actuals_to_formals (
1796- arg_kinds ,
1797- arg_names ,
1798- callee .arg_kinds ,
1799- callee .arg_names ,
1800- lambda i : self .accept (args [i ]),
1801- )
1816+ if formal_to_actual is None :
1817+ formal_to_actual = map_actuals_to_formals (
1818+ arg_kinds ,
1819+ arg_names ,
1820+ callee .arg_kinds ,
1821+ callee .arg_names ,
1822+ lambda i : self .accept (args [i ]),
1823+ )
18021824
18031825 if callee .special_sig == "tuple" and len (args ) == 1 :
18041826 with self .msg .filter_errors ():
@@ -2097,6 +2119,115 @@ def infer_arg_types_in_context(
20972119 res .append (self .accept (arg ))
20982120 return res
20992121
2122+ def should_infer_args_without_context (
2123+ self ,
2124+ callee : CallableType ,
2125+ contextual_callee : CallableType ,
2126+ args : list [Expression ],
2127+ arg_kinds : list [ArgKind ],
2128+ arg_names : Sequence [str | None ] | None ,
2129+ formal_to_actual : list [list [int ]],
2130+ context : Context ,
2131+ ) -> bool :
2132+ """Should we abandon contextual type argument inference for this call?
2133+
2134+ Context can infer a wider type argument than the actual argument supports when
2135+ the type variable also appears in an invariant or callback argument position.
2136+ In that case we can use regular argument inference instead, but only if it
2137+ produces a valid call whose return type still satisfies the outer context.
2138+ """
2139+ if contextual_callee .special_sig is not None or contextual_callee .is_type_obj ():
2140+ # Keep the previous behavior for special synthetic signatures and type object
2141+ # calls, where context is often intentionally used to produce better errors.
2142+ return False
2143+
2144+ valid = True
2145+
2146+ def check_arg (
2147+ caller_type : Type ,
2148+ original_caller_type : Type ,
2149+ caller_kind : ArgKind ,
2150+ callee_type : Type ,
2151+ n : int ,
2152+ m : int ,
2153+ callee : CallableType ,
2154+ object_type : Type | None ,
2155+ context : Context ,
2156+ outer_context : Context ,
2157+ ) -> None :
2158+ nonlocal valid
2159+ if not is_subtype (
2160+ get_proper_type (caller_type ),
2161+ get_proper_type (callee_type ),
2162+ options = self .chk .options ,
2163+ ):
2164+ valid = False
2165+
2166+ validation_callee = contextual_callee
2167+ validation_formal_to_actual = formal_to_actual
2168+ with self .msg .filter_errors (), self .chk .local_type_map :
2169+ if validation_callee .is_generic ():
2170+ need_refresh = any (
2171+ isinstance (v , (ParamSpecType , TypeVarTupleType ))
2172+ for v in validation_callee .variables
2173+ )
2174+ validation_callee = self .infer_function_type_arguments (
2175+ validation_callee ,
2176+ args ,
2177+ arg_kinds ,
2178+ arg_names ,
2179+ validation_formal_to_actual ,
2180+ need_refresh ,
2181+ context ,
2182+ )
2183+ if need_refresh :
2184+ validation_formal_to_actual = map_actuals_to_formals (
2185+ arg_kinds ,
2186+ arg_names ,
2187+ validation_callee .arg_kinds ,
2188+ validation_callee .arg_names ,
2189+ lambda i : self .accept (args [i ]),
2190+ )
2191+ arg_types = self .infer_arg_types_in_context (
2192+ validation_callee , args , arg_kinds , validation_formal_to_actual
2193+ )
2194+ self .check_argument_types (
2195+ arg_types ,
2196+ arg_kinds ,
2197+ args ,
2198+ validation_callee ,
2199+ validation_formal_to_actual ,
2200+ context ,
2201+ check_arg = check_arg ,
2202+ )
2203+ if valid :
2204+ return False
2205+
2206+ ctx = self .type_context [- 1 ]
2207+ if not ctx :
2208+ return False
2209+
2210+ with self .msg .filter_errors () as local_errors , self .chk .local_type_map :
2211+ formal_to_actual = map_actuals_to_formals (
2212+ arg_kinds ,
2213+ arg_names ,
2214+ callee .arg_kinds ,
2215+ callee .arg_names ,
2216+ lambda i : self .accept (args [i ]),
2217+ )
2218+ need_refresh = any (
2219+ isinstance (v , (ParamSpecType , TypeVarTupleType )) for v in callee .variables
2220+ )
2221+ inferred_callee = self .infer_function_type_arguments (
2222+ callee , args , arg_kinds , arg_names , formal_to_actual , need_refresh , context
2223+ )
2224+ return (
2225+ not local_errors .has_new_errors ()
2226+ and not has_ambiguous_uninhabited_component (inferred_callee .ret_type )
2227+ and not has_erased_component (inferred_callee .ret_type )
2228+ and is_subtype (inferred_callee .ret_type , ctx , options = self .chk .options )
2229+ )
2230+
21002231 def infer_function_type_arguments_using_context (
21012232 self , callable : CallableType , error_context : Context
21022233 ) -> CallableType :
0 commit comments