Repository: rust-lang/rust
File: compiler/rustc_hir_analysis/src/check/compare_impl_item.rs (Rust)

Code before:
                find_param_bounds(&signature).map(|(lo, hi)| {
                    let mut params = signature[lo..hi].trim().to_string();
                    if trait_m.is_method() {
                        params = params.replacen("Self", "self", 1);
                    }
                    params
                })
            });

        // Only emit verbose suggestions when the trait span isn’t local (e.g., cross-crate).
        if trait_span.is_none() {
            if let (Some(span), Some(missing)) = (impl_inputs_span, missing_params) {
                let sep = if impl_number_args == 0 { "" } else { ", " };
                err.span_suggestion_verbose(
                    span.shrink_to_hi(),
                    "add the missing parameter from the trait",
                    format!("{sep}{missing}"),
                    Applicability::MaybeIncorrect,
                );
            } else if let (Some(span), Some(suggestion)) = (impl_inputs_span, full_suggestion) {
                err.span_suggestion_verbose(
                    span,
                    "modify the signature to match the trait definition",
                    suggestion,
                    Applicability::MaybeIncorrect,
                );
            }
        }

        return Err(err.emit_unless_delay(delay));
    }

    Ok(())
}

fn find_param_bounds(snippet: &str) -> Option<(usize, usize)> {
    let start = snippet.find('(')?;
    let mut depth = 1usize;
    let bytes = snippet.as_bytes();
    let mut i = start + 1;
    while i < bytes.len() {
        match bytes[i] {
            b'(' => depth += 1,
            b')' => {
                depth -= 1;
                if depth == 0 {
                    return Some((start + 1, i));
                }
            }
            _ => {}
        }

Review comment (suggestion):
Hmm, feels like this is already somewhat handled by `report_trait_method_mismatch`.

I think is should be fine to not handle mismatching types in existing parameters, and only focus on the _amount_ of parameters in this PR?

That way, if the user wrote something like:
```rust
trait Foo {
    fn foo(a: u32, b: i8);
}

struct Bar;
impl Foo for Bar {
    fn foo(a: i32) {}
}
```

We would suggest `fn foo(a: i32, b: i8) {}`, then they edit and recompile, and then we suggest in `report_trait_method_mismatch` that they fix the `a` parameter type as well.

Code after:
                    .unwrap_or(first.span.lo());
                Some(impl_m_sig.span.with_lo(first_lo).with_hi(last.span.hi()))
            } else {
                // We have no inputs; construct the span to the left of the last parenthesis
                // fn foo( ) {}
                //        ^
                // FIXME: Keep spans for function parentheses around to make this more robust.
                sm.span_to_snippet(impl_m_sig.span).ok().and_then(|s| {
                    let right_paren = s.as_bytes().iter().rposition(|&b| b == b')')?;
                    let pos = impl_m_sig.span.lo() + BytePos(right_paren as u32);
                    Some(impl_m_sig.span.with_lo(pos).with_hi(pos))
                })
            };
            let suggestion = match trait_number_args.cmp(&impl_number_args) {
                Ordering::Greater => {
                    // Span is right before the end parenthesis:
                    // fn foo(a: i32 ) {}
                    //              ^
                    let trait_inputs = trait_sig.skip_binder().inputs().skip_binder();
                    let missing = trait_inputs
                        .iter()
                        .enumerate()
                        .skip(impl_number_args)
                        .map(|(idx, ty)| {
                            let name = trait_arg_idents
                                .get(idx)
                                .and_then(|ident| *ident)
                                .map(|ident| ident.to_string())
                                .unwrap_or_else(|| "_".to_string());
                            format!("{name}: {ty}")
                        })
                        .collect::<Vec<_>>();

                    if missing.is_empty() {
                        None
                    } else {
                        impl_inputs_span.map(|s| {
                            let span = s.shrink_to_hi();
                            let prefix = if impl_number_args == 0 { "" } else { ", " };
                            let replacement = format!("{prefix}{}", missing.join(", "));
                            (
                                span,
                                format!(
                                    "add the missing parameter{} from the trait",
                                    pluralize!(trait_number_args - impl_number_args)
                                ),
                                replacement,
                            )
                        })
                    }
                }