Skip to content

Commit

Permalink
suggest adding a where-clause when that can help
Browse files Browse the repository at this point in the history
suggest adding a where-clause when there is an unmet trait-bound that
can be satisfied if some type can implement it.
  • Loading branch information
Ariel Ben-Yehuda authored and arielb1 committed Apr 5, 2016
1 parent 513d9f2 commit 8a461d9
Show file tree
Hide file tree
Showing 159 changed files with 421 additions and 298 deletions.
5 changes: 2 additions & 3 deletions src/doc/book/closures.md
Expand Up @@ -371,14 +371,13 @@ assert_eq!(6, answer);
This gives us these long, related errors:

```text
error: the trait `core::marker::Sized` is not implemented for the type
`core::ops::Fn(i32) -> i32` [E0277]
error: the predicate `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277]
fn factory() -> (Fn(i32) -> i32) {
^~~~~~~~~~~~~~~~
note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
fn factory() -> (Fn(i32) -> i32) {
^~~~~~~~~~~~~~~~
error: the trait `core::marker::Sized` is not implemented for the type `core::ops::Fn(i32) -> i32` [E0277]
error: the predicate `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277]
let f = factory();
^
note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
Expand Down
4 changes: 2 additions & 2 deletions src/doc/book/concurrency.md
Expand Up @@ -231,8 +231,8 @@ fn main() {
This won't work, however, and will give us the error:

```text
13:9: 13:22 error: the trait `core::marker::Send` is not
implemented for the type `alloc::rc::Rc<collections::vec::Vec<i32>>`
13:9: 13:22 error: the predicate `alloc::rc::Rc<collections::vec::Vec<i32>> : core::marker::Send`
is not satisfied
...
13:9: 13:22 note: `alloc::rc::Rc<collections::vec::Vec<i32>>`
cannot be sent between threads safely
Expand Down
4 changes: 2 additions & 2 deletions src/doc/book/traits.md
Expand Up @@ -154,7 +154,7 @@ print_area(5);
We get a compile-time error:

```text
error: the trait `HasArea` is not implemented for the type `_` [E0277]
error: the predicate `_ : HasArea` is not satisfied [E0277]
```

## Trait bounds on generic structs
Expand Down Expand Up @@ -496,7 +496,7 @@ impl FooBar for Baz {
If we forget to implement `Foo`, Rust will tell us:

```text
error: the trait `main::Foo` is not implemented for the type `main::Baz` [E0277]
error: the predicate `main::Baz : main::Foo` is not satisfied [E0277]
```

# Deriving
Expand Down
4 changes: 2 additions & 2 deletions src/doc/book/vectors.md
Expand Up @@ -56,8 +56,8 @@ v[j];
Indexing with a non-`usize` type gives an error that looks like this:

```text
error: the trait `core::ops::Index<i32>` is not implemented for the type
`collections::vec::Vec<_>` [E0277]
error: the predicate `collections::vec::Vec<_> : core::ops::Index<i32>`
is not satisfied [E0277]
v[j];
^~~~
note: the type `collections::vec::Vec<_>` cannot be indexed by `i32`
Expand Down
2 changes: 1 addition & 1 deletion src/doc/nomicon/coercions.md
Expand Up @@ -64,7 +64,7 @@ fn main() {
```

```text
<anon>:10:5: 10:8 error: the trait `Trait` is not implemented for the type `&mut i32` [E0277]
<anon>:10:5: 10:8 error: the predicate `&mut i32 : Trait` is not satisfied [E0277]
<anon>:10 foo(t);
^~~
```
3 changes: 1 addition & 2 deletions src/librustc/diagnostics.rs
Expand Up @@ -1006,8 +1006,7 @@ fn some_func<T: Foo>(foo: T) {
fn main() {
// we now call the method with the i32 type, which doesn't implement
// the Foo trait
some_func(5i32); // error: the trait `Foo` is not implemented for the
// type `i32`
some_func(5i32); // error: the predicate `i32 : Foo` is not satisfied
}
```
Expand Down
83 changes: 71 additions & 12 deletions src/librustc/traits/error_reporting.rs
Expand Up @@ -13,10 +13,12 @@ use super::{
FulfillmentErrorCode,
MismatchedProjectionTypes,
Obligation,
ObligationCause,
ObligationCauseCode,
OutputTypeParameterMismatch,
TraitNotObjectSafe,
PredicateObligation,
SelectionContext,
SelectionError,
ObjectSafetyViolation,
MethodViolationCode,
Expand All @@ -26,8 +28,9 @@ use super::{
use fmt_macros::{Parser, Piece, Position};
use middle::def_id::DefId;
use infer::InferCtxt;
use ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable};
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
use ty::fast_reject;
use ty::fold::{TypeFoldable, TypeFolder};
use util::nodemap::{FnvHashMap, FnvHashSet};

use std::cmp;
Expand Down Expand Up @@ -100,9 +103,10 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
}
}

fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
trait_ref: &TraitRef<'tcx>,
span: Span) -> Option<String> {
fn on_unimplemented_note<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
span: Span) -> Option<String> {
let trait_ref = trait_ref.skip_binder();
let def_id = trait_ref.def_id;
let mut report = None;
for item in infcx.tcx.get_attrs(def_id).iter() {
Expand Down Expand Up @@ -357,14 +361,20 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
let trait_ref = trait_predicate.to_poly_trait_ref();
let mut err = struct_span_err!(
infcx.tcx.sess, obligation.cause.span, E0277,
"the trait `{}` is not implemented for the type `{}`",
trait_ref, trait_ref.self_ty());

// Check if it has a custom "#[rustc_on_unimplemented]"
// error message, report with that message if it does
let custom_note = report_on_unimplemented(infcx, &trait_ref.0,
obligation.cause.span);
if let Some(s) = custom_note {
"the predicate `{}` is not satisfied",
trait_ref.to_predicate());

// Try to report a good error message.

if !trait_ref.has_infer_types() &&
predicate_can_apply(infcx, trait_ref)
{
err.fileline_help(obligation.cause.span, &format!(
"consider adding a `where {}` bound",
trait_ref.to_predicate()
));
} else if let Some(s) = on_unimplemented_note(infcx, trait_ref,
obligation.cause.span) {
err.fileline_note(obligation.cause.span, &s);
} else {
let simp = fast_reject::simplify_type(infcx.tcx,
Expand Down Expand Up @@ -644,6 +654,55 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
}
}

/// Returns whether the trait predicate may apply for *some* assignment
/// to the type parameters.
fn predicate_can_apply<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
pred: ty::PolyTraitRef<'tcx>)
-> bool
{
struct ParamToVarFolder<'a, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'tcx>,
var_map: FnvHashMap<Ty<'tcx>, Ty<'tcx>>
}

impl<'a, 'tcx> TypeFolder<'tcx> for ParamToVarFolder<'a, 'tcx>
{
fn tcx(&self) -> &TyCtxt<'tcx> { self.infcx.tcx }

fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::TyParam(..) = ty.sty {
let infcx = self.infcx;
self.var_map.entry(ty).or_insert_with(|| infcx.next_ty_var())
} else {
ty.super_fold_with(self)
}
}
}

infcx.probe(|_| {
let mut selcx = SelectionContext::new(infcx);

let cleaned_pred = pred.fold_with(&mut ParamToVarFolder {
infcx: infcx,
var_map: FnvHashMap()
});

let cleaned_pred = super::project::normalize(
&mut selcx,
ObligationCause::dummy(),
&cleaned_pred
).value;

let obligation = Obligation::new(
ObligationCause::dummy(),
cleaned_pred.to_predicate()
);

selcx.evaluate_obligation(&obligation)
})
}


fn need_type_info<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
span: Span,
ty: Ty<'tcx>)
Expand Down
Expand Up @@ -31,5 +31,5 @@ trait Add<RHS=Self> {
fn ice<A>(a: A) {
let r = loop {};
r = r + a;
//~^ ERROR not implemented
//~^ ERROR E0277
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/associated-types-bound-failure.rs
Expand Up @@ -24,7 +24,7 @@ pub trait GetToInt
fn foo<G>(g: G) -> isize
where G : GetToInt
{
ToInt::to_int(&g.get()) //~ ERROR not implemented
ToInt::to_int(&g.get()) //~ ERROR E0277
}

fn bar<G : GetToInt>(g: G) -> isize
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/associated-types-for-unimpl-trait.rs
Expand Up @@ -15,7 +15,7 @@ trait Get {

trait Other {
fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
//~^ ERROR the trait `Get` is not implemented for the type `Self`
//~^ ERROR the predicate `Self : Get` is not satisfied
}

fn main() {
Expand Down
Expand Up @@ -18,7 +18,7 @@ trait Foo<T> {

fn f<T:Foo<isize>>(t: &T) {
let u: <T as Foo<usize>>::Bar = t.get_bar();
//~^ ERROR the trait `Foo<usize>` is not implemented for the type `T`
//~^ ERROR the predicate `T : Foo<usize>` is not satisfied
}

fn main() { }
Expand Up @@ -19,7 +19,7 @@ struct Struct {

impl Struct {
fn uhoh<T>(foo: <T as Get>::Value) {}
//~^ ERROR the trait `Get` is not implemented for the type `T`
//~^ ERROR the predicate `T : Get` is not satisfied
}

fn main() {
Expand Down
Expand Up @@ -25,7 +25,7 @@ trait Get {

trait Other {
fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
//~^ ERROR the trait `Get` is not implemented for the type `Self`
//~^ ERROR the predicate `Self : Get` is not satisfied
}

fn main() { }
Expand Up @@ -25,12 +25,12 @@ trait Get {

trait Other {
fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
//~^ ERROR the trait `Get` is not implemented for the type `Self`
//~^ ERROR the predicate `Self : Get` is not satisfied
}

impl<T:Get> Other for T {
fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
//~^ ERROR the trait `Get` is not implemented for the type `(T, U)`
//~^ ERROR the predicate `(T, U) : Get` is not satisfied
}

fn main() { }
4 changes: 2 additions & 2 deletions src/test/compile-fail/associated-types-path-2.rs
Expand Up @@ -38,12 +38,12 @@ pub fn f1_int_uint() {

pub fn f1_uint_uint() {
f1(2u32, 4u32);
//~^ ERROR the trait `Foo` is not implemented
//~^ ERROR `u32 : Foo` is not satisfied
}

pub fn f1_uint_int() {
f1(2u32, 4i32);
//~^ ERROR the trait `Foo` is not implemented
//~^ ERROR `u32 : Foo` is not satisfied
}

pub fn f2_int() {
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/associated-types-unsized.rs
Expand Up @@ -14,7 +14,7 @@ trait Get {
}

fn foo<T:Get>(t: T) {
let x = t.get(); //~ ERROR the trait `std::marker::Sized` is not implemented
let x = t.get(); //~ ERROR `<T as Get>::Value : std::marker::Sized` is not
}

fn main() {
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/bad-method-typaram-kind.rs
Expand Up @@ -9,7 +9,7 @@
// except according to those terms.

fn foo<T:'static>() {
1.bar::<T>(); //~ ERROR `std::marker::Send` is not implemented
1.bar::<T>(); //~ ERROR `T : std::marker::Send` is not satisfied
}

trait bar {
Expand Down
6 changes: 3 additions & 3 deletions src/test/compile-fail/bad-sized.rs
Expand Up @@ -12,7 +12,7 @@ trait Trait {}

pub fn main() {
let x: Vec<Trait + Sized> = Vec::new();
//~^ ERROR the trait `std::marker::Sized` is not implemented
//~| ERROR the trait `std::marker::Sized` is not implemented
//~| ERROR the trait `std::marker::Sized` is not implemented
//~^ ERROR `Trait + Sized : std::marker::Sized` is not satisfied
//~| ERROR `Trait + Sized : std::marker::Sized` is not satisfied
//~| ERROR `Trait + Sized : std::marker::Sized` is not satisfied
}
4 changes: 2 additions & 2 deletions src/test/compile-fail/builtin-superkinds-double-superkind.rs
Expand Up @@ -13,9 +13,9 @@

trait Foo : Send+Sync { }

impl <T: Sync+'static> Foo for (T,) { } //~ ERROR the trait `std::marker::Send` is not implemented
impl <T: Sync+'static> Foo for (T,) { } //~ ERROR `T : std::marker::Send` is not satisfied

impl <T: Send> Foo for (T,T) { } //~ ERROR the trait `std::marker::Sync` is not implemented
impl <T: Send> Foo for (T,T) { } //~ ERROR `T : std::marker::Sync` is not satisfied

impl <T: Send+Sync> Foo for (T,T,T) { } // (ok)

Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/builtin-superkinds-in-metadata.rs
Expand Up @@ -22,6 +22,6 @@ struct X<T>(T);
impl <T:Sync> RequiresShare for X<T> { }

impl <T:Sync+'static> RequiresRequiresShareAndSend for X<T> { }
//~^ ERROR the trait `std::marker::Send` is not implemented
//~^ ERROR `T : std::marker::Send` is not satisfied

fn main() { }
2 changes: 1 addition & 1 deletion src/test/compile-fail/builtin-superkinds-simple.rs
Expand Up @@ -14,6 +14,6 @@
trait Foo : Send { }

impl Foo for std::rc::Rc<i8> { }
//~^ ERROR the trait `std::marker::Send` is not implemented
//~^ ERROR `std::rc::Rc<i8> : std::marker::Send` is not satisfied

fn main() { }
Expand Up @@ -12,6 +12,6 @@

trait Foo : Send { }

impl <T: Sync+'static> Foo for T { } //~ ERROR the trait `std::marker::Send` is not implemented
impl <T: Sync+'static> Foo for T { } //~ ERROR `T : std::marker::Send` is not satisfied

fn main() { }
4 changes: 2 additions & 2 deletions src/test/compile-fail/cast-rfc0401.rs
Expand Up @@ -91,7 +91,7 @@ fn main()
let _ = 42usize as *const [u8]; //~ ERROR casting
let _ = v as *const [u8]; //~ ERROR cannot cast
let _ = fat_v as *const Foo;
//~^ ERROR `std::marker::Sized` is not implemented for the type `[u8]`
//~^ ERROR the predicate `[u8] : std::marker::Sized` is not satisfied
//~^^ HELP run `rustc --explain E0277` to see a detailed explanation
//~^^^ NOTE `[u8]` does not have a constant size known at compile-time
//~^^^^ NOTE required for the cast to the object type `Foo`
Expand All @@ -106,7 +106,7 @@ fn main()

let a : *const str = "hello";
let _ = a as *const Foo;
//~^ ERROR `std::marker::Sized` is not implemented for the type `str`
//~^ ERROR the predicate `str : std::marker::Sized` is not satisfied
//~^^ HELP run `rustc --explain E0277` to see a detailed explanation
//~^^^ NOTE `str` does not have a constant size known at compile-time
//~^^^^ NOTE required for the cast to the object type `Foo`
Expand Down
Expand Up @@ -13,7 +13,7 @@ struct X<F> where F: FnOnce() + 'static + Send {
}

fn foo<F>(blk: F) -> X<F> where F: FnOnce() + 'static {
//~^ ERROR the trait `std::marker::Send` is not implemented for the type
//~^ ERROR `F : std::marker::Send` is not satisfied
return X { field: blk };
}

Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/closure-bounds-subtype.rs
Expand Up @@ -21,7 +21,7 @@ fn give_any<F>(f: F) where F: FnOnce() {

fn give_owned<F>(f: F) where F: FnOnce() + Send {
take_any(f);
take_const_owned(f); //~ ERROR the trait `std::marker::Sync` is not implemented for the type
take_const_owned(f); //~ ERROR `F : std::marker::Sync` is not satisfied
}

fn main() {}
2 changes: 1 addition & 1 deletion src/test/compile-fail/cross-fn-cache-hole.rs
Expand Up @@ -23,7 +23,7 @@ trait Bar<X> { }

// We don't always check where clauses for sanity, but in this case
// wfcheck does report an error here:
fn vacuous<A>() //~ ERROR the trait `Bar<u32>` is not implemented for the type `i32`
fn vacuous<A>() //~ ERROR the predicate `i32 : Bar<u32>` is not satisfied
where i32: Foo<u32, A>
{
// ... the original intention was to check that we don't use that
Expand Down
Expand Up @@ -18,7 +18,7 @@ struct E {
#[derive(Clone)]
struct C {
x: NoCloneOrEq
//~^ ERROR the trait `std::clone::Clone` is not implemented for the type `NoCloneOrEq`
//~^ ERROR `NoCloneOrEq : std::clone::Clone` is not satisfied
}


Expand Down

0 comments on commit 8a461d9

Please sign in to comment.