Skip to content

Commit e408b20

Browse files
committed
Implement method signature suggestion for trait mismatches error
1 parent 5dbf406 commit e408b20

File tree

9 files changed

+98
-1
lines changed

9 files changed

+98
-1
lines changed

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_middle::ty::{
1818
TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
1919
};
2020
use rustc_middle::{bug, span_bug};
21-
use rustc_span::{DUMMY_SP, Span};
21+
use rustc_span::{BytePos, DUMMY_SP, Span};
2222
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
2323
use rustc_trait_selection::infer::InferCtxtExt;
2424
use rustc_trait_selection::regions::InferCtxtRegionExt;
@@ -1742,6 +1742,46 @@ fn compare_number_of_method_arguments<'tcx>(
17421742
),
17431743
);
17441744

1745+
let sm = tcx.sess.source_map();
1746+
let find_param_bounds = |snippet: &str| {
1747+
let start = snippet.find('(')? + 1;
1748+
let mut depth = 1;
1749+
for (i, ch) in snippet[start..].char_indices() {
1750+
match ch {
1751+
'(' => depth += 1,
1752+
')' => { depth -= 1; if depth == 0 { return Some((start, start + i)); } }
1753+
_ => {}
1754+
}
1755+
}
1756+
None
1757+
};
1758+
1759+
let extract_params = |span: Span| sm.span_to_snippet(span).ok()
1760+
.and_then(|s| find_param_bounds(&s).map(|(lo, hi)| s[lo..hi].to_string()));
1761+
1762+
let impl_inputs_span = (!impl_m_sig.span.is_dummy()).then(|| {
1763+
let snippet = sm.span_to_snippet(impl_m_sig.span).ok()?;
1764+
let (lo, hi) = find_param_bounds(&snippet)?;
1765+
Some(impl_m_sig.span.with_lo(impl_m_sig.span.lo() + BytePos(lo as u32))
1766+
.with_hi(impl_m_sig.span.lo() + BytePos(hi as u32)))
1767+
}).flatten();
1768+
1769+
let suggestion = trait_m.def_id.as_local()
1770+
.and_then(|id| extract_params(tcx.hir_expect_trait_item(id).expect_fn().0.span))
1771+
.or_else(|| {
1772+
let sig = trait_m.signature(tcx);
1773+
find_param_bounds(&sig).map(|(lo, hi)| sig[lo..hi].trim().to_string())
1774+
});
1775+
1776+
if let (Some(span), Some(suggestion)) = (impl_inputs_span, suggestion) {
1777+
err.span_suggestion_verbose(
1778+
span,
1779+
"modify the signature to match the trait definition",
1780+
suggestion,
1781+
Applicability::MaybeIncorrect,
1782+
);
1783+
}
1784+
17451785
return Err(err.emit_unless_delay(delay));
17461786
}
17471787

tests/ui/error-codes/E0050.stderr

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ LL | fn foo(&self, x: u8) -> bool;
66
...
77
LL | fn foo(&self) -> bool { true }
88
| ^^^^^ expected 2 parameters, found 1
9+
|
10+
help: modify the signature to match the trait definition
11+
|
12+
LL | fn foo(&self, x: u8) -> bool { true }
13+
| +++++++
914

1015
error[E0050]: method `bar` has 1 parameter but the declaration in trait `Foo::bar` has 4
1116
--> $DIR/E0050.rs:11:12
@@ -15,6 +20,11 @@ LL | fn bar(&self, x: u8, y: u8, z: u8);
1520
...
1621
LL | fn bar(&self) { }
1722
| ^^^^^ expected 4 parameters, found 1
23+
|
24+
help: modify the signature to match the trait definition
25+
|
26+
LL | fn bar(&self, x: u8, y: u8, z: u8) { }
27+
| +++++++++++++++++++++
1828

1929
error[E0050]: method `less` has 4 parameters but the declaration in trait `Foo::less` has 1
2030
--> $DIR/E0050.rs:12:13
@@ -24,6 +34,12 @@ LL | fn less(&self);
2434
...
2535
LL | fn less(&self, x: u8, y: u8, z: u8) { }
2636
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 parameter, found 4
37+
|
38+
help: modify the signature to match the trait definition
39+
|
40+
LL - fn less(&self, x: u8, y: u8, z: u8) { }
41+
LL + fn less(&self) { }
42+
|
2743

2844
error: aborting due to 3 previous errors
2945

tests/ui/fn/issue-39259.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ LL | fn call(&self) -> u32 {
1717
| ^^^^^ expected 2 parameters, found 1
1818
|
1919
= note: `call` from trait: `extern "rust-call" fn(&Self, Args) -> <Self as FnOnce<Args>>::Output`
20+
help: modify the signature to match the trait definition
21+
|
22+
LL - fn call(&self) -> u32 {
23+
LL + fn call(&Self, Args) -> u32 {
24+
|
2025

2126
error[E0277]: expected a `FnMut(u32)` closure, found `S`
2227
--> $DIR/issue-39259.rs:6:25

tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ LL | fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
66
...
77
LL | fn come_on_a_little_more_effort() {}
88
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 3 parameters, found 0
9+
|
10+
help: modify the signature to match the trait definition
11+
|
12+
LL | fn come_on_a_little_more_effort(_: (), _: (), _: ()) {}
13+
| +++++++++++++++++++
914

1015
error: aborting due to 1 previous error
1116

tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ LL | fn calm_down_please() -> impl Sized;
66
...
77
LL | fn calm_down_please(_: (), _: (), _: ()) {}
88
| ^^^^^^^^^^^^^^^^ expected 0 parameters, found 3
9+
|
10+
help: modify the signature to match the trait definition
11+
|
12+
LL - fn calm_down_please(_: (), _: (), _: ()) {}
13+
LL + fn calm_down_please() {}
14+
|
915

1016
error: aborting due to 1 previous error
1117

tests/ui/impl-trait/trait_type.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ LL | fn fmt(&self) -> () { }
1919
| ^^^^^ expected 2 parameters, found 1
2020
|
2121
= note: `fmt` from trait: `fn(&Self, &mut Formatter<'_>) -> Result<(), std::fmt::Error>`
22+
help: modify the signature to match the trait definition
23+
|
24+
LL - fn fmt(&self) -> () { }
25+
LL + fn fmt(&Self, &mut Formatter<'_>) -> () { }
26+
|
2227

2328
error[E0186]: method `fmt` has a `&self` declaration in the trait, but not in the impl
2429
--> $DIR/trait_type.rs:17:4

tests/ui/suggestions/bad-infer-in-trait-impl.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ LL | fn bar();
1212
...
1313
LL | fn bar(s: _) {}
1414
| ^ expected 0 parameters, found 1
15+
|
16+
help: modify the signature to match the trait definition
17+
|
18+
LL - fn bar(s: _) {}
19+
LL + fn bar() {}
20+
|
1521

1622
error: aborting due to 2 previous errors
1723

tests/ui/traits/impl-different-num-params.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ LL | fn bar(&self, x: usize) -> Self;
66
...
77
LL | fn bar(&self) -> isize {
88
| ^^^^^ expected 2 parameters, found 1
9+
|
10+
help: modify the signature to match the trait definition
11+
|
12+
LL | fn bar(&self, x: usize) -> isize {
13+
| ++++++++++
914

1015
error: aborting due to 1 previous error
1116

tests/ui/traits/trait-method-signature-mismatch.stderr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ LL | fn foo(&mut self, x: i32, y: i32) -> i32;
77
LL | / &mut self,
88
LL | | x: i32,
99
| |______________^ expected 3 parameters, found 2
10+
|
11+
help: modify the signature to match the trait definition
12+
|
13+
LL - fn foo(
14+
LL - &mut self,
15+
LL - x: i32,
16+
LL - ) {
17+
LL + fn foo(&mut self, x: i32, y: i32) {
18+
|
1019

1120
error: aborting due to 1 previous error
1221

0 commit comments

Comments
 (0)