Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggest adding super trait constraints #71451

Merged
merged 4 commits into from
May 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 56 additions & 8 deletions src/librustc_trait_selection/traits/error_reporting/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rustc_middle::ty::{
self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty,
TyCtxt, TypeFoldable, WithConstness,
};
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use std::fmt;

Expand Down Expand Up @@ -156,7 +156,7 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, St
(
generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(),
format!(
"{} {} ",
"{} {}",
if !generics.where_clause.predicates.is_empty() { "," } else { " where" },
pred,
),
Expand All @@ -173,7 +173,13 @@ fn suggest_restriction(
fn_sig: Option<&hir::FnSig<'_>>,
projection: Option<&ty::ProjectionTy<'_>>,
trait_ref: ty::PolyTraitRef<'_>,
super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>,
estebank marked this conversation as resolved.
Show resolved Hide resolved
) {
// When we are dealing with a trait, `super_traits` will be `Some`:
// Given `trait T: A + B + C {}`
// - ^^^^^^^^^ GenericBounds
// |
// &Ident
let span = generics.where_clause.span_for_predicates_or_empty_place();
if span.from_expansion() || span.desugaring_kind().is_some() {
return;
Expand Down Expand Up @@ -262,10 +268,28 @@ fn suggest_restriction(
);
} else {
// Trivial case: `T` needs an extra bound: `T: Bound`.
let (sp, sugg) =
predicate_constraint(generics, trait_ref.without_const().to_predicate().to_string());
let appl = Applicability::MachineApplicable;
err.span_suggestion(sp, &format!("consider further restricting {}", msg), sugg, appl);
let (sp, suggestion) = match super_traits {
None => {
predicate_constraint(generics, trait_ref.without_const().to_predicate().to_string())
}
Some((ident, bounds)) => match bounds {
[.., bound] => (
bound.span().shrink_to_hi(),
format!(" + {}", trait_ref.print_only_trait_path().to_string()),
),
[] => (
ident.span.shrink_to_hi(),
format!(": {}", trait_ref.print_only_trait_path().to_string()),
),
},
};

err.span_suggestion_verbose(
sp,
&format!("consider further restricting {}", msg),
suggestion,
Applicability::MachineApplicable,
);
}
}

Expand All @@ -288,13 +312,35 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let mut hir_id = body_id;
while let Some(node) = self.tcx.hir().find(hir_id) {
match node {
hir::Node::Item(hir::Item {
ident,
kind: hir::ItemKind::Trait(_, _, generics, bounds, _),
..
}) if self_ty == self.tcx.types.self_param => {
assert!(param_ty);
// Restricting `Self` for a single method.
suggest_restriction(
&generics,
"`Self`",
err,
None,
projection,
trait_ref,
Some((ident, bounds)),
);
return;
}

hir::Node::TraitItem(hir::TraitItem {
generics,
kind: hir::TraitItemKind::Fn(..),
..
}) if param_ty && self_ty == self.tcx.types.self_param => {
}) if self_ty == self.tcx.types.self_param => {
assert!(param_ty);
// Restricting `Self` for a single method.
suggest_restriction(&generics, "`Self`", err, None, projection, trait_ref);
suggest_restriction(
&generics, "`Self`", err, None, projection, trait_ref, None,
);
return;
}

Expand All @@ -319,6 +365,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
Some(fn_sig),
projection,
trait_ref,
None,
);
return;
}
Expand All @@ -336,6 +383,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
None,
projection,
trait_ref,
None,
);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterato
--> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20
|
LL | fn assume_case1<T: Case1>() {
| ^^^^^ - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::iter::Iterator`
| |
| `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
| ^^^^^ `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
|
= help: the trait `std::iter::Iterator` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
help: consider further restricting the associated type
|
LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as std::iter::Iterator>::Item: std::iter::Iterator {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
--> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20
Expand All @@ -32,11 +34,13 @@ LL | Send + Iterator<Item:
| ---- required by this bound in `Case1`
...
LL | fn assume_case1<T: Case1>() {
| ^^^^^ - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Send`
| |
| `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
| ^^^^^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
help: consider further restricting the associated type
|
LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Send {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
--> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20
Expand All @@ -48,11 +52,13 @@ LL | > + Sync>;
| ---- required by this bound in `Case1`
...
LL | fn assume_case1<T: Case1>() {
| ^^^^^ - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync`
| |
| `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
| ^^^^^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
|
= help: the trait `std::marker::Sync` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
help: consider further restricting the associated type
|
LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug`
--> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub trait GetToInt
}

fn foo<G>(g: G) -> isize
where G : GetToInt, <G as GetToInt>::R: ToInt
where G : GetToInt, <G as GetToInt>::R: ToInt
{
ToInt::to_int(&g.get()) //~ ERROR E0277
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ error[E0277]: the trait bound `<G as GetToInt>::R: ToInt` is not satisfied
LL | fn to_int(&self) -> isize;
| -------------------------- required by `ToInt::to_int`
...
LL | where G : GetToInt
| - help: consider further restricting the associated type: `, <G as GetToInt>::R: ToInt`
LL | {
LL | ToInt::to_int(&g.get())
| ^^^^^^^^ the trait `ToInt` is not implemented for `<G as GetToInt>::R`
|
help: consider further restricting the associated type
|
LL | where G : GetToInt, <G as GetToInt>::R: ToInt
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ trait Get {
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ error[E0277]: the trait bound `Self: Get` is not satisfied
--> $DIR/associated-types-for-unimpl-trait.rs:10:5
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
| | |
| | help: consider further restricting `Self`: `where Self: Get`
| the trait `Get` is not implemented for `Self`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {}
| ^^^^^^^^^^^^^^^

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ error[E0277]: the trait bound `Self: Get` is not satisfied
--> $DIR/associated-types-no-suitable-supertrait-2.rs:17:5
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
| | |
| | help: consider further restricting `Self`: `where Self: Get`
| the trait `Get` is not implemented for `Self`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {}
| ^^^^^^^^^^^^^^^

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ error[E0277]: the trait bound `Self: Get` is not satisfied
--> $DIR/associated-types-no-suitable-supertrait.rs:17:5
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
| | |
| | help: consider further restricting `Self`: `where Self: Get`
| the trait `Get` is not implemented for `Self`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {}
| ^^^^^^^^^^^^^^^

error[E0277]: the trait bound `(T, U): Get` is not satisfied
--> $DIR/associated-types-no-suitable-supertrait.rs:22:5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ trait Get {
}

trait Other {
fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get ;
fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get;
//~^ ERROR E0277
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ error[E0277]: the trait bound `Self: Get` is not satisfied
--> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:5
|
LL | fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| | |
| | help: consider further restricting `Self`: `where Self: Get`
| the trait `Get` is not implemented for `Self`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|
LL | fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get;
| ^^^^^^^^^^^^^^^

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ trait Get {
fn get(&self) -> <Self as Get>::Value;
}

fn foo<T:Get>(t: T) where <T as Get>::Value: std::marker::Sized {
fn foo<T:Get>(t: T) where <T as Get>::Value: std::marker::Sized {
let x = t.get(); //~ ERROR the size for values of type
}

Expand Down
6 changes: 4 additions & 2 deletions src/test/ui/associated-types/associated-types-unsized.stderr
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
error[E0277]: the size for values of type `<T as Get>::Value` cannot be known at compilation time
--> $DIR/associated-types-unsized.rs:10:9
|
LL | fn foo<T:Get>(t: T) {
| - help: consider further restricting the associated type: `where <T as Get>::Value: std::marker::Sized`
LL | let x = t.get();
| ^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `<T as Get>::Value`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: all local variables must have a statically known size
= help: unsized locals are gated as an unstable feature
help: consider further restricting the associated type
|
LL | fn foo<T:Get>(t: T) where <T as Get>::Value: std::marker::Sized {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

Expand Down
16 changes: 10 additions & 6 deletions src/test/ui/associated-types/defaults-suitability.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -85,25 +85,29 @@ error[E0277]: the trait bound `<Self as Foo2<T>>::Baz: std::clone::Clone` is not
--> $DIR/defaults-suitability.rs:72:15
|
LL | trait Foo2<T> {
| -------------- help: consider further restricting the associated type: `where <Self as Foo2<T>>::Baz: std::clone::Clone`
| |
| required by `Foo2`
| ------------- required by `Foo2`
LL | type Bar: Clone = Vec<Self::Baz>;
| ^^^^^ the trait `std::clone::Clone` is not implemented for `<Self as Foo2<T>>::Baz`
|
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<<Self as Foo2<T>>::Baz>`
help: consider further restricting the associated type
|
LL | trait Foo2<T> where <Self as Foo2<T>>::Baz: std::clone::Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `<Self as Foo25<T>>::Baz: std::clone::Clone` is not satisfied
--> $DIR/defaults-suitability.rs:81:15
|
LL | trait Foo25<T: Clone> {
| ---------------------- help: consider further restricting the associated type: `where <Self as Foo25<T>>::Baz: std::clone::Clone`
| |
| required by `Foo25`
| --------------------- required by `Foo25`
LL | type Bar: Clone = Vec<Self::Baz>;
| ^^^^^ the trait `std::clone::Clone` is not implemented for `<Self as Foo25<T>>::Baz`
|
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<<Self as Foo25<T>>::Baz>`
help: consider further restricting the associated type
|
LL | trait Foo25<T: Clone> where <Self as Foo25<T>>::Baz: std::clone::Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied
--> $DIR/defaults-suitability.rs:90:16
Expand Down
18 changes: 18 additions & 0 deletions src/test/ui/associated-types/defaults-unsound-62211-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ LL | trait UncheckedCopy: Sized {
...
LL | type Output: Copy
| ^^^^ the trait `std::marker::Copy` is not implemented for `Self`
|
help: consider further restricting `Self`
|
LL | trait UncheckedCopy: Sized + std::marker::Copy {
| ^^^^^^^^^^^^^^^^^^^

error[E0277]: cannot add-assign `&'static str` to `Self`
--> $DIR/defaults-unsound-62211-1.rs:25:7
Expand All @@ -17,6 +22,10 @@ LL | + AddAssign<&'static str>
| ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
|
= help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self`
help: consider further restricting `Self`
|
LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied
--> $DIR/defaults-unsound-62211-1.rs:23:7
Expand All @@ -26,6 +35,11 @@ LL | trait UncheckedCopy: Sized {
...
LL | + Deref<Target = str>
| ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self`
|
help: consider further restricting `Self`
|
LL | trait UncheckedCopy: Sized + std::ops::Deref {
| ^^^^^^^^^^^^^^^^^

error[E0277]: `Self` doesn't implement `std::fmt::Display`
--> $DIR/defaults-unsound-62211-1.rs:28:7
Expand All @@ -38,6 +52,10 @@ LL | + Display = Self;
|
= help: the trait `std::fmt::Display` is not implemented for `Self`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
help: consider further restricting `Self`
|
LL | trait UncheckedCopy: Sized + std::fmt::Display {
| ^^^^^^^^^^^^^^^^^^^

error[E0277]: `T` doesn't implement `std::fmt::Display`
--> $DIR/defaults-unsound-62211-1.rs:41:9
Expand Down
Loading