@@ -1121,35 +1121,65 @@ def check_overload_call(self,
1121
1121
plausible_targets = self .plausible_overload_call_targets (arg_types , arg_kinds ,
1122
1122
arg_names , callee )
1123
1123
1124
- # Step 2: Attempt to find a matching overload
1124
+ # Step 2: If the arguments contain a union, we try performing union math first.
1125
+ erased_targets = None # type: Optional[List[CallableType]]
1126
+ unioned_result = None # type: Optional[Tuple[Type, Type]]
1127
+ unioned_errors = None # type: Optional[MessageBuilder]
1128
+ if any (isinstance (arg , UnionType ) for arg in arg_types ):
1129
+ erased_targets = self .overload_erased_call_targets (plausible_targets , arg_types ,
1130
+ arg_kinds , arg_names , context )
1131
+ unioned_callable = self .union_overload_matches (erased_targets )
1132
+
1133
+ if unioned_callable is not None :
1134
+ unioned_errors = arg_messages .clean_copy ()
1135
+ unioned_result = self .check_call (unioned_callable , args , arg_kinds ,
1136
+ context , arg_names ,
1137
+ arg_messages = unioned_errors ,
1138
+ callable_name = callable_name ,
1139
+ object_type = object_type )
1140
+ if not unioned_errors .is_errors ():
1141
+ # Success! Stop early.
1142
+ return unioned_result
1143
+
1144
+ # Step 3: If the union math fails, or if there was no union in the argument types,
1145
+ # we fall back to checking each branch one-by-one.
1125
1146
inferred_result = self .infer_overload_return_type (plausible_targets , args , arg_types ,
1126
1147
arg_kinds , arg_names , callable_name ,
1127
1148
object_type , context , arg_messages )
1128
1149
if inferred_result is not None :
1129
1150
# Success! Stop early.
1130
1151
return inferred_result
1131
1152
1132
- # Step 3: At this point, we know none of the overload alternatives exactly match.
1133
- # We fall back to using the erased types to help with union math/help us
1134
- # produce a better error message.
1135
- erased_targets = self .overload_erased_call_targets (plausible_targets , arg_types ,
1136
- arg_kinds , arg_names , context )
1137
-
1138
- # Step 4: Try and infer a second-best alternative.
1139
- if len (erased_targets ) == 0 :
1140
- # Step 4a: There are no viable targets, even if we relax our constraints. Give up.
1153
+ # Step 4: Failure. At this point, we know there is no match. We fall back to trying
1154
+ # to find a somewhat plausible overload target using the erased types
1155
+ # so we can produce a nice error message.
1156
+ #
1157
+ # For example, suppose the user passes a value of type 'List[str]' into an
1158
+ # overload with signatures f(x: int) -> int and f(x: List[int]) -> List[int].
1159
+ #
1160
+ # Neither alternative matches, but we can guess the user probably wants the
1161
+ # second one.
1162
+ if erased_targets is None :
1163
+ erased_targets = self .overload_erased_call_targets (plausible_targets , arg_types ,
1164
+ arg_kinds , arg_names , context )
1165
+
1166
+ # Step 5: We try and infer a second-best alternative if possible. If not, fall back
1167
+ # to using 'Any'.
1168
+ if unioned_result is not None :
1169
+ # When possible, return the error messages generated from the union-math attempt:
1170
+ # they tend to be a little nicer.
1171
+ assert unioned_errors is not None
1172
+ arg_messages .add_errors (unioned_errors )
1173
+ return unioned_result
1174
+ elif len (erased_targets ) > 0 :
1175
+ # Pick the first plausible erased target as the fallback
1176
+ # TODO: Adjust the error message here to make it clear there was no match.
1177
+ target = erased_targets [0 ] # type: Type
1178
+ else :
1179
+ # There was no plausible match: give up
1141
1180
if not self .chk .should_suppress_optional_error (arg_types ):
1142
1181
arg_messages .no_variant_matches_arguments (callee , arg_types , context )
1143
- target = AnyType (TypeOfAny .from_error ) # type: Type
1144
- elif any (isinstance (arg , UnionType ) for arg in arg_types ):
1145
- # Step 4b: Try performing union math
1146
- unioned_callable = self .union_overload_matches (erased_targets )
1147
- target = unioned_callable if unioned_callable is not None else erased_targets [0 ]
1148
- else :
1149
- # Step 4c: Use the first matching erased target: it won't match, but at
1150
- # least we can have a nicer error message.
1151
- # TODO: Adjust the error message here to make it clear there was no match.
1152
- target = erased_targets [0 ]
1182
+ target = AnyType (TypeOfAny .from_error )
1153
1183
1154
1184
return self .check_call (target , args , arg_kinds , context , arg_names ,
1155
1185
arg_messages = arg_messages ,
@@ -1230,7 +1260,7 @@ def infer_overload_return_type(self,
1230
1260
matches .append (typ )
1231
1261
return_types .append (ret_type )
1232
1262
inferred_types .append (infer_type )
1233
-
1263
+
1234
1264
if len (matches ) == 0 :
1235
1265
# No match was found
1236
1266
return None
0 commit comments