Handle more cases involving `impl` and `trait`

This commit is contained in:
Esteban Küber 2019-10-08 15:22:27 -07:00
parent 5b7ffd9333
commit dbd75c8c40
6 changed files with 100 additions and 77 deletions

View File

@ -969,90 +969,103 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
trait_ref: &ty::PolyTraitRef<'_>,
body_id: hir::HirId,
) {
let node = self.tcx.hir()
.find(self.tcx.hir().get_parent_item(body_id))
.or_else(|| self.tcx.hir().find(body_id));
debug!(
"suggest_restricting_param_bound node={:?} - trait_ref={:?} ty={:?} ({:?})",
node,
"suggest_restricting_param_bound trait_ref={:?} ty={:?} ({:?})",
trait_ref,
trait_ref.self_ty(),
trait_ref.self_ty().kind,
);
if let ty::Param(param_ty) = &trait_ref.self_ty().kind {
let restrict_msg = "consider further restricting this bound";
let param_name = param_ty.name.as_str();
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;
};
if let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Struct(_, generics), span, ..
})) |
Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Enum(_, generics), span, ..
})) |
Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Union(_, generics), span, ..
})) |
Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Trait(_, _, generics, ..), span, ..
})) |
Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(_, _, _, generics, ..), span, ..
})) |
Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(_, _, generics, _), span, ..
})) = &node {
for param in &generics.params {
if param_name == param.name.ident().as_str() {
if param_name.starts_with("impl ") {
err.span_suggestion(
param.span,
restrict_msg,
// `impl CurrentTrait + MissingTrait`
format!("{} + {}", param.name.ident(), trait_ref),
Applicability::MachineApplicable,
);
} else {
if generics.where_clause.predicates.is_empty() &&
param.bounds.is_empty()
{
let mut hir_id = body_id;
while let Some(node) = self.tcx.hir().find(hir_id) {
debug!("suggest_restricting_param_bound node={:?}", node);
match node {
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, .. }) |
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Trait(_, _, generics, ..), span, ..
}) |
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(_, _, _, generics, ..), span, ..
}) |
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(_, _, generics, _), span, ..
}) |
hir::Node::Item(hir::Item {
kind: hir::ItemKind::TyAlias(_, generics), span, ..
}) |
hir::Node::Item(hir::Item {
kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), span, ..
}) |
hir::Node::TraitItem(hir::TraitItem { generics, span, .. }) |
hir::Node::ImplItem(hir::ImplItem { generics, span, .. }) => {
let restrict_msg = "consider further restricting this bound";
let param_name = param_ty.name.as_str();
for param in &generics.params {
if param_name == param.name.ident().as_str() {
if param_name.starts_with("impl ") {
err.span_suggestion(
param.span,
"consider restricting this bound",
format!("{}", trait_ref.to_predicate()),
Applicability::MachineApplicable,
);
} else if !generics.where_clause.predicates.is_empty() {
err.span_suggestion(
generics.where_clause.span().unwrap().shrink_to_hi(),
&format!(
"consider further restricting type parameter `{}`",
param_ty,
),
format!(", {}", trait_ref.to_predicate()),
restrict_msg,
// `impl CurrentTrait + MissingTrait`
format!("{} + {}", param.name.ident(), trait_ref),
Applicability::MachineApplicable,
);
} else {
let sp = param.span.with_hi(span.hi());
let span = self.tcx.sess.source_map().span_through_char(sp, ':');
if sp != param.span && sp != span {
// Only suggest if we have high certainty that the span covers
// the colon in `foo<T: Trait>`.
err.span_suggestion(span, restrict_msg, format!(
"{} + ",
trait_ref.to_predicate(),
), Applicability::MachineApplicable);
if generics.where_clause.predicates.is_empty() &&
param.bounds.is_empty()
{
err.span_suggestion(
param.span,
"consider restricting this bound",
format!("{}", trait_ref.to_predicate()),
Applicability::MachineApplicable,
);
} else if !generics.where_clause.predicates.is_empty() {
err.span_suggestion(
generics.where_clause.span().unwrap().shrink_to_hi(),
&format!(
"consider further restricting type parameter `{}`",
param_ty,
),
format!(", {}", trait_ref.to_predicate()),
Applicability::MachineApplicable,
);
} else {
err.span_label(param.span, &format!(
"consider adding a `where {}` bound",
trait_ref.to_predicate(),
));
let sp = param.span.with_hi(span.hi());
let span = self.tcx.sess.source_map()
.span_through_char(sp, ':');
if sp != param.span && sp != span {
// Only suggest if we have high certainty that the span
// covers the colon in `foo<T: Trait>`.
err.span_suggestion(span, restrict_msg, format!(
"{} + ",
trait_ref.to_predicate(),
), Applicability::MachineApplicable);
} else {
err.span_label(param.span, &format!(
"consider adding a `where {}` bound",
trait_ref.to_predicate(),
));
}
}
}
return;
}
return;
}
}
hir::Node::Crate => return,
_ => {}
}
hir_id = self.tcx.hir().get_parent_item(hir_id);
}
// FIXME: Add special check for `?Sized` so we don't suggest `T: Sized + ?Sized`.

