Repository: astral-sh/ruff
File: crates/ty_python_semantic/src/types/ide_support.rs (Rust)

Code before:
        .iter()
        .enumerate()
        .max_by_key(|(_, details)| {
            details
                .argument_to_parameter_mapping
                .iter()
                .filter(|mapping| mapping.matched)
                .count()
        })?;

    Some(best_index)
}

/// Resolve a call expression to its matching overload's signature details,
/// using full type checking (not just arity matching) for overload resolution.
///
/// Falls back to arity-based matching if type-based resolution fails.
fn resolve_call_signature<'db>(
    db: &'db dyn Db,
    model: &SemanticModel<'db>,
    call_expr: &ast::ExprCall,
) -> Option<CallSignatureDetails<'db>> {
    let func_type = call_expr.func.inferred_type(model)?;
    let callable_type = func_type
        .try_upcast_to_callable(model.db())
        .map(|callables| callables.into_type(model.db()))?;

    let args = CallArguments::from_arguments_typed(&call_expr.arguments, |_, splatted_value| {
        splatted_value
            .inferred_type(model)
            .unwrap_or(Type::unknown())
    });

    let bindings = callable_type.bindings(db).match_parameters(db, &args);

    // Extract the `Bindings` regardless of whether type checking succeeded or failed.
    let checked = bindings.check_types(db, &args, TypeContext::default(), &[]);
    let bindings = match &checked {
        Ok(bindings) => bindings,
        Err(err) => &err.1,
    };

    // First, try to find the matching overload after full type checking.
    let type_checked_details: Vec<_> = bindings
        .iter()
        .flat_map(|binding| binding.matching_overloads().map(|(_, overload)| overload))
        .map(|binding| CallSignatureDetails::from_binding(db, binding))
        .collect();

    if !type_checked_details.is_empty() {
        let active = find_active_signature_from_details(&type_checked_details)?;

Review comment (suggestion):
```suggestion
    let callable_type = func_type.try_upcast_to_callable(db)?.into_type(db);
```

Code after:
        .iter()
        .enumerate()
        .max_by_key(|(_, details)| {
            details
                .argument_to_parameter_mapping
                .iter()
                .filter(|mapping| mapping.matched)
                .count()
        })?;

    Some(best_index)
}

/// Resolve a call expression to its matching overload's signature details,
/// using full type checking (not just arity matching) for overload resolution.
///
/// Falls back to arity-based matching if type-based resolution fails.
fn resolve_call_signature<'db>(
    model: &SemanticModel<'db>,
    call_expr: &ast::ExprCall,
) -> Option<CallSignatureDetails<'db>> {
    let db = model.db();
    let func_type = call_expr.func.inferred_type(model)?;
    let callable_type = func_type.try_upcast_to_callable(db)?.into_type(db);

    let args = CallArguments::from_arguments_typed(&call_expr.arguments, |splatted_value| {
        splatted_value
            .inferred_type(model)
            .unwrap_or(Type::unknown())
    });

    // Extract the `Bindings` regardless of whether type checking succeeded or failed.
    let bindings = callable_type
        .bindings(db)
        .match_parameters(db, &args)
        .check_types(db, &args, TypeContext::default(), &[])
        .unwrap_or_else(|CallError(_, bindings)| *bindings);

    // First, try to find the matching overload after full type checking.
    let type_checked_details: Vec<_> = bindings
        .iter()
        .flat_map(|binding| binding.matching_overloads().map(|(_, overload)| overload))
        .map(|binding| CallSignatureDetails::from_binding(db, binding))
        .collect();

    if !type_checked_details.is_empty() {
        let active = find_active_signature_from_details(&type_checked_details)?;
        return type_checked_details.into_iter().nth(active);
    }

    // If all overloads have type-checking errors (e.g., `InvalidArgumentType`),