From dbd75c8c40a06ac682251b67a548a8252c5d4b18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 8 Oct 2019 15:22:27 -0700 Subject: [PATCH] Handle more cases involving `impl` and `trait` --- src/librustc/traits/error_reporting.rs | 145 ++++++++++-------- .../associated-types-no-suitable-bound.stderr | 7 +- .../ui/consts/too_generic_eval_ice.stderr | 8 +- src/test/ui/impl-trait/issue-55872-1.stderr | 7 +- ...traints-are-local-for-inherent-impl.stderr | 5 +- ...onstraints-are-local-for-trait-impl.stderr | 5 +- 6 files changed, 100 insertions(+), 77 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index a717fb7f7c0f..c8baafef50a7 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -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`. - 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`. + 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`. diff --git a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr index ada9cacbee52..78198322913c 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr @@ -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(foo: ::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 diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr index 0733a51233e3..2fb9977f4d70 100644 --- a/src/test/ui/consts/too_generic_eval_ice.stderr +++ b/src/test/ui/consts/too_generic_eval_ice.stderr @@ -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); | --------------------------- required by `Foo` +LL | +LL | impl Foo { + | - 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 - = 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); | --------------------------- required by `Foo` +LL | +LL | impl Foo { + | - 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 - = help: consider adding a `where B: std::marker::Sized` bound error: aborting due to 3 previous errors diff --git a/src/test/ui/impl-trait/issue-55872-1.stderr b/src/test/ui/impl-trait/issue-55872-1.stderr index d5756c015596..0d8ee61b5ba1 100644 --- a/src/test/ui/impl-trait/issue-55872-1.stderr +++ b/src/test/ui/impl-trait/issue-55872-1.stderr @@ -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 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() -> 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 diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr index 727c9b8e0672..995b54460038 100644 --- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr +++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr @@ -4,10 +4,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied LL | fn require_copy(x: T) {} | ------------ ---- required by this bound in `require_copy` ... +LL | impl Foo { + | - 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 diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr index 1c1937c3074d..fe575f3a28a9 100644 --- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr +++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr @@ -4,10 +4,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied LL | fn require_copy(x: T) {} | ------------ ---- required by this bound in `require_copy` ... +LL | impl Foo for Bar { + | - 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