|
| 1 | +use std::cmp::Ordering; |
1 | 2 | use std::sync::Arc; |
2 | 3 |
|
3 | 4 | use crate::{ |
@@ -112,14 +113,6 @@ pub fn resolve_signature_by_args( |
112 | 113 | *opt_func = None; |
113 | 114 | continue; |
114 | 115 | } |
115 | | - |
116 | | - if !has_declined_no_flow_arg |
117 | | - && match_result > ParamMatchResult::Any |
118 | | - && arg_index + 1 == expr_len |
119 | | - && param_index + 1 == func.get_params().len() |
120 | | - { |
121 | | - return Ok(func.clone()); |
122 | | - } |
123 | 116 | } |
124 | 117 |
|
125 | 118 | if current_match_result == ParamMatchResult::Not { |
@@ -149,6 +142,18 @@ pub fn resolve_signature_by_args( |
149 | 142 | _ => {} |
150 | 143 | } |
151 | 144 |
|
| 145 | + if !has_declined_no_flow_arg |
| 146 | + && let Some(func) = choose_more_specific_callable( |
| 147 | + db, |
| 148 | + &rest_need_resolve_funcs, |
| 149 | + expr_types, |
| 150 | + is_colon_call, |
| 151 | + declined_no_flow_args, |
| 152 | + ) |
| 153 | + { |
| 154 | + return Ok(func); |
| 155 | + } |
| 156 | + |
152 | 157 | let start_param_index = expr_len; |
153 | 158 | let mut max_param_len = 0; |
154 | 159 | for func in rest_need_resolve_funcs.iter().flatten() { |
@@ -236,6 +241,110 @@ pub fn resolve_signature_by_args( |
236 | 241 | } |
237 | 242 | } |
238 | 243 |
|
| 244 | +fn choose_more_specific_callable( |
| 245 | + db: &DbIndex, |
| 246 | + funcs: &[Option<Arc<LuaFunctionType>>], |
| 247 | + expr_types: &[LuaType], |
| 248 | + is_colon_call: bool, |
| 249 | + declined_no_flow_args: &[bool], |
| 250 | +) -> Option<Arc<LuaFunctionType>> { |
| 251 | + if expr_types.is_empty() |
| 252 | + || expr_types.iter().enumerate().all(|(i, expr_type)| { |
| 253 | + declined_no_flow_args.get(i).copied().unwrap_or(false) |
| 254 | + || expr_type.is_any() |
| 255 | + || expr_type.is_unknown() |
| 256 | + }) |
| 257 | + { |
| 258 | + return None; |
| 259 | + } |
| 260 | + |
| 261 | + let mut best: Option<Arc<LuaFunctionType>> = None; |
| 262 | + let mut has_strict_better = false; |
| 263 | + for func in funcs.iter().flatten() { |
| 264 | + let Some(best_func) = best.as_ref() else { |
| 265 | + best = Some(func.clone()); |
| 266 | + continue; |
| 267 | + }; |
| 268 | + |
| 269 | + match compare_callable_specificity( |
| 270 | + db, |
| 271 | + func, |
| 272 | + best_func, |
| 273 | + expr_types, |
| 274 | + is_colon_call, |
| 275 | + declined_no_flow_args, |
| 276 | + ) { |
| 277 | + Some(Ordering::Greater) => { |
| 278 | + best = Some(func.clone()); |
| 279 | + has_strict_better = true; |
| 280 | + } |
| 281 | + Some(Ordering::Less) => { |
| 282 | + has_strict_better = true; |
| 283 | + } |
| 284 | + Some(Ordering::Equal) => {} |
| 285 | + None => return None, |
| 286 | + } |
| 287 | + } |
| 288 | + |
| 289 | + if has_strict_better { best } else { None } |
| 290 | +} |
| 291 | + |
| 292 | +fn compare_callable_specificity( |
| 293 | + db: &DbIndex, |
| 294 | + a: &LuaFunctionType, |
| 295 | + b: &LuaFunctionType, |
| 296 | + expr_types: &[LuaType], |
| 297 | + is_colon_call: bool, |
| 298 | + declined_no_flow_args: &[bool], |
| 299 | +) -> Option<Ordering> { |
| 300 | + let mut result = Ordering::Equal; |
| 301 | + for (arg_index, expr_type) in expr_types.iter().enumerate() { |
| 302 | + if declined_no_flow_args |
| 303 | + .get(arg_index) |
| 304 | + .copied() |
| 305 | + .unwrap_or(false) |
| 306 | + || expr_type.is_any() |
| 307 | + || expr_type.is_unknown() |
| 308 | + { |
| 309 | + continue; |
| 310 | + } |
| 311 | + |
| 312 | + let param_index = get_call_param_index(a, arg_index, is_colon_call)?; |
| 313 | + let a_param = get_func_param_type(a, param_index)?; |
| 314 | + let b_param = get_func_param_type(b, param_index)?; |
| 315 | + let param_order = compare_param_specificity(db, &a_param, &b_param); |
| 316 | + match (result, param_order) { |
| 317 | + (Ordering::Equal, order) => result = order, |
| 318 | + (Ordering::Greater, Ordering::Less) | (Ordering::Less, Ordering::Greater) => { |
| 319 | + return None; |
| 320 | + } |
| 321 | + _ => {} |
| 322 | + } |
| 323 | + } |
| 324 | + |
| 325 | + Some(result) |
| 326 | +} |
| 327 | + |
| 328 | +fn compare_param_specificity(db: &DbIndex, a: &LuaType, b: &LuaType) -> Ordering { |
| 329 | + if a == b { |
| 330 | + return Ordering::Equal; |
| 331 | + } |
| 332 | + |
| 333 | + match (a.is_any() || a.is_unknown(), b.is_any() || b.is_unknown()) { |
| 334 | + (true, false) => return Ordering::Less, |
| 335 | + (false, true) => return Ordering::Greater, |
| 336 | + _ => {} |
| 337 | + } |
| 338 | + |
| 339 | + let a_sub_b = check_type_compact(db, b, a).is_ok(); |
| 340 | + let b_sub_a = check_type_compact(db, a, b).is_ok(); |
| 341 | + match (a_sub_b, b_sub_a) { |
| 342 | + (true, false) => Ordering::Greater, |
| 343 | + (false, true) => Ordering::Less, |
| 344 | + _ => Ordering::Equal, |
| 345 | + } |
| 346 | +} |
| 347 | + |
239 | 348 | pub(crate) fn is_func_last_param_variadic(func: &LuaFunctionType) -> bool { |
240 | 349 | if let Some(last_param) = func.get_params().last() { |
241 | 350 | last_param.0 == "..." |
|
0 commit comments