From 545320a22ff61c30e932200c07466ba3f2be76aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 22 Apr 2020 16:03:39 -0700 Subject: [PATCH] Suggest adding super trait constraints --- .../traits/error_reporting/suggestions.rs | 45 +++++++++++++++++-- .../defaults-unsound-62211-1.stderr | 16 +++++-- .../defaults-unsound-62211-2.stderr | 16 +++++-- .../ui/associated-types/issue-63593.stderr | 4 +- ...ait-with-supertraits-needing-sized-self.rs | 11 +++++ ...with-supertraits-needing-sized-self.stderr | 17 +++++++ 6 files changed, 96 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.rs create mode 100644 src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index e0b99333fd10b..5abae7ed68b99 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{ self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use std::fmt; @@ -173,6 +173,7 @@ fn suggest_restriction( fn_sig: Option<&hir::FnSig<'_>>, projection: Option<&ty::ProjectionTy<'_>>, trait_ref: ty::PolyTraitRef<'_>, + super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>, ) { let span = generics.where_clause.span_for_predicates_or_empty_place(); if span.from_expansion() || span.desugaring_kind().is_some() { @@ -262,8 +263,22 @@ fn suggest_restriction( ); } else { // Trivial case: `T` needs an extra bound: `T: Bound`. - let (sp, sugg) = - predicate_constraint(generics, trait_ref.without_const().to_predicate().to_string()); + let (sp, sugg) = match super_traits { + None => { + predicate_constraint(generics, trait_ref.without_const().to_predicate().to_string()) + } + Some((ident, bounds)) => match bounds { + [.., bound] => ( + bound.span().shrink_to_hi(), + format!(" + {}", trait_ref.print_only_trait_path().to_string()), + ), + [] => ( + ident.span.shrink_to_hi(), + format!(": {}", trait_ref.print_only_trait_path().to_string()), + ), + }, + }; + let appl = Applicability::MachineApplicable; err.span_suggestion(sp, &format!("consider further restricting {}", msg), sugg, appl); } @@ -288,13 +303,33 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let mut hir_id = body_id; while let Some(node) = self.tcx.hir().find(hir_id) { match node { + hir::Node::Item(hir::Item { + ident, + kind: hir::ItemKind::Trait(_, _, generics, bounds, _), + .. + }) if param_ty && self_ty == self.tcx.types.self_param => { + // Restricting `Self` for a single method. + suggest_restriction( + &generics, + "`Self`", + err, + None, + projection, + trait_ref, + Some((ident, bounds)), + ); + return; + } + hir::Node::TraitItem(hir::TraitItem { generics, kind: hir::TraitItemKind::Fn(..), .. }) if param_ty && self_ty == self.tcx.types.self_param => { // Restricting `Self` for a single method. - suggest_restriction(&generics, "`Self`", err, None, projection, trait_ref); + suggest_restriction( + &generics, "`Self`", err, None, projection, trait_ref, None, + ); return; } @@ -319,6 +354,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { Some(fn_sig), projection, trait_ref, + None, ); return; } @@ -336,6 +372,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { None, projection, trait_ref, + None, ); return; } diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr index 856d513d60bd3..c804bc3d833fa 100644 --- a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr +++ b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr @@ -2,7 +2,9 @@ error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied --> $DIR/defaults-unsound-62211-1.rs:21:18 | LL | trait UncheckedCopy: Sized { - | -------------------------- required by `UncheckedCopy` + | --------------------------- help: consider further restricting `Self`: `+ std::marker::Copy` + | | + | required by `UncheckedCopy` ... LL | type Output: Copy | ^^^^ the trait `std::marker::Copy` is not implemented for `Self` @@ -11,7 +13,9 @@ error[E0277]: cannot add-assign `&'static str` to `Self` --> $DIR/defaults-unsound-62211-1.rs:25:7 | LL | trait UncheckedCopy: Sized { - | -------------------------- required by `UncheckedCopy` + | --------------------------- help: consider further restricting `Self`: `+ std::ops::AddAssign<&'static str>` + | | + | required by `UncheckedCopy` ... LL | + AddAssign<&'static str> | ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str` @@ -22,7 +26,9 @@ error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied --> $DIR/defaults-unsound-62211-1.rs:23:7 | LL | trait UncheckedCopy: Sized { - | -------------------------- required by `UncheckedCopy` + | --------------------------- help: consider further restricting `Self`: `+ std::ops::Deref` + | | + | required by `UncheckedCopy` ... LL | + Deref | ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self` @@ -31,7 +37,9 @@ error[E0277]: `Self` doesn't implement `std::fmt::Display` --> $DIR/defaults-unsound-62211-1.rs:28:7 | LL | trait UncheckedCopy: Sized { - | -------------------------- required by `UncheckedCopy` + | --------------------------- help: consider further restricting `Self`: `+ std::fmt::Display` + | | + | required by `UncheckedCopy` ... LL | + Display = Self; | ^^^^^^^ `Self` cannot be formatted with the default formatter diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr index 1060c82fec22a..aee5e4b28ca6d 100644 --- a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr +++ b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr @@ -2,7 +2,9 @@ error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied --> $DIR/defaults-unsound-62211-2.rs:21:18 | LL | trait UncheckedCopy: Sized { - | -------------------------- required by `UncheckedCopy` + | --------------------------- help: consider further restricting `Self`: `+ std::marker::Copy` + | | + | required by `UncheckedCopy` ... LL | type Output: Copy | ^^^^ the trait `std::marker::Copy` is not implemented for `Self` @@ -11,7 +13,9 @@ error[E0277]: cannot add-assign `&'static str` to `Self` --> $DIR/defaults-unsound-62211-2.rs:25:7 | LL | trait UncheckedCopy: Sized { - | -------------------------- required by `UncheckedCopy` + | --------------------------- help: consider further restricting `Self`: `+ std::ops::AddAssign<&'static str>` + | | + | required by `UncheckedCopy` ... LL | + AddAssign<&'static str> | ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str` @@ -22,7 +26,9 @@ error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied --> $DIR/defaults-unsound-62211-2.rs:23:7 | LL | trait UncheckedCopy: Sized { - | -------------------------- required by `UncheckedCopy` + | --------------------------- help: consider further restricting `Self`: `+ std::ops::Deref` + | | + | required by `UncheckedCopy` ... LL | + Deref | ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self` @@ -31,7 +37,9 @@ error[E0277]: `Self` doesn't implement `std::fmt::Display` --> $DIR/defaults-unsound-62211-2.rs:28:7 | LL | trait UncheckedCopy: Sized { - | -------------------------- required by `UncheckedCopy` + | --------------------------- help: consider further restricting `Self`: `+ std::fmt::Display` + | | + | required by `UncheckedCopy` ... LL | + Display = Self; | ^^^^^^^ `Self` cannot be formatted with the default formatter diff --git a/src/test/ui/associated-types/issue-63593.stderr b/src/test/ui/associated-types/issue-63593.stderr index c27800f5a3fb1..42529fd2b220e 100644 --- a/src/test/ui/associated-types/issue-63593.stderr +++ b/src/test/ui/associated-types/issue-63593.stderr @@ -2,7 +2,9 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation --> $DIR/issue-63593.rs:9:5 | LL | trait MyTrait { - | ------------- required by `MyTrait` + | -------------- help: consider further restricting `Self`: `: std::marker::Sized` + | | + | required by `MyTrait` LL | type This = Self; | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | diff --git a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.rs b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.rs new file mode 100644 index 0000000000000..0474bf0a33944 --- /dev/null +++ b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.rs @@ -0,0 +1,11 @@ +use std::ops::{Add, Sub, Mul, Div}; + +trait ArithmeticOps: Add + Sub + Mul + Div {} +//~^ ERROR the size for values of type `Self` cannot be known at compilation time + +impl ArithmeticOps for T where T: Add + Sub + Mul + Div { + // Nothing to implement, since T already supports the other traits. + // It has the functions it needs already +} + +fn main() {} diff --git a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr new file mode 100644 index 0000000000000..707bcf5e2feb7 --- /dev/null +++ b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr @@ -0,0 +1,17 @@ +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/trait-with-supertraits-needing-sized-self.rs:3:22 + | +LL | trait ArithmeticOps: Add + Sub + Mul + Div {} + | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - help: consider further restricting `Self`: `+ std::marker::Sized` + | + ::: $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | pub trait Add { + | --- required by this bound in `std::ops::Add` + | + = help: the trait `std::marker::Sized` is not implemented for `Self` + = note: to learn more, visit + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`.