Add method disambiguation help for trait implementation
Closes #51046 Closes #40471
This commit is contained in:
parent
299ef86e1f
commit
bd8813e52c
@ -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(¬e_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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
16
src/test/ui/methods/method-ambig-two-traits-from-impls.rs
Normal file
16
src/test/ui/methods/method-ambig-two-traits-from-impls.rs
Normal 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
|
||||
}
|
@ -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`.
|
16
src/test/ui/methods/method-ambig-two-traits-from-impls2.rs
Normal file
16
src/test/ui/methods/method-ambig-two-traits-from-impls2.rs
Normal 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
|
||||
}
|
@ -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`.
|
Loading…
Reference in New Issue
Block a user