Handle missing projection restriction
This commit is contained in:
parent
daa8491648
commit
5cc99eed04
13 changed files with 134 additions and 25 deletions
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
14
src/test/ui/associated-types/associated-types-unsized.fixed
Normal file
14
src/test/ui/associated-types/associated-types-unsized.fixed
Normal 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() {
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
// run-rustfix
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
trait Get {
|
||||
type Value: ?Sized;
|
||||
fn get(&self) -> <Self as Get>::Value;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>`
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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() { }
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue