Handle missing projection restriction

This commit is contained in:
Esteban Küber 2019-10-09 15:07:22 -07:00
parent daa8491648
commit 5cc99eed04
13 changed files with 134 additions and 25 deletions

View file

@ -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,

View file

@ -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

View file

@ -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() {
}

View file

@ -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;

View file

@ -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

View file

@ -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() {
}

View file

@ -1,3 +1,6 @@
// run-rustfix
#![allow(dead_code, unused_variables)]
trait Get {
type Value: ?Sized;
fn get(&self) -> <Self as Get>::Value;

View file

@ -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

View file

@ -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>`

View file

@ -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

View file

@ -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() { }

View file

@ -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;

View file

@ -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