about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-07-25 23:21:04 +0200
committerGitHub <noreply@github.com>2019-07-25 23:21:04 +0200
commitfe07132c80be874f47ddebe1456d0c3af2d8e36b (patch)
tree06334a1f4bd81ed57d63224ed5ccae288723ae77
parentc9a766ab47fb0515316bc7e68b9c27d460196af4 (diff)
parentbe510dbc35960c9d90f42811787eea2acef8ffe5 (diff)
downloadrust-fe07132c80be874f47ddebe1456d0c3af2d8e36b.tar.gz
rust-fe07132c80be874f47ddebe1456d0c3af2d8e36b.zip
Rollup merge of #62921 - iluuu1994:improve-help-for-method-disambiguation, r=estebank
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/associated-const/associated-const-ambiguity-report.stderr2
-rw-r--r--src/test/ui/error-codes/E0034.stderr2
-rw-r--r--src/test/ui/inference/inference_unstable_featured.stderr2
-rw-r--r--src/test/ui/issues/issue-3702-2.stderr2
-rw-r--r--src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr2
-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
-rw-r--r--src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr2
-rw-r--r--src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr2
-rw-r--r--src/test/ui/traits/trait-alias-ambiguous.stderr2
13 files changed, 123 insertions, 19 deletions
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index cb83630100a..d48ba74f9f2 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/associated-const/associated-const-ambiguity-report.stderr b/src/test/ui/associated-const/associated-const-ambiguity-report.stderr
index 5f2b9c47e8c..bb217bd182d 100644
--- a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr
+++ b/src/test/ui/associated-const/associated-const-ambiguity-report.stderr
@@ -9,11 +9,13 @@ note: candidate #1 is defined in an impl of the trait `Foo` for the type `i32`
    |
 LL |     const ID: i32 = 1;
    |     ^^^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `Foo::ID(...)` instead
 note: candidate #2 is defined in an impl of the trait `Bar` for the type `i32`
   --> $DIR/associated-const-ambiguity-report.rs:14:5
    |
 LL |     const ID: i32 = 3;
    |     ^^^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `Bar::ID(...)` instead
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0034.stderr b/src/test/ui/error-codes/E0034.stderr
index 816a48f102d..a58d16bfafb 100644
--- a/src/test/ui/error-codes/E0034.stderr
+++ b/src/test/ui/error-codes/E0034.stderr
@@ -9,11 +9,13 @@ note: candidate #1 is defined in an impl of the trait `Trait1` for the type `Tes
    |
 LL |     fn foo() {}
    |     ^^^^^^^^
+   = help: to disambiguate the method call, write `Trait1::foo(...)` instead
 note: candidate #2 is defined in an impl of the trait `Trait2` for the type `Test`
   --> $DIR/E0034.rs:16:5
    |
 LL |     fn foo() {}
    |     ^^^^^^^^
+   = help: to disambiguate the method call, write `Trait2::foo(...)` instead
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/inference_unstable_featured.stderr b/src/test/ui/inference/inference_unstable_featured.stderr
index 08cdb8cc688..b06a6298a57 100644
--- a/src/test/ui/inference/inference_unstable_featured.stderr
+++ b/src/test/ui/inference/inference_unstable_featured.stderr
@@ -5,7 +5,9 @@ LL |     assert_eq!('x'.ipu_flatten(), 0);
    |                    ^^^^^^^^^^^ multiple `ipu_flatten` found
    |
    = note: candidate #1 is defined in an impl of the trait `inference_unstable_iterator::IpuIterator` for the type `char`
+   = help: to disambiguate the method call, write `inference_unstable_iterator::IpuIterator::ipu_flatten('x')` instead
    = note: candidate #2 is defined in an impl of the trait `inference_unstable_itertools::IpuItertools` for the type `char`
+   = help: to disambiguate the method call, write `inference_unstable_itertools::IpuItertools::ipu_flatten('x')` instead
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-3702-2.stderr b/src/test/ui/issues/issue-3702-2.stderr
index 347a19b687f..4d0ff750c25 100644
--- a/src/test/ui/issues/issue-3702-2.stderr
+++ b/src/test/ui/issues/issue-3702-2.stderr
@@ -9,11 +9,13 @@ note: candidate #1 is defined in an impl of the trait `ToPrimitive` for the type
    |
 LL |     fn to_int(&self) -> isize { 0 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `ToPrimitive::to_int(&self)` instead
 note: candidate #2 is defined in an impl of the trait `Add` for the type `isize`
   --> $DIR/issue-3702-2.rs:14:5
    |
 LL |     fn to_int(&self) -> isize { *self }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `Add::to_int(&self)` instead
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr
index 2b87ddfdf98..9f46a722a50 100644
--- a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr
+++ b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr
@@ -9,7 +9,9 @@ note: candidate #1 is defined in an impl of the trait `Me2` for the type `usize`
    |
 LL | impl Me2 for usize { fn me(&self) -> usize { *self } }
    |                      ^^^^^^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `Me2::me(1_usize)` instead
    = note: candidate #2 is defined in an impl of the trait `ambig_impl_2_lib::Me` for the type `usize`
+   = help: to disambiguate the method call, write `ambig_impl_2_lib::Me::me(1_usize)` instead
 
 error: aborting due to previous error
 
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`.
diff --git a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr
index 5d508d57022..dc8aef25037 100644
--- a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr
+++ b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr
@@ -9,11 +9,13 @@ note: candidate #1 is defined in an impl of the trait `Foo` for the type `usize`
    |
 LL | trait Foo { fn method(&self) {} }
    |             ^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `Foo::method(1_usize)` instead
 note: candidate #2 is defined in an impl of the trait `Bar` for the type `usize`
   --> $DIR/method-ambig-two-traits-with-default-method.rs:6:13
    |
 LL | trait Bar { fn method(&self) {} }
    |             ^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `Bar::method(1_usize)` instead
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr
index d6fac7025a4..283ef8fcba7 100644
--- a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr
+++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr
@@ -27,11 +27,13 @@ note: candidate #1 is defined in an impl of the trait `internal::X` for the type
    |
 LL |         fn foo(self: Smaht<Self, u64>) -> u64 {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `internal::X::foo(x)` instead
 note: candidate #2 is defined in an impl of the trait `nuisance_foo::NuisanceFoo` for the type `_`
   --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:70:9
    |
 LL |         fn foo(self) {}
    |         ^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `nuisance_foo::NuisanceFoo::foo(x)` instead
 note: candidate #3 is defined in the trait `FinalFoo`
   --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:57:5
    |
diff --git a/src/test/ui/traits/trait-alias-ambiguous.stderr b/src/test/ui/traits/trait-alias-ambiguous.stderr
index b7443269b88..cde7dd08249 100644
--- a/src/test/ui/traits/trait-alias-ambiguous.stderr
+++ b/src/test/ui/traits/trait-alias-ambiguous.stderr
@@ -9,11 +9,13 @@ note: candidate #1 is defined in an impl of the trait `inner::A` for the type `u
    |
 LL |         fn foo(&self) {}
    |         ^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `inner::A::foo(t)` instead
 note: candidate #2 is defined in an impl of the trait `inner::B` for the type `u8`
   --> $DIR/trait-alias-ambiguous.rs:11:9
    |
 LL |         fn foo(&self) {}
    |         ^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `inner::B::foo(t)` instead
 
 error: aborting due to previous error