about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-01-03 19:14:20 +0000
committerbors <bors@rust-lang.org>2016-01-03 19:14:20 +0000
commitcae9267d4735fa84cf7758b000ae1d64bdbac55c (patch)
tree41fa100c1163ebd14edc4f206fcf95e1d89348ba /src
parent4744472fe03cceb81747ac9c7c64ae5fe6340c0b (diff)
parenta8d60708ecabc90ca4b72e12483159339a0b40ce (diff)
Auto merge of #29949 - fhahn:issue-21659-show-relevant-trait-impls, r=arielb1
This PR for #21659 uses `DefId.for_each_relevant_impl()` to show other possible implementations in the "trait not implemented" message.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/traits/error_reporting.rs47
-rw-r--r--src/test/compile-fail/issue-21659-show-relevant-trait-impls-1.rs39
-rw-r--r--src/test/compile-fail/issue-21659-show-relevant-trait-impls-2.rs46
-rw-r--r--src/test/compile-fail/issue-21659-show-relevant-trait-impls-3.rs34
4 files changed, 164 insertions, 2 deletions
diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs
index 9193b1a09f9..038c414662a 100644
--- a/src/librustc/middle/traits/error_reporting.rs
+++ b/src/librustc/middle/traits/error_reporting.rs
@@ -27,9 +27,11 @@ use fmt_macros::{Parser, Piece, Position};
 use middle::def_id::DefId;
 use middle::infer::InferCtxt;
 use middle::ty::{self, ToPredicate, HasTypeFlags, ToPolyTraitRef, TraitRef, Ty};
+use middle::ty::fast_reject;
 use middle::ty::fold::TypeFoldable;
 use util::nodemap::{FnvHashMap, FnvHashSet};
 
+use std::cmp;
 use std::fmt;
 use syntax::attr::{AttributeMethods, AttrMetaMethods};
 use syntax::codemap::Span;
@@ -231,12 +233,53 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                                                       obligation.cause.span);
                             if let Some(s) = custom_note {
                                 err.fileline_note(obligation.cause.span, &s);
+                            } else {
+                                let simp = fast_reject::simplify_type(infcx.tcx,
+                                                                      trait_ref.self_ty(),
+                                                                      true);
+                                let mut impl_candidates = Vec::new();
+                                let trait_def = infcx.tcx.lookup_trait_def(trait_ref.def_id());
+
+                                match simp {
+                                    Some(simp) => trait_def.for_each_impl(infcx.tcx, |def_id| {
+                                        let imp = infcx.tcx.impl_trait_ref(def_id).unwrap();
+                                        let imp_simp = fast_reject::simplify_type(infcx.tcx,
+                                                                                  imp.self_ty(),
+                                                                                  true);
+                                        if let Some(imp_simp) = imp_simp {
+                                            if simp != imp_simp {
+                                                return;
+                                            }
+                                        }
+                                        impl_candidates.push(imp);
+                                    }),
+                                    None => trait_def.for_each_impl(infcx.tcx, |def_id| {
+                                        impl_candidates.push(
+                                            infcx.tcx.impl_trait_ref(def_id).unwrap());
+                                    })
+                                };
+
+                                if impl_candidates.len() > 0 {
+                                    err.fileline_help(
+                                        obligation.cause.span,
+                                        &format!("the following implementations were found:"));
+
+                                    let end = cmp::min(4, impl_candidates.len());
+                                    for candidate in &impl_candidates[0..end] {
+                                        err.fileline_help(obligation.cause.span,
+                                                          &format!("  {:?}", candidate));
+                                    }
+                                    if impl_candidates.len() > 4 {
+                                        err.fileline_help(obligation.cause.span,
+                                                          &format!("and {} others",
+                                                                   impl_candidates.len()-4));
+                                    }
+                                }
                             }
                             note_obligation_cause(infcx, &mut err, obligation);
                             err.emit();
                         }
-                    }
-
+                    },
                     ty::Predicate::Equate(ref predicate) => {
                         let predicate = infcx.resolve_type_vars_if_possible(predicate);
                         let err = infcx.equality_predicate(obligation.cause.span,
diff --git a/src/test/compile-fail/issue-21659-show-relevant-trait-impls-1.rs b/src/test/compile-fail/issue-21659-show-relevant-trait-impls-1.rs
new file mode 100644
index 00000000000..416eef4ad25
--- /dev/null
+++ b/src/test/compile-fail/issue-21659-show-relevant-trait-impls-1.rs
@@ -0,0 +1,39 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo<A> {
+    fn foo(&self, a: A) -> A {
+        a
+    }
+}
+
+trait NotRelevant<A> {
+    fn nr(&self, a: A) -> A {
+        a
+    }
+}
+
+struct Bar;
+
+impl Foo<i32> for Bar {}
+
+impl Foo<u8> for Bar {}
+
+impl NotRelevant<usize> for Bar {}
+
+fn main() {
+    let f1 = Bar;
+
+    f1.foo(1usize);
+    //~^ error: the trait `Foo<usize>` is not implemented for the type `Bar`
+    // | help: the following implementations were found:
+    // | help: implementation 1: `Foo<i32>`
+    // | help: implementation 2: `Foo<u8>`
+}
diff --git a/src/test/compile-fail/issue-21659-show-relevant-trait-impls-2.rs b/src/test/compile-fail/issue-21659-show-relevant-trait-impls-2.rs
new file mode 100644
index 00000000000..07a7c98dd7f
--- /dev/null
+++ b/src/test/compile-fail/issue-21659-show-relevant-trait-impls-2.rs
@@ -0,0 +1,46 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo<A> {
+    fn foo(&self, a: A) -> A {
+        a
+    }
+}
+
+trait NotRelevant<A> {
+    fn nr(&self, a: A) -> A {
+        a
+    }
+}
+
+struct Bar;
+
+impl Foo<i8> for Bar {}
+impl Foo<i16> for Bar {}
+impl Foo<i32> for Bar {}
+
+impl Foo<u8> for Bar {}
+impl Foo<u16> for Bar {}
+impl Foo<u32> for Bar {}
+
+impl NotRelevant<usize> for Bar {}
+
+fn main() {
+    let f1 = Bar;
+
+    f1.foo(1usize);
+    //~^ error: the trait `Foo<usize>` is not implemented for the type `Bar`
+    // | help: the following implementations were found:
+    // | help:   Foo<i8>
+    // | help:   Foo<i16>
+    // | help:   Foo<i32>
+    // | help:   Foo<u8>
+    // | help: and 2 others
+}
diff --git a/src/test/compile-fail/issue-21659-show-relevant-trait-impls-3.rs b/src/test/compile-fail/issue-21659-show-relevant-trait-impls-3.rs
new file mode 100644
index 00000000000..0bb944edb9d
--- /dev/null
+++ b/src/test/compile-fail/issue-21659-show-relevant-trait-impls-3.rs
@@ -0,0 +1,34 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo<A> {
+    fn foo(&self, a: A) -> A {
+        a
+    }
+}
+
+trait NotRelevant<A> {
+    fn nr(&self, a: A) -> A {
+        a
+    }
+}
+
+struct Bar;
+
+impl NotRelevant<usize> for Bar {}
+
+fn main() {
+    let f1 = Bar;
+
+    f1.foo(1usize);
+    //~^ error: method named `foo` found for type `Bar` in the current scope
+    //~| help: items from traits can only be used if the trait is implemented and in scope
+    //~| help: candidate #1: `Foo`
+}