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

Code before:
        })
        .collect();

    Some((definitions, callable_type))
}

/// Returns the definitions for an unary operator along with their callable types.
pub fn definitions_for_unary_op<'db>(
    db: &'db dyn Db,
    model: &SemanticModel<'db>,
    unary_op: &ast::ExprUnaryOp,
) -> Option<(Vec<ResolvedDefinition<'db>>, Type<'db>)> {
    let operand_ty = unary_op.operand.inferred_type(model);

    let unary_dunder_method = match unary_op.op {
        ast::UnaryOp::Invert => "__invert__",
        ast::UnaryOp::UAdd => "__pos__",
        ast::UnaryOp::USub => "__neg__",
        ast::UnaryOp::Not => "__bool__",
    };

    let bindings = match operand_ty.try_call_dunder(
        db,
        unary_dunder_method,
        CallArguments::none(),
        TypeContext::default(),
    ) {
        Ok(bindings) => bindings,
        Err(CallDunderError::MethodNotAvailable) if unary_op.op == ast::UnaryOp::Not => {
            // The runtime falls back to `__len__` for `not` if `__bool__` is not defined.
            match operand_ty.try_call_dunder(
                db,
                "__len__",
                CallArguments::none(),
                TypeContext::default(),
            ) {
                Ok(bindings) => bindings,
                Err(CallDunderError::MethodNotAvailable) => return None,
                Err(
                    CallDunderError::PossiblyUnbound(bindings)
                    | CallDunderError::CallError(_, bindings),
                ) => *bindings,
            }
        }
        Err(CallDunderError::MethodNotAvailable) => return None,
        Err(
            CallDunderError::PossiblyUnbound(bindings) | CallDunderError::CallError(_, bindings),
        ) => *bindings,
    };

    let callable_type = promote_literals_for_self(db, bindings.callable_type());

Review comment (suggestion):
I spent an *unconscionable* amount of time trying to have this return a Type or something more useful than a String but the types on `Binding` are haunted by the overloads when you try to render them (meaning printing them still returns the full overload set!). 

Stringifying the raw Signature is the only thing that seems to be safe.

Code after:
    // If the callable is trivial this analysis is useless, bail out
    if let Some(binding) = bindings.single_element()
        && binding.overloads().len() < 2
    {
        return None;
    }

    // Hand the overload resolution system as much type info as we have
    let args = CallArguments::from_arguments_typed(&call_expr.arguments, |_, splatted_value| {
        splatted_value.inferred_type(model)
    });

    // Try to resolve overloads with the arguments/types we have
    let mut resolved = bindings
        .match_parameters(db, &args)
        .check_types(db, &args, TypeContext::default(), &[])
        // Only use the Ok
        .iter()
        .flatten()
        .flat_map(|binding| {
            binding.matching_overloads().map(|(_, overload)| {
                overload
                    .signature
                    .display_with(db, DisplaySettings::default().multiline())
                    .to_string()
            })
        })
        .collect::<Vec<_>>();

    // If at the end of this we still got multiple signatures (or no signatures), give up
    if resolved.len() != 1 {
        return None;
    }

    resolved.pop()
}

/// Returns the definitions of the binary operation along with its callable type.
pub fn definitions_for_bin_op<'db>(
    db: &'db dyn Db,
    model: &SemanticModel<'db>,
    binary_op: &ast::ExprBinOp,
) -> Option<(Vec<ResolvedDefinition<'db>>, Type<'db>)> {
    let left_ty = binary_op.left.inferred_type(model);
    let right_ty = binary_op.right.inferred_type(model);

    let Ok(bindings) = Type::try_call_bin_op(db, left_ty, binary_op.op, right_ty) else {
        return None;
    };

    let callable_type = promote_literals_for_self(db, bindings.callable_type());