View File

@ -2,9 +2,10 @@ error[E0277]: the trait bound `T: Get` is not satisfied
--> $DIR/associated-types-no-suitable-bound.rs:11:5
|
LL | fn uhoh<T>(foo: <T as Get>::Value) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
|
= help: consider adding a `where T: Get` bound
| ^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | help: consider restricting this bound: `T: Get`
| the trait `Get` is not implemented for `T`
error: aborting due to previous error

View File

@ -16,26 +16,30 @@ error[E0277]: the size for values of type `A` cannot be known at compilation tim
|
LL | pub struct Foo<A, B>(A, B);
| --------------------------- required by `Foo`
LL |
LL | impl<A, B> Foo<A, B> {
| - help: consider restricting this bound: `A: std::marker::Sized`
...
LL | [5; Self::HOST_SIZE] == [6; 0]
| ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `A`
= 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 A: std::marker::Sized` bound
error[E0277]: the size for values of type `B` cannot be known at compilation time
--> $DIR/too_generic_eval_ice.rs:7:13
|
LL | pub struct Foo<A, B>(A, B);
| --------------------------- required by `Foo`
LL |
LL | impl<A, B> Foo<A, B> {
| - help: consider restricting this bound: `B: std::marker::Sized`
...
LL | [5; Self::HOST_SIZE] == [6; 0]
| ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `B`
= 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 B: std::marker::Sized` bound
error: aborting due to 3 previous errors

View File

@ -1,10 +1,11 @@
error[E0277]: the trait bound `S: std::marker::Copy` is not satisfied in `(S, T)`
--> $DIR/issue-55872-1.rs:12:5
|
LL | impl<S: Default> Bar for S {
| -- help: consider further restricting this bound: `S: std::marker::Copy +`
LL | type E = impl Copy;
| ^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `S`
|
= help: consider adding a `where S: std::marker::Copy` bound
= note: required because it appears within the type `(S, T)`
= note: the return type of a function must have a statically known size
@ -13,8 +14,10 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied in `(S, T)
|
LL | type E = impl Copy;
| ^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `T`
...
LL | fn foo<T: Default>() -> Self::E {
| -- help: consider further restricting this bound: `T: std::marker::Copy +`
|
= help: consider adding a `where T: std::marker::Copy` bound
= note: required because it appears within the type `(S, T)`
= note: the return type of a function must have a statically known size

View File

@ -4,10 +4,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
LL | fn require_copy<T: Copy>(x: T) {}
| ------------ ---- required by this bound in `require_copy`
...
LL | impl<T> Foo<T> {
| - help: consider restricting this bound: `T: std::marker::Copy`
...
LL | require_copy(self.x);
| ^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
|
= help: consider adding a `where T: std::marker::Copy` bound
error: aborting due to previous error

View File

@ -4,10 +4,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
LL | fn require_copy<T: Copy>(x: T) {}
| ------------ ---- required by this bound in `require_copy`
...
LL | impl<T> Foo<T> for Bar<T> {
| - help: consider restricting this bound: `T: std::marker::Copy`
...
LL | require_copy(self.x);
| ^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
|
= help: consider adding a `where T: std::marker::Copy` bound
error: aborting due to previous error