diff options
| author | Jack Huey <31162821+jackh726@users.noreply.github.com> | 2022-01-08 23:30:19 -0500 |
|---|---|---|
| committer | Jack Huey <31162821+jackh726@users.noreply.github.com> | 2022-02-17 14:09:21 -0500 |
| commit | 3d19c8defd776eb7e9e113cf49c3e1d2f51e408e (patch) | |
| tree | 1a033554d1cbe17bd8dda1f54886017acd4b3548 /compiler | |
| parent | 30b3f35c420694a4f24e5a4df00f06073f4f3a37 (diff) | |
Suggest copying trait associated type bounds on lifetime error
Diffstat (limited to 'compiler')
6 files changed, 86 insertions, 3 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index 8512597cb91..f44e6e04346 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -64,7 +64,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { .or_else(|| self.try_report_mismatched_static_lifetime()) } - pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> { + pub(super) fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> { match (&self.error, self.regions) { (Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), *sub, *sup)), (Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => { diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 8e5efa12ac6..8671ecba6e9 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -102,6 +102,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "...so that the definition in impl matches the definition from the trait", ); } + infer::CheckAssociatedTypeBounds { ref parent, .. } => { + self.note_region_origin(err, &parent); + } } } @@ -345,6 +348,55 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_item_def_id, &format!("`{}: {}`", sup, sub), ), + infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { + let mut err = self.report_concrete_failure(*parent, sub, sup); + + let trait_item_span = self.tcx.def_span(trait_item_def_id); + let item_name = self.tcx.item_name(impl_item_def_id); + err.span_label( + trait_item_span, + format!("definition of `{}` from trait", item_name), + ); + + let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id); + let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id); + + let impl_predicates: rustc_data_structures::stable_set::FxHashSet<_> = + impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect(); + let clauses: Vec<_> = trait_predicates + .predicates + .into_iter() + .filter(|&(pred, _)| !impl_predicates.contains(pred)) + .map(|(pred, _)| format!("{}", pred)) + .collect(); + + if !clauses.is_empty() { + let where_clause_span = self + .tcx + .hir() + .get_generics(impl_item_def_id.expect_local()) + .unwrap() + .where_clause + .tail_span_for_suggestion(); + + let suggestion = format!( + "{} {}", + if !impl_predicates.is_empty() { "," } else { " where" }, + clauses.join(", "), + ); + err.span_suggestion( + where_clause_span, + &format!( + "try copying {} from the trait", + if clauses.len() > 1 { "these clauses" } else { "this clause" } + ), + suggestion, + rustc_errors::Applicability::MaybeIncorrect, + ); + } + + err + } } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index f0a4ec81313..57ac98ca897 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -438,6 +438,13 @@ pub enum SubregionOrigin<'tcx> { /// Comparing the signature and requirements of an impl associated type /// against the containing trait CompareImplTypeObligation { span: Span, impl_item_def_id: DefId, trait_item_def_id: DefId }, + + /// Checking that the bounds of a trait's associated type hold for a given impl + CheckAssociatedTypeBounds { + parent: Box<SubregionOrigin<'tcx>>, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + }, } // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. @@ -1832,6 +1839,7 @@ impl<'tcx> SubregionOrigin<'tcx> { ReferenceOutlivesReferent(_, a) => a, CompareImplMethodObligation { span, .. } => span, CompareImplTypeObligation { span, .. } => span, + CheckAssociatedTypeBounds { ref parent, .. } => parent.span(), } } @@ -1862,6 +1870,15 @@ impl<'tcx> SubregionOrigin<'tcx> { trait_item_def_id, }, + traits::ObligationCauseCode::CheckAssociatedTypeBounds { + impl_item_def_id, + trait_item_def_id, + } => SubregionOrigin::CheckAssociatedTypeBounds { + impl_item_def_id, + trait_item_def_id, + parent: Box::new(default()), + }, + _ => default(), } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 1123cab8076..b54418e5201 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -285,6 +285,12 @@ pub enum ObligationCauseCode<'tcx> { trait_item_def_id: DefId, }, + /// Checking that the bounds of a trait's associated type hold for a given impl + CheckAssociatedTypeBounds { + impl_item_def_id: DefId, + trait_item_def_id: DefId, + }, + /// Checking that this expression can be assigned where it needs to be // FIXME(eddyb) #11161 is the original Expr required? ExprAssignable, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 40cb9647a35..6068b90aef8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1932,7 +1932,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::AwaitableExpr(_) | ObligationCauseCode::ForLoopIterator | ObligationCauseCode::QuestionMark - | ObligationCauseCode::LetElse => {} + | ObligationCauseCode::LetElse + | ObligationCauseCode::CheckAssociatedTypeBounds { .. } => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 457e9cf1ea5..38449c2a76a 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -1378,7 +1378,14 @@ pub fn check_type_bounds<'tcx>( let mut selcx = traits::SelectionContext::new(&infcx); let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()); - let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id); + let normalize_cause = ObligationCause::new( + impl_ty_span, + impl_ty_hir_id, + ObligationCauseCode::CheckAssociatedTypeBounds { + impl_item_def_id: impl_ty.def_id, + trait_item_def_id: trait_ty.def_id, + }, + ); let mk_cause = |span: Span| { let code = if span.is_dummy() { traits::MiscObligation |
