Perform limited lookup of a matching overload item. Full overload resolution is only supported during type checking, but plugins sometimes need to resolve overloads. This can be used in some such use cases. Resolve overloads based on these things only: * Match using argument kinds
(overload: Overloaded, call: CallExpr)
| 99 | |
| 100 | |
| 101 | def find_shallow_matching_overload_item(overload: Overloaded, call: CallExpr) -> CallableType: |
| 102 | """Perform limited lookup of a matching overload item. |
| 103 | |
| 104 | Full overload resolution is only supported during type checking, but plugins |
| 105 | sometimes need to resolve overloads. This can be used in some such use cases. |
| 106 | |
| 107 | Resolve overloads based on these things only: |
| 108 | |
| 109 | * Match using argument kinds and names |
| 110 | * If formal argument has type None, only accept the "None" expression in the callee |
| 111 | * If formal argument has type Literal[True] or Literal[False], only accept the |
| 112 | relevant bool literal |
| 113 | |
| 114 | Return the first matching overload item, or the last one if nothing matches. |
| 115 | """ |
| 116 | for item in overload.items[:-1]: |
| 117 | ok = True |
| 118 | mapped = map_actuals_to_formals( |
| 119 | call.arg_kinds, |
| 120 | call.arg_names, |
| 121 | item.arg_kinds, |
| 122 | item.arg_names, |
| 123 | lambda i: AnyType(TypeOfAny.special_form), |
| 124 | ) |
| 125 | |
| 126 | # Look for extra actuals |
| 127 | matched_actuals = set() |
| 128 | for actuals in mapped: |
| 129 | matched_actuals.update(actuals) |
| 130 | if any(i not in matched_actuals for i in range(len(call.args))): |
| 131 | ok = False |
| 132 | |
| 133 | for arg_type, kind, actuals in zip(item.arg_types, item.arg_kinds, mapped): |
| 134 | if kind.is_required() and not actuals: |
| 135 | # Missing required argument |
| 136 | ok = False |
| 137 | break |
| 138 | elif actuals: |
| 139 | args = [call.args[i] for i in actuals] |
| 140 | arg_type = get_proper_type(arg_type) |
| 141 | arg_none = any(isinstance(arg, NameExpr) and arg.name == "None" for arg in args) |
| 142 | if isinstance(arg_type, NoneType): |
| 143 | if not arg_none: |
| 144 | ok = False |
| 145 | break |
| 146 | elif ( |
| 147 | arg_none |
| 148 | and not is_overlapping_none(arg_type) |
| 149 | and not ( |
| 150 | isinstance(arg_type, Instance) |
| 151 | and arg_type.type.fullname == "builtins.object" |
| 152 | ) |
| 153 | and not isinstance(arg_type, AnyType) |
| 154 | ): |
| 155 | ok = False |
| 156 | break |
| 157 | elif isinstance(arg_type, LiteralType) and isinstance(arg_type.value, bool): |
| 158 | if not any(parse_bool(arg) == arg_type.value for arg in args): |
searching dependent graphs…