Skip to content

Conversation

@reddevilmidzy
Copy link
Member

@reddevilmidzy reddevilmidzy commented Nov 17, 2025

resolve: #106999

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Nov 17, 2025
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@reddevilmidzy reddevilmidzy marked this pull request as ready for review November 17, 2025 17:04
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Nov 17, 2025
@rustbot rustbot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Nov 17, 2025
@rustbot
Copy link
Collaborator

rustbot commented Nov 17, 2025

r? @madsmtm

rustbot has assigned @madsmtm.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rust-log-analyzer

This comment has been minimized.

@madsmtm madsmtm added A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` labels Nov 20, 2025
Copy link
Contributor

@madsmtm madsmtm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay in getting back here, this slipped my notifications.

Did you have a look at the previous implementation? #107548

Some of the tests in that one contains //~| HELP attributes, which I think is useful for actually testing that the behaviour is what we desire.

View changes since this review

|
help: modify the signature to match the trait definition
|
LL | fn come_on_a_little_more_effort(_: (), _: (), _: ()) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the help message is desirable for the cross-crate case (such as the serde example in the issue), since there the solution for the user is always to change the implementation (vs. e.g. changing the trait).

But here, it feels overly verbose? We're showing come_on_a_little_more_effort three times.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. In the case of local traits, the trait definition may be wrong, so it would be good to just point out that the two are different.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 13, 2025
@rustbot
Copy link
Collaborator

rustbot commented Dec 13, 2025

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@rustbot
Copy link
Collaborator

rustbot commented Dec 15, 2025

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@reddevilmidzy
Copy link
Member Author

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Dec 15, 2025
Copy link
Contributor

@madsmtm madsmtm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I had another look through, I like the test you've added, but I still feel that the approach with extracting the signature from spans is the wrong one (though maybe that's just me hating span calculation code), have expanded upon it in a comment.

View changes since this review

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 15, 2025
@reddevilmidzy
Copy link
Member Author

I've incorporated your suggestions! It looks much cleaner.
@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Dec 16, 2025
Copy link
Contributor

@madsmtm madsmtm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I'm happy with the output, now it's just comments on the implementation.

View changes since this review

//~^ ERROR: method `has_self` has 2 parameters but the declaration in trait `has_self` has 1
//~| HELP: remove the extra parameter to match the trait
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a test for missing and extra &self as well?

Suggested change
struct MyStruct5;
impl Bar for MyStruct5 {
fn no_params(&self) {}
fn has_self() {}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, please add a test like:

trait NonIdentArguments {
    fn pattern_types_in_arguments(_: i32, (_a, _b): (i32, i32)) {}
}

struct MyStruct6;
impl NonIdentArguments for MyStruct6 {
    fn pattern_types_in_arguments() {}
}

Copy link
Member Author

@reddevilmidzy reddevilmidzy Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding or removing &self from the implementation causes E0185 and E0186 errors instead of E0050. So I don't see any suggestions working on this pr, but would it be a good idea to still add that test case?

error[E0185]: method `no_params` has a `&self` declaration in the impl, but not in the trait
  --> $DIR/trait-impl-param-mismatched-cross-crate.rs:45:5
   |
LL |     fn no_params(&self) {}
   |     ^^^^^^^^^^^^^^^^^^^ `&self` used in impl
   |
   = note: `no_params` from trait: `fn()`

error[E0186]: method `has_self` has a `&self` declaration in the trait, but not in the impl
  --> $DIR/trait-impl-param-mismatched-cross-crate.rs:48:5
   |
LL |     fn has_self() {}
   |     ^^^^^^^^^^^^^ expected `&self` in impl
   |
   = note: `has_self` from trait: `fn(&Self)`

Or would it be better to add HELP to E0185 and E0186 as well?
(I think it's going to get a bit longer)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that's fine then for now.

Maybe add a test for self: &Self as well, just to ensure that that works?

let replacement = if kept.is_empty() { String::new() } else { kept.join(", ") };
Some(("remove the extra parameter to match the trait", replacement))
} else {
None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: We already checked trait_number_args != impl_number_args above, this case should be unreachable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to make it clear, use:

match trait_number_args.cmp(impl_number_args) {
    Ordering::Less => { ... }
    Ordering::Greater => { ... }
    Ordering::Equal => unreachable!(),
}

But I'm fine with just doing if trait_number_args > impl_number_args { ... } else { ... }.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to use .cmp and unreachable! rather than if {} else {}

};

if let (Some(span), Some((msg, replacement))) = (impl_inputs_span, suggestion_text) {
err.span_suggestion_verbose(span, msg, replacement, Applicability::MaybeIncorrect);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of always making the span the entire argument list, maybe you can shrink it to only be the relevant parts?

Something like:

let (span, replacement) = if trait_number_args > impl_number_args {
    // Span is right before the end parenthesis:
    // fn foo(a: i32 ) {}
    //              ^
    let span = impl_inputs_span.shrink_to_hi();
    let replacement = ", b: u32";
    (span, replacement)
} else {
    // Span of the arguments that there are too many of:
    // fn foo(a: i32, b: u32) {}
    //              ^^^^^^^^
    let span = impl_inputs_span.with_lo(impl_m_sig.decl.inputs[trait_number_args - 1].span);
    let replacement = "";
    (span, replacement)
};

);

// Only emit verbose suggestions when the trait span isn’t local (e.g., cross-crate).
if trait_span.is_none() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Use !trait_m.def_id.is_local() instead.

let trait_sig = tcx.fn_sig(trait_m.def_id);
let trait_arg_idents = tcx.fn_arg_idents(trait_m.def_id);
let sm = tcx.sess.source_map();
let impl_inputs_span = (!impl_m_sig.span.is_dummy())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I don't think you need to guard span_to_snippet with is_dummy?

Comment on lines 1769 to 1779
let impl_inputs_span = (!impl_m_sig.span.is_dummy())
.then(|| {
sm.span_to_snippet(impl_m_sig.span).ok().and_then(|snippet| {
find_param_bounds(&snippet).map(|(lo_rel, hi_rel)| {
let lo = impl_m_sig.span.lo() + BytePos(lo_rel as u32);
let hi = impl_m_sig.span.lo() + BytePos(hi_rel as u32);
impl_m_sig.span.with_lo(lo).with_hi(hi)
})
})
})
.flatten();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like inspecting the source and looking for parentheses with find_param_bounds is brittle. For example, I think it would find the wrong span on something like:

trait Foo<T> {}
fn foo<T: Foo<()>>() {}

That said, I recognize that it's gonna be annoying to find this span in any case, because the span of the parentheses that enclose parameters seems to be dropped early in the compilation pipeline (it's not even part of ast::Fn).

Maybe a more robust approach would be to:

  • If there are parameters, grab the span from the first parameter identifier and last parameter type, and combine them.
  • If there are no parameters, grab the span of the output, and walk backwards until we find ) and (.

In any case, maybe you could inline find_param_bounds, that might make it easier to follow what's going on?

And maybe you could add a comment about what it is that we're actually looking for? Something like:

// Find the span of the space between the parentheses in a method.
// fn foo(...) {}
//        ^^^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, I'm not sure what's the best option here. Neither the current solution, nor the solution that I'm proposing are gonna handle every edge-case, and maybe the best would be a blend somewhere in between.

No matter what, I'd lean towards whatever solution is the simplest in terms of LOC, it is just a suggestion that we're implementing, it doesn't have to be perfect (especially given that we're using Applicability::MaybeIncorrect).

@reddevilmidzy
Copy link
Member Author

thank you for the review:)
I added the mentioned test case.
If there is anything I misunderstood or implemented incorrectly, please let me know.

@rustbot ready


struct MyStruct5;
impl NonIdentArguments for MyStruct5 {
fn pattern_types_in_arguments(_: i32, _: (i32, i32)) {}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the trait is fn pattern_types_in_arguments(_: i32, (_a, _b): (i32, i32)) {}
but replacing (_a, _b) with _

@reddevilmidzy
Copy link
Member Author

Hello, @madsmtm. I was wondering if there is anything else I should add to this PR. I would appreciate your review :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Trait method signature mismatch could suggest changing the signature inline

4 participants