Add method disambiguation help for trait implementation

Closes #51046
Closes #40471
This commit is contained in:
Ilija Tovilo 2019-07-24 01:42:39 +02:00
parent 299ef86e1f
commit bd8813e52c
No known key found for this signature in database
GPG Key ID: 3F123D0ADD448198
5 changed files with 107 additions and 19 deletions

View File

@ -10,7 +10,6 @@ use rustc::hir::{self, ExprKind, Node, QPath};
use rustc::hir::def::{Res, DefKind};
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
use rustc::hir::map as hir_map;
use rustc::hir::print;
use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc::traits::Obligation;
use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
@ -78,6 +77,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
let print_disambiguation_help = |
err: &mut DiagnosticBuilder<'_>,
trait_name: String,
| {
err.help(&format!(
"to disambiguate the method call, write `{}::{}({}{})` instead",
trait_name,
item_name,
if rcvr_ty.is_region_ptr() && args.is_some() {
if rcvr_ty.is_mutable_pointer() {
"&mut "
} else {
"&"
}
} else {
""
},
args.map(|arg| arg
.iter()
.map(|arg| self.tcx.sess.source_map().span_to_snippet(arg.span)
.unwrap_or_else(|_| "...".to_owned()))
.collect::<Vec<_>>()
.join(", ")
).unwrap_or_else(|| "...".to_owned())
));
};
let report_candidates = |
span: Span,
err: &mut DiagnosticBuilder<'_>,
@ -139,6 +165,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
err.note(&note_str);
}
if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
print_disambiguation_help(err, self.tcx.def_path_str(trait_ref.def_id));
}
}
CandidateSource::TraitSource(trait_did) => {
let item = match self.associated_item(
@ -163,24 +192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"the candidate is defined in the trait `{}`",
self.tcx.def_path_str(trait_did));
}
err.help(&format!("to disambiguate the method call, write `{}::{}({}{})` \
instead",
self.tcx.def_path_str(trait_did),
item_name,
if rcvr_ty.is_region_ptr() && args.is_some() {
if rcvr_ty.is_mutable_pointer() {
"&mut "
} else {
"&"
}
} else {
""
},
args.map(|arg| arg.iter()
.map(|arg| print::to_string(print::NO_ANN,
|s| s.print_expr(arg)))
.collect::<Vec<_>>()
.join(", ")).unwrap_or_else(|| "...".to_owned())));
print_disambiguation_help(err, self.tcx.def_path_str(trait_did));
}
}
}

View File

@ -0,0 +1,16 @@
trait A { fn foo(self); }
trait B { fn foo(self); }
struct AB {}
impl A for AB {
fn foo(self) {}
}
impl B for AB {
fn foo(self) {}
}
fn main() {
AB {}.foo(); //~ ERROR E0034
}

View File

@ -0,0 +1,22 @@
error[E0034]: multiple applicable items in scope
--> $DIR/method-ambig-two-traits-from-impls.rs:15:11
|
LL | AB {}.foo();
| ^^^ multiple `foo` found
|
note: candidate #1 is defined in an impl of the trait `A` for the type `AB`
--> $DIR/method-ambig-two-traits-from-impls.rs:7:5
|
LL | fn foo(self) {}
| ^^^^^^^^^^^^
= help: to disambiguate the method call, write `A::foo(AB {})` instead
note: candidate #2 is defined in an impl of the trait `B` for the type `AB`
--> $DIR/method-ambig-two-traits-from-impls.rs:11:5
|
LL | fn foo(self) {}
| ^^^^^^^^^^^^
= help: to disambiguate the method call, write `B::foo(AB {})` instead
error: aborting due to previous error
For more information about this error, try `rustc --explain E0034`.

View File

@ -0,0 +1,16 @@
trait A { fn foo(); }
trait B { fn foo(); }
struct AB {}
impl A for AB {
fn foo() {}
}
impl B for AB {
fn foo() {}
}
fn main() {
AB::foo(); //~ ERROR E0034
}

View File

@ -0,0 +1,22 @@
error[E0034]: multiple applicable items in scope
--> $DIR/method-ambig-two-traits-from-impls2.rs:15:5
|
LL | AB::foo();
| ^^^^^^^ multiple `foo` found
|
note: candidate #1 is defined in an impl of the trait `A` for the type `AB`
--> $DIR/method-ambig-two-traits-from-impls2.rs:7:5
|
LL | fn foo() {}
| ^^^^^^^^
= help: to disambiguate the method call, write `A::foo(...)` instead
note: candidate #2 is defined in an impl of the trait `B` for the type `AB`
--> $DIR/method-ambig-two-traits-from-impls2.rs:11:5
|
LL | fn foo() {}
| ^^^^^^^^
= help: to disambiguate the method call, write `B::foo(...)` instead
error: aborting due to previous error
For more information about this error, try `rustc --explain E0034`.