Skip to content

Commit bd8813e

Browse files
committedJul 24, 2019
Add method disambiguation help for trait implementation
Closes #51046 Closes #40471
1 parent 299ef86 commit bd8813e

5 files changed

+107
-19
lines changed
 

‎src/librustc_typeck/check/method/suggest.rs

+31-19
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use rustc::hir::{self, ExprKind, Node, QPath};
1010
use rustc::hir::def::{Res, DefKind};
1111
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
1212
use rustc::hir::map as hir_map;
13-
use rustc::hir::print;
1413
use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1514
use rustc::traits::Obligation;
1615
use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
@@ -78,6 +77,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7877
return;
7978
}
8079

80+
let print_disambiguation_help = |
81+
err: &mut DiagnosticBuilder<'_>,
82+
trait_name: String,
83+
| {
84+
err.help(&format!(
85+
"to disambiguate the method call, write `{}::{}({}{})` instead",
86+
trait_name,
87+
item_name,
88+
if rcvr_ty.is_region_ptr() && args.is_some() {
89+
if rcvr_ty.is_mutable_pointer() {
90+
"&mut "
91+
} else {
92+
"&"
93+
}
94+
} else {
95+
""
96+
},
97+
args.map(|arg| arg
98+
.iter()
99+
.map(|arg| self.tcx.sess.source_map().span_to_snippet(arg.span)
100+
.unwrap_or_else(|_| "...".to_owned()))
101+
.collect::<Vec<_>>()
102+
.join(", ")
103+
).unwrap_or_else(|| "...".to_owned())
104+
));
105+
};
106+
81107
let report_candidates = |
82108
span: Span,
83109
err: &mut DiagnosticBuilder<'_>,
@@ -139,6 +165,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
139165
} else {
140166
err.note(&note_str);
141167
}
168+
if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
169+
print_disambiguation_help(err, self.tcx.def_path_str(trait_ref.def_id));
170+
}
142171
}
143172
CandidateSource::TraitSource(trait_did) => {
144173
let item = match self.associated_item(
@@ -163,24 +192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
163192
"the candidate is defined in the trait `{}`",
164193
self.tcx.def_path_str(trait_did));
165194
}
166-
err.help(&format!("to disambiguate the method call, write `{}::{}({}{})` \
167-
instead",
168-
self.tcx.def_path_str(trait_did),
169-
item_name,
170-
if rcvr_ty.is_region_ptr() && args.is_some() {
171-
if rcvr_ty.is_mutable_pointer() {
172-
"&mut "
173-
} else {
174-
"&"
175-
}
176-
} else {
177-
""
178-
},
179-
args.map(|arg| arg.iter()
180-
.map(|arg| print::to_string(print::NO_ANN,
181-
|s| s.print_expr(arg)))
182-
.collect::<Vec<_>>()
183-
.join(", ")).unwrap_or_else(|| "...".to_owned())));
195+
print_disambiguation_help(err, self.tcx.def_path_str(trait_did));
184196
}
185197
}
186198
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
trait A { fn foo(self); }
2+
trait B { fn foo(self); }
3+
4+
struct AB {}
5+
6+
impl A for AB {
7+
fn foo(self) {}
8+
}
9+
10+
impl B for AB {
11+
fn foo(self) {}
12+
}
13+
14+
fn main() {
15+
AB {}.foo(); //~ ERROR E0034
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0034]: multiple applicable items in scope
2+
--> $DIR/method-ambig-two-traits-from-impls.rs:15:11
3+
|
4+
LL | AB {}.foo();
5+
| ^^^ multiple `foo` found
6+
|
7+
note: candidate #1 is defined in an impl of the trait `A` for the type `AB`
8+
--> $DIR/method-ambig-two-traits-from-impls.rs:7:5
9+
|
10+
LL | fn foo(self) {}
11+
| ^^^^^^^^^^^^
12+
= help: to disambiguate the method call, write `A::foo(AB {})` instead
13+
note: candidate #2 is defined in an impl of the trait `B` for the type `AB`
14+
--> $DIR/method-ambig-two-traits-from-impls.rs:11:5
15+
|
16+
LL | fn foo(self) {}
17+
| ^^^^^^^^^^^^
18+
= help: to disambiguate the method call, write `B::foo(AB {})` instead
19+
20+
error: aborting due to previous error
21+
22+
For more information about this error, try `rustc --explain E0034`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
trait A { fn foo(); }
2+
trait B { fn foo(); }
3+
4+
struct AB {}
5+
6+
impl A for AB {
7+
fn foo() {}
8+
}
9+
10+
impl B for AB {
11+
fn foo() {}
12+
}
13+
14+
fn main() {
15+
AB::foo(); //~ ERROR E0034
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0034]: multiple applicable items in scope
2+
--> $DIR/method-ambig-two-traits-from-impls2.rs:15:5
3+
|
4+
LL | AB::foo();
5+
| ^^^^^^^ multiple `foo` found
6+
|
7+
note: candidate #1 is defined in an impl of the trait `A` for the type `AB`
8+
--> $DIR/method-ambig-two-traits-from-impls2.rs:7:5
9+
|
10+
LL | fn foo() {}
11+
| ^^^^^^^^
12+
= help: to disambiguate the method call, write `A::foo(...)` instead
13+
note: candidate #2 is defined in an impl of the trait `B` for the type `AB`
14+
--> $DIR/method-ambig-two-traits-from-impls2.rs:11:5
15+
|
16+
LL | fn foo() {}
17+
| ^^^^^^^^
18+
= help: to disambiguate the method call, write `B::foo(...)` instead
19+
20+
error: aborting due to previous error
21+
22+
For more information about this error, try `rustc --explain E0034`.

0 commit comments

Comments
 (0)