From 2b35247d7a80e689dee6363730807687fdf42b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 16 Feb 2020 17:59:29 -0800 Subject: [PATCH] Modify wording --- .../trait_impl_difference.rs | 83 ++++++++++++++++--- .../mismatched_trait_impl-2.stderr | 4 +- .../mismatched_trait_impl.stderr | 4 +- ...ime-mismatch-between-trait-and-impl.stderr | 4 +- ...t-param-without-lifetime-constraint.stderr | 9 +- 5 files changed, 84 insertions(+), 20 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 4019708df98..ca925233333 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -2,15 +2,17 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::infer::{Subtype, ValuePairs}; +use crate::infer::{Subtype, TyCtxtInferExt, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::ErrorReported; +use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::Visitor; use rustc_hir::ItemKind; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -59,8 +61,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { .tcx() .sess .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature"); - err.span_label(sp, &format!("found {:?}", found)); - err.span_label(trait_sp, &format!("expected {:?}", expected)); + err.span_label(sp, &format!("found `{:?}`", found)); + err.span_label(trait_sp, &format!("expected `{:?}`", expected)); let trait_fn_sig = tcx.fn_sig(trait_def_id); // Check the `trait`'s method's output to look for type parameters that might have @@ -73,7 +75,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { struct AssocTypeFinder(FxIndexSet); impl<'tcx> ty::fold::TypeVisitor<'tcx> for AssocTypeFinder { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - debug!("assoc type finder ty {:?} {:?}", ty, ty.kind); if let ty::Param(param) = ty.kind { self.0.insert(param); } @@ -86,18 +87,40 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let parent_id = tcx.hir().get_parent_item(id); let trait_item = tcx.hir().expect_item(parent_id); if let ItemKind::Trait(_, _, generics, _, _) = &trait_item.kind { - for param_ty in visitor.0 { + for param_ty in &visitor.0 { if let Some(generic) = generics.get_named(param_ty.name) { - err.span_label(generic.span, &format!( - "for `impl` items to implement the method, this type parameter might \ - need a lifetime restriction like `{}: 'a`", - param_ty.name, - )); + err.span_label( + generic.span, + "this type parameter might not have a lifetime compatible with the \ + `impl`", + ); } } } } + // Get the span of all the used type parameters in the method. + let assoc_item = self.tcx().associated_item(trait_def_id); + let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] }; + match assoc_item.kind { + ty::AssocKind::Method => { + let hir = self.tcx().hir(); + if let Some(hir_id) = hir.as_local_hir_id(assoc_item.def_id) { + if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) { + visitor.visit_fn_decl(decl); + } + } + } + _ => {} + } + for span in visitor.types { + err.span_label( + span, + "you might want to borrow this type parameter in the trait to make it match the \ + `impl`", + ); + } + if let Some((expected, found)) = tcx .infer_ctxt() .enter(|infcx| infcx.expected_found_str_ty(&ExpectedFound { expected, found })) @@ -116,3 +139,41 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.emit(); } } + +struct TypeParamSpanVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + types: Vec, +} + +impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { + type Map = hir::intravisit::Map<'tcx>; + + fn nested_visit_map<'this>( + &'this mut self, + ) -> hir::intravisit::NestedVisitorMap<'this, Self::Map> { + hir::intravisit::NestedVisitorMap::OnlyBodies(&self.tcx.hir()) + } + + fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { + match arg.kind { + hir::TyKind::Slice(_) | hir::TyKind::Tup(_) | hir::TyKind::Array(..) => { + hir::intravisit::walk_ty(self, arg); + } + hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments { + [segment] + if segment + .res + .map(|res| match res { + hir::def::Res::Def(hir::def::DefKind::TyParam, _) => true, + _ => false, + }) + .unwrap_or(false) => + { + self.types.push(path.span); + } + _ => {} + }, + _ => {} + } + } +} diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr index 05413c3a292..61a8674a231 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -2,12 +2,12 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/mismatched_trait_impl-2.rs:8:5 | LL | fn deref(&self) -> &dyn Trait { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Struct) -> &dyn Trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Struct) -> &dyn Trait` | ::: $SRC_DIR/libcore/ops/deref.rs:LL:COL | LL | fn deref(&self) -> &Self::Target; - | --------------------------------- expected fn(&Struct) -> &(dyn Trait + 'static) + | --------------------------------- expected `fn(&Struct) -> &(dyn Trait + 'static)` | = note: expected `fn(&Struct) -> &(dyn Trait + 'static)` found `fn(&Struct) -> &dyn Trait` diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index 4dbd4ac6a85..ca610291455 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -2,10 +2,10 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/mismatched_trait_impl.rs:9:5 | LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32; - | ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32 + | ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32` ... LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32` | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr index 0e56473c5b6..53f6aae5ff6 100644 --- a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr +++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr @@ -2,10 +2,10 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/lifetime-mismatch-between-trait-and-impl.rs:6:5 | LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32; - | ------------------------------------------- expected fn(&i32, &'a i32) -> &'a i32 + | ------------------------------------------- expected `fn(&i32, &'a i32) -> &'a i32` ... LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &i32) -> &i32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &i32) -> &i32` | = note: expected `fn(&i32, &'a i32) -> &'a i32` found `fn(&i32, &i32) -> &i32` diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr index 724062b1a58..a7be2d3365c 100644 --- a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr +++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr @@ -2,12 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/trait-param-without-lifetime-constraint.rs:14:5 | LL | pub trait HaveRelationship { - | -- for `impl` items to implement the method, this type parameter might need a lifetime restriction like `To: 'a` + | -- this type parameter might not have a lifetime compatible with the `impl` LL | fn get_relation(&self) -> To; - | ----------------------------- expected fn(&Article) -> &ProofReader + | ----------------------------- + | | | + | | you might want to borrow this type parameter in the trait to make it match the `impl` + | expected `fn(&Article) -> &ProofReader` ... LL | fn get_relation(&self) -> &ProofReader { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Article) -> &ProofReader + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader` | = note: expected `fn(&Article) -> &ProofReader` found `fn(&Article) -> &ProofReader`