about summary refs log tree commit diff
diff options
context:
space:
mode:
authorIlija Tovilo <ilija.tovilo@me.com>2019-07-24 01:42:39 +0200
committerIlija Tovilo <ilija.tovilo@me.com>2019-07-24 03:03:52 +0200
commitbd8813e52c5120c40ec3cca096ff4a98fdf56be8 (patch)
treec4bd33dfa623017bc1a7dd543d01348f7d1c87b8
parent299ef86e1f8b3e53154f834115752c719b611fa1 (diff)
downloadrust-bd8813e52c5120c40ec3cca096ff4a98fdf56be8.tar.gz
rust-bd8813e52c5120c40ec3cca096ff4a98fdf56be8.zip
Add method disambiguation help for trait implementation
Closes #51046
Closes #40471
-rw-r--r--src/librustc_typeck/check/method/suggest.rs50
-rw-r--r--src/test/ui/methods/method-ambig-two-traits-from-impls.rs16
-rw-r--r--src/test/ui/methods/method-ambig-two-traits-from-impls.stderr22
-rw-r--r--src/test/ui/methods/method-ambig-two-traits-from-impls2.rs16
-rw-r--r--src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr22
5 files changed, 107 insertions, 19 deletions
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 5febc694def..cd4c8a28dab 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -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));
                     }
                 }
             }
diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls.rs b/src/test/ui/methods/method-ambig-two-traits-from-impls.rs
new file mode 100644
index 00000000000..22bf8406605
--- /dev/null
+++ b/src/test/ui/methods/method-ambig-two-traits-from-impls.rs
@@ -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
+}
diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr
new file mode 100644
index 00000000000..0b3724e030f
--- /dev/null
+++ b/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr
@@ -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`.
diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls2.rs b/src/test/ui/methods/method-ambig-two-traits-from-impls2.rs
new file mode 100644
index 00000000000..0a96c1223da
--- /dev/null
+++ b/src/test/ui/methods/method-ambig-two-traits-from-impls2.rs
@@ -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
+}
diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr
new file mode 100644
index 00000000000..81c99b33c81
--- /dev/null
+++ b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr
@@ -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`.