diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2019-10-09 15:07:22 -0700 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2019-10-15 13:55:44 -0700 |
| commit | 5cc99eed04005108797fbba82eaf8ef7918051db (patch) | |
| tree | e62d586e89316a4253ed97bddcefadf27f0e6ab5 | |
| parent | daa8491648d742085bf071169624d99d542a044f (diff) | |
| download | rust-5cc99eed04005108797fbba82eaf8ef7918051db.tar.gz rust-5cc99eed04005108797fbba82eaf8ef7918051db.zip | |
Handle missing projection restriction
13 files changed, 134 insertions, 25 deletions
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 77d4e10d4f4..2ac691b47ac 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -975,11 +975,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_ref.self_ty(), trait_ref.self_ty().kind, ); - let param_ty = if let ty::Param(param_ty) = &trait_ref.self_ty().kind { - param_ty - } else { - err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate())); - return; + let (param_ty, projection) = match &trait_ref.self_ty().kind { + ty::Param(param_ty) => (Some(param_ty), None), + ty::Projection(projection) => (None, Some(projection)), + _ => { + err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate())); + return; + } }; let mut hir_id = body_id; @@ -996,7 +998,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { hir::Node::ImplItem(hir::ImplItem { generics, kind: hir::ImplItemKind::Method(hir::MethodSig { decl, .. }, _), .. - }) if param_ty.name.as_str() == "Self" => { + }) if param_ty.map(|p| p.name.as_str() == "Self").unwrap_or(false) => { if !generics.where_clause.predicates.is_empty() { err.span_suggestion( generics.where_clause.span().unwrap().shrink_to_hi(), @@ -1014,6 +1016,34 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } return; } + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(decl, _, generics, _), .. + }) | + hir::Node::TraitItem(hir::TraitItem { + generics, + kind: hir::TraitItemKind::Method(hir::MethodSig { decl, .. }, _), .. + }) | + hir::Node::ImplItem(hir::ImplItem { + generics, + kind: hir::ImplItemKind::Method(hir::MethodSig { decl, .. }, _), .. + }) if projection.is_some() => { + if !generics.where_clause.predicates.is_empty() { + err.span_suggestion( + generics.where_clause.span().unwrap().shrink_to_hi(), + "consider further restricting the associated type", + format!(", {}", trait_ref.to_predicate()), + Applicability::MachineApplicable, + ); + } else { + err.span_suggestion( + decl.output.span().shrink_to_hi(), + "consider further restricting the associated type", + format!(" where {}", trait_ref.to_predicate()), + Applicability::MachineApplicable, + ); + } + return; + } hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(_, generics), span, .. }) | hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics), span, .. }) | hir::Node::Item(hir::Item { kind: hir::ItemKind::Union(_, generics), span, .. }) | @@ -1036,9 +1066,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), span, .. }) | hir::Node::TraitItem(hir::TraitItem { generics, span, .. }) | - hir::Node::ImplItem(hir::ImplItem { generics, span, .. }) => { + hir::Node::ImplItem(hir::ImplItem { generics, span, .. }) + if param_ty.is_some() => { let restrict_msg = "consider further restricting this bound"; - let param_name = param_ty.name.as_str(); + let param_name = param_ty.unwrap().name.as_str(); for param in &generics.params { if param_name == param.name.ident().as_str() { if param_name.starts_with("impl ") { @@ -1064,7 +1095,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { generics.where_clause.span().unwrap().shrink_to_hi(), &format!( "consider further restricting type parameter `{}`", - param_ty, + param_name, ), format!(", {}", trait_ref.to_predicate()), Applicability::MachineApplicable, diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr index 06e8230aa15..1795fb5aceb 100644 --- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr @@ -9,7 +9,10 @@ LL | impl Case1 for S1 { error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 | -LL | / fn assume_case1<T: 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::iter::Iterator` + | _| + | | LL | | LL | | LL | | @@ -19,7 +22,6 @@ LL | | } | |_^ `<<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 adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::iter::Iterator` bound 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:37:1 @@ -27,7 +29,10 @@ error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent be LL | trait Case1 { | ----------- required by `Case1` ... -LL | / fn assume_case1<T: 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` + | _| + | | LL | | LL | | LL | | @@ -37,7 +42,6 @@ LL | | } | |_^ `<<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 adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Send` bound 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:37:1 @@ -45,7 +49,10 @@ error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared LL | trait Case1 { | ----------- required by `Case1` ... -LL | / fn assume_case1<T: 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` + | _| + | | LL | | LL | | LL | | @@ -55,7 +62,6 @@ LL | | } | |_^ `<<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 adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync` bound error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 diff --git a/src/test/ui/associated-types/associated-types-bound-failure.fixed b/src/test/ui/associated-types/associated-types-bound-failure.fixed new file mode 100644 index 00000000000..68ee38d16b3 --- /dev/null +++ b/src/test/ui/associated-types/associated-types-bound-failure.fixed @@ -0,0 +1,29 @@ +// run-rustfix +// Test equality constraints on associated types in a where clause. +#![allow(dead_code)] + +pub trait ToInt { + fn to_int(&self) -> isize; +} + +pub trait GetToInt +{ + type R; + + fn get(&self) -> <Self as GetToInt>::R; +} + +fn foo<G>(g: G) -> isize + where G : GetToInt, <G as GetToInt>::R: ToInt +{ + ToInt::to_int(&g.get()) //~ ERROR E0277 +} + +fn bar<G : GetToInt>(g: G) -> isize + where G::R : ToInt +{ + ToInt::to_int(&g.get()) // OK +} + +pub fn main() { +} diff --git a/src/test/ui/associated-types/associated-types-bound-failure.rs b/src/test/ui/associated-types/associated-types-bound-failure.rs index 883ac363b44..31e073cc7a8 100644 --- a/src/test/ui/associated-types/associated-types-bound-failure.rs +++ b/src/test/ui/associated-types/associated-types-bound-failure.rs @@ -1,4 +1,6 @@ +// run-rustfix // Test equality constraints on associated types in a where clause. +#![allow(dead_code)] pub trait ToInt { fn to_int(&self) -> isize; diff --git a/src/test/ui/associated-types/associated-types-bound-failure.stderr b/src/test/ui/associated-types/associated-types-bound-failure.stderr index 85acf134d51..c420c86a275 100644 --- a/src/test/ui/associated-types/associated-types-bound-failure.stderr +++ b/src/test/ui/associated-types/associated-types-bound-failure.stderr @@ -1,13 +1,14 @@ error[E0277]: the trait bound `<G as GetToInt>::R: ToInt` is not satisfied - --> $DIR/associated-types-bound-failure.rs:17:19 + --> $DIR/associated-types-bound-failure.rs:19:19 | 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 adding a `where <G as GetToInt>::R: ToInt` bound error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-unsized.fixed b/src/test/ui/associated-types/associated-types-unsized.fixed new file mode 100644 index 00000000000..385de541e56 --- /dev/null +++ b/src/test/ui/associated-types/associated-types-unsized.fixed @@ -0,0 +1,14 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] + +trait Get { + type Value: ?Sized; + fn get(&self) -> <Self as Get>::Value; +} + +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 +} + +fn main() { +} diff --git a/src/test/ui/associated-types/associated-types-unsized.rs b/src/test/ui/associated-types/associated-types-unsized.rs index a9bc24e44d1..bdba4c7ff16 100644 --- a/src/test/ui/associated-types/associated-types-unsized.rs +++ b/src/test/ui/associated-types/associated-types-unsized.rs @@ -1,3 +1,6 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] + trait Get { type Value: ?Sized; fn get(&self) -> <Self as Get>::Value; diff --git a/src/test/ui/associated-types/associated-types-unsized.stderr b/src/test/ui/associated-types/associated-types-unsized.stderr index b5db9743932..18595721bce 100644 --- a/src/test/ui/associated-types/associated-types-unsized.stderr +++ b/src/test/ui/associated-types/associated-types-unsized.stderr @@ -1,12 +1,13 @@ error[E0277]: the size for values of type `<T as Get>::Value` cannot be known at compilation time - --> $DIR/associated-types-unsized.rs:7:9 + --> $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> - = help: consider adding a `where <T as Get>::Value: std::marker::Sized` bound = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/issues/issue-22872.stderr b/src/test/ui/issues/issue-22872.stderr index fc5de23752b..283a5e04a8b 100644 --- a/src/test/ui/issues/issue-22872.stderr +++ b/src/test/ui/issues/issue-22872.stderr @@ -1,11 +1,12 @@ error[E0277]: `<P as Process<'_>>::Item` is not an iterator --> $DIR/issue-22872.rs:20:40 | +LL | fn push_process<P>(process: P) where P: Process<'static> { + | - help: consider further restricting the associated type: `, <P as Process<'_>>::Item: std::iter::Iterator` LL | let _: Box<dyn for<'b> Wrap<'b>> = Box::new(Wrapper(process)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `<P as Process<'_>>::Item` is not an iterator | = help: the trait `std::iter::Iterator` is not implemented for `<P as Process<'_>>::Item` - = help: consider adding a `where <P as Process<'_>>::Item: std::iter::Iterator` bound = note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper<P>` = note: required for the cast to the object type `dyn for<'b> Wrap<'b>` diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr index bfdc4272fb3..6688203147e 100644 --- a/src/test/ui/issues/issue-42312.stderr +++ b/src/test/ui/issues/issue-42312.stderr @@ -2,11 +2,12 @@ error[E0277]: the size for values of type `<Self as std::ops::Deref>::Target` ca --> $DIR/issue-42312.rs:4:29 | LL | fn baz(_: Self::Target) where Self: Deref {} - | ^ doesn't have a size known at compile-time + | ^ - help: consider further restricting the associated type: `, <Self as std::ops::Deref>::Target: std::marker::Sized` + | | + | doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `<Self as std::ops::Deref>::Target` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> - = help: consider adding a `where <Self as std::ops::Deref>::Target: std::marker::Sized` bound = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed new file mode 100644 index 00000000000..757d8b8a235 --- /dev/null +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed @@ -0,0 +1,17 @@ +// run-rustfix +// Test that we do not consider associated types to be sendable without +// some applicable trait bound (and we don't ICE). +#![allow(dead_code)] + +trait Trait { + type AssocType; + fn dummy(&self) { } +} +fn bar<T:Trait+Send>() where <T as Trait>::AssocType: std::marker::Send{ + is_send::<T::AssocType>(); //~ ERROR E0277 +} + +fn is_send<T:Send>() { +} + +fn main() { } diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs index d6483539386..bafc1657737 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs @@ -1,5 +1,7 @@ +// run-rustfix // Test that we do not consider associated types to be sendable without // some applicable trait bound (and we don't ICE). +#![allow(dead_code)] trait Trait { type AssocType; diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr index b842d0ae1a2..dd6dcbe2ef5 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr @@ -1,6 +1,8 @@ error[E0277]: `<T as Trait>::AssocType` cannot be sent between threads safely - --> $DIR/typeck-default-trait-impl-assoc-type.rs:9:5 + --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:5 | +LL | fn bar<T:Trait+Send>() { + | - help: consider further restricting the associated type: `where <T as Trait>::AssocType: std::marker::Send` LL | is_send::<T::AssocType>(); | ^^^^^^^^^^^^^^^^^^^^^^^ `<T as Trait>::AssocType` cannot be sent between threads safely ... @@ -8,7 +10,6 @@ LL | fn is_send<T:Send>() { | ------- ---- required by this bound in `is_send` | = help: the trait `std::marker::Send` is not implemented for `<T as Trait>::AssocType` - = help: consider adding a `where <T as Trait>::AssocType: std::marker::Send` bound error: aborting due to previous error |
