Skip to content

Commit

Permalink
Add method disambiguation help for trait implementation
Browse files Browse the repository at this point in the history
Closes #51046
Closes #40471
  • Loading branch information
iluuu1994 committed Jul 24, 2019
1 parent 299ef86 commit bd8813e
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 19 deletions.
50 changes: 31 additions & 19 deletions src/librustc_typeck/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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<'_>,
Expand Down Expand Up @@ -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(
Expand All @@ -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));
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions src/test/ui/methods/method-ambig-two-traits-from-impls.rs
Original file line number Diff line number Diff line change
@@ -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
}
22 changes: 22 additions & 0 deletions src/test/ui/methods/method-ambig-two-traits-from-impls.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 16 additions & 0 deletions src/test/ui/methods/method-ambig-two-traits-from-impls2.rs
Original file line number Diff line number Diff line change
@@ -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
}
22 changes: 22 additions & 0 deletions src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit bd8813e

Please sign in to comment.