diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 76e779bfec608..366ade1a71388 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op; use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _}; -use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span}; +use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; use std::fmt; use std::rc::Rc; @@ -45,13 +45,12 @@ impl UniverseInfo<'tcx> { mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, placeholder: ty::PlaceholderRegion, error_element: RegionElement, - span: Span, + cause: ObligationCause<'tcx>, ) { match self.0 { UniverseInfoInner::RelateTys { expected, found } => { - let body_id = mbcx.infcx.tcx.hir().local_def_id_to_hir_id(mbcx.mir_def_id()); let err = mbcx.infcx.report_mismatched_types( - &ObligationCause::misc(span, body_id), + &cause, expected, found, TypeError::RegionsPlaceholderMismatch, @@ -59,7 +58,7 @@ impl UniverseInfo<'tcx> { err.buffer(&mut mbcx.errors_buffer); } UniverseInfoInner::TypeOp(ref type_op_info) => { - type_op_info.report_error(mbcx, placeholder, error_element, span); + type_op_info.report_error(mbcx, placeholder, error_element, cause); } UniverseInfoInner::Other => { // FIXME: This error message isn't great, but it doesn't show @@ -68,7 +67,7 @@ impl UniverseInfo<'tcx> { mbcx.infcx .tcx .sess - .struct_span_err(span, "higher-ranked subtype error") + .struct_span_err(cause.span, "higher-ranked subtype error") .buffer(&mut mbcx.errors_buffer); } } @@ -130,7 +129,7 @@ trait TypeOpInfo<'tcx> { fn nice_error( &self, tcx: TyCtxt<'tcx>, - span: Span, + cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option>; @@ -140,7 +139,7 @@ trait TypeOpInfo<'tcx> { mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, placeholder: ty::PlaceholderRegion, error_element: RegionElement, - span: Span, + cause: ObligationCause<'tcx>, ) { let tcx = mbcx.infcx.tcx; let base_universe = self.base_universe(); @@ -150,7 +149,7 @@ trait TypeOpInfo<'tcx> { { adjusted } else { - self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer); + self.fallback_error(tcx, cause.span).buffer(&mut mbcx.errors_buffer); return; }; @@ -175,7 +174,8 @@ trait TypeOpInfo<'tcx> { debug!(?placeholder_region); - let nice_error = self.nice_error(tcx, span, placeholder_region, error_region); + let span = cause.span; + let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region); if let Some(nice_error) = nice_error { nice_error.buffer(&mut mbcx.errors_buffer); @@ -205,15 +205,24 @@ impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> { fn nice_error( &self, tcx: TyCtxt<'tcx>, - span: Span, + cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); - type_op_prove_predicate_with_span(infcx, &mut *fulfill_cx, key, Some(span)); - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) - }) + tcx.infer_ctxt().enter_with_canonical( + cause.span, + &self.canonical_query, + |ref infcx, key, _| { + let mut fulfill_cx = >::new(tcx); + type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause); + try_extract_error_from_fulfill_cx( + fulfill_cx, + infcx, + placeholder_region, + error_region, + ) + }, + ) } } @@ -239,32 +248,41 @@ where fn nice_error( &self, tcx: TyCtxt<'tcx>, - span: Span, + cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); - - let mut selcx = SelectionContext::new(infcx); - - // FIXME(lqd): Unify and de-duplicate the following with the actual - // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the - // `ObligationCause`. The normalization results are currently different between - // `AtExt::normalize` used in the query and `normalize` called below: the former fails - // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check - // after #85499 lands to see if its fixes have erased this difference. - let (param_env, value) = key.into_parts(); - let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize( - &mut selcx, - param_env, - ObligationCause::dummy_with_span(span), - value.value, - ); - fulfill_cx.register_predicate_obligations(infcx, obligations); - - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) - }) + tcx.infer_ctxt().enter_with_canonical( + cause.span, + &self.canonical_query, + |ref infcx, key, _| { + let mut fulfill_cx = >::new(tcx); + + let mut selcx = SelectionContext::new(infcx); + + // FIXME(lqd): Unify and de-duplicate the following with the actual + // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the + // `ObligationCause`. The normalization results are currently different between + // `AtExt::normalize` used in the query and `normalize` called below: the former fails + // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check + // after #85499 lands to see if its fixes have erased this difference. + let (param_env, value) = key.into_parts(); + let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize( + &mut selcx, + param_env, + cause, + value.value, + ); + fulfill_cx.register_predicate_obligations(infcx, obligations); + + try_extract_error_from_fulfill_cx( + fulfill_cx, + infcx, + placeholder_region, + error_region, + ) + }, + ) } } @@ -287,15 +305,25 @@ impl TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { fn nice_error( &self, tcx: TyCtxt<'tcx>, - span: Span, + cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); - type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(span)).ok()?; - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) - }) + tcx.infer_ctxt().enter_with_canonical( + cause.span, + &self.canonical_query, + |ref infcx, key, _| { + let mut fulfill_cx = >::new(tcx); + type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)) + .ok()?; + try_extract_error_from_fulfill_cx( + fulfill_cx, + infcx, + placeholder_region, + error_region, + ) + }, + ) } } diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 2d12a682e7ae6..d5de0801ac443 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -300,7 +300,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_region: RegionVid, outlived_region: RegionVid, ) -> (ConstraintCategory, bool, Span, Option) { - let BlameConstraint { category, from_closure, span, variance_info: _ } = + let BlameConstraint { category, from_closure, cause, variance_info: _ } = self.regioncx.best_blame_constraint( &self.body, borrow_region, @@ -310,7 +310,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let outlived_fr_name = self.give_region_a_name(outlived_region); - (category, from_closure, span, outlived_fr_name) + (category, from_closure, cause.span, outlived_fr_name) } /// Returns structured explanation for *why* the borrow contains the diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 0761d63c66540..d05cfebc5f02e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -13,6 +13,7 @@ use rustc_span::{BytePos, Span}; use crate::borrowck_errors; +use super::{OutlivesSuggestionBuilder, RegionName}; use crate::region_infer::BlameConstraint; use crate::{ nll::ConstraintDescription, @@ -21,8 +22,6 @@ use crate::{ MirBorrowckCtxt, }; -use super::{OutlivesSuggestionBuilder, RegionName}; - impl ConstraintDescription for ConstraintCategory { fn description(&self) -> &'static str { // Must end with a space. Allows for empty names to be provided. @@ -41,7 +40,8 @@ impl ConstraintDescription for ConstraintCategory { ConstraintCategory::OpaqueType => "opaque type ", ConstraintCategory::ClosureUpvar(_) => "closure capture ", ConstraintCategory::Usage => "this usage ", - ConstraintCategory::Boring + ConstraintCategory::Predicate(_) + | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => "", } @@ -217,7 +217,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let error_vid = self.regioncx.region_from_element(longer_fr, &error_element); // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. - let (_, span) = self.regioncx.find_outlives_blame_span( + let (_, cause) = self.regioncx.find_outlives_blame_span( &self.body, longer_fr, NllRegionVariableOrigin::Placeholder(placeholder), @@ -227,7 +227,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let universe = placeholder.universe; let universe_info = self.regioncx.universe_info(universe); - universe_info.report_error(self, placeholder, error_element, span); + universe_info.report_error(self, placeholder, error_element, cause); } RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => { @@ -275,15 +275,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ) { debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); - let BlameConstraint { category, span, variance_info, from_closure: _ } = + let BlameConstraint { category, cause, variance_info, from_closure: _ } = self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| { self.regioncx.provides_universal_region(r, fr, outlived_fr) }); - debug!("report_region_error: category={:?} {:?} {:?}", category, span, variance_info); + debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info); // Check if we can use one of the "nice region errors". if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { - let nice = NiceRegionError::new_from_span(self.infcx, span, o, f); + let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f); if let Some(diag) = nice.try_report_from_nll() { diag.buffer(&mut self.errors_buffer); return; @@ -306,7 +306,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fr_is_local, outlived_fr_is_local, category, - span, + span: cause.span, }; let mut diag = match (category, fr_is_local, outlived_fr_is_local) { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 128faab8d722e..917d69a5c8664 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -5,7 +5,8 @@ use rustc_data_structures::binary_search_util; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::scc::Sccs; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; +use rustc_hir::CRATE_HIR_ID; use rustc_index::vec::IndexVec; use rustc_infer::infer::canonical::QueryOutlivesConstraint; use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound}; @@ -14,6 +15,8 @@ use rustc_middle::mir::{ Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint, }; +use rustc_middle::traits::ObligationCause; +use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; @@ -1596,7 +1599,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { propagated_outlives_requirements.push(ClosureOutlivesRequirement { subject: ClosureOutlivesSubject::Region(fr_minus), outlived_free_region: fr, - blame_span: blame_span_category.1, + blame_span: blame_span_category.1.span, category: blame_span_category.0, }); } @@ -1738,7 +1741,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { return BlameConstraint { category: constraint.category, from_closure: false, - span, + cause: ObligationCause::dummy_with_span(span), variance_info: constraint.variance_info, }; } @@ -1751,30 +1754,30 @@ impl<'tcx> RegionInferenceContext<'tcx> { .map(|&(category, span)| BlameConstraint { category, from_closure: true, - span: span, + cause: ObligationCause::dummy_with_span(span), variance_info: constraint.variance_info, }) .unwrap_or(BlameConstraint { category: constraint.category, from_closure: false, - span: body.source_info(loc).span, + cause: ObligationCause::dummy_with_span(body.source_info(loc).span), variance_info: constraint.variance_info, }) } - /// Finds a good span to blame for the fact that `fr1` outlives `fr2`. + /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`. crate fn find_outlives_blame_span( &self, body: &Body<'tcx>, fr1: RegionVid, fr1_origin: NllRegionVariableOrigin, fr2: RegionVid, - ) -> (ConstraintCategory, Span) { - let BlameConstraint { category, span, .. } = + ) -> (ConstraintCategory, ObligationCause<'tcx>) { + let BlameConstraint { category, cause, .. } = self.best_blame_constraint(body, fr1, fr1_origin, |r| { self.provides_universal_region(r, fr1, fr2) }); - (category, span) + (category, cause) } /// Walks the graph of constraints (where `'a: 'b` is considered @@ -1990,6 +1993,27 @@ impl<'tcx> RegionInferenceContext<'tcx> { .collect::>() ); + // We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint. + // Instead, we use it to produce an improved `ObligationCauseCode`. + // FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate` + // constraints. Currently, we just pick the first one. + let cause_code = path + .iter() + .find_map(|constraint| { + if let ConstraintCategory::Predicate(predicate_span) = constraint.category { + // We currentl'y doesn't store the `DefId` in the `ConstraintCategory` + // for perforamnce reasons. The error reporting code used by NLL only + // uses the span, so this doesn't cause any problems at the moment. + Some(ObligationCauseCode::BindingObligation( + CRATE_DEF_ID.to_def_id(), + predicate_span, + )) + } else { + None + } + }) + .unwrap_or_else(|| ObligationCauseCode::MiscObligation); + // Classify each of the constraints along the path. let mut categorized_path: Vec> = path .iter() @@ -2000,7 +2024,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { BlameConstraint { category: constraint.category, from_closure: false, - span: constraint.locations.span(body), + cause: ObligationCause::new( + constraint.locations.span(body), + CRATE_HIR_ID, + cause_code.clone(), + ), variance_info: constraint.variance_info, } } @@ -2083,7 +2111,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { ConstraintCategory::OpaqueType | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation - | ConstraintCategory::Internal => false, + | ConstraintCategory::Internal + | ConstraintCategory::Predicate(_) => false, ConstraintCategory::TypeAnnotation | ConstraintCategory::Return(_) | ConstraintCategory::Yield => true, @@ -2094,7 +2123,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { ConstraintCategory::OpaqueType | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation - | ConstraintCategory::Internal => false, + | ConstraintCategory::Internal + | ConstraintCategory::Predicate(_) => false, _ => true, } } @@ -2249,6 +2279,6 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx pub struct BlameConstraint<'tcx> { pub category: ConstraintCategory, pub from_closure: bool, - pub span: Span, + pub cause: ObligationCause<'tcx>, pub variance_info: ty::VarianceDiagInfo<'tcx>, } diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index e776198822281..df28fb6e28e06 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -4,6 +4,7 @@ use rustc_infer::infer::canonical::Canonical; use rustc_infer::traits::query::NoSolution; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::{self, ToPredicate, TypeFoldable}; +use rustc_span::def_id::DefId; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput}; use rustc_trait_selection::traits::query::Fallible; @@ -100,12 +101,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { pub(super) fn normalize_and_prove_instantiated_predicates( &mut self, + // Keep this parameter for now, in case we start using + // it in `ConstraintCategory` at some point. + _def_id: DefId, instantiated_predicates: ty::InstantiatedPredicates<'tcx>, locations: Locations, ) { - for predicate in instantiated_predicates.predicates { + for (predicate, span) in instantiated_predicates + .predicates + .into_iter() + .zip(instantiated_predicates.spans.into_iter()) + { let predicate = self.normalize(predicate, locations); - self.prove_predicate(predicate, locations, ConstraintCategory::Boring); + self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span)); } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index cf50fa38687b5..4bbeed39e45ae 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -32,6 +32,7 @@ use rustc_middle::ty::{ self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness, }; +use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_trait_selection::infer::InferCtxtExt as _; @@ -449,6 +450,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() { let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); self.cx.normalize_and_prove_instantiated_predicates( + def_id, instantiated_predicates, location.to_locations(), ); @@ -2572,9 +2574,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { aggregate_kind, location ); - let instantiated_predicates = match aggregate_kind { + let (def_id, instantiated_predicates) = match aggregate_kind { AggregateKind::Adt(def, _, substs, _, _) => { - tcx.predicates_of(def.did).instantiate(tcx, substs) + (def.did, tcx.predicates_of(def.did).instantiate(tcx, substs)) } // For closures, we have some **extra requirements** we @@ -2599,13 +2601,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // clauses on the struct. AggregateKind::Closure(def_id, substs) | AggregateKind::Generator(def_id, substs, _) => { - self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location) + (*def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location)) } - AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(), + AggregateKind::Array(_) | AggregateKind::Tuple => { + (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty()) + } }; self.normalize_and_prove_instantiated_predicates( + def_id, instantiated_predicates, location.to_locations(), ); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index d9b7022f03ac1..45dd8868d6cca 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -609,6 +609,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>, exp_found: Option>>, + terr: &TypeError<'tcx>, ) { match cause.code { ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { @@ -785,7 +786,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.help("try adding a diverging expression, such as `return` or `panic!(..)`"); err.help("...or use `match` instead of `let...else`"); } - _ => (), + _ => { + if let ObligationCauseCode::BindingObligation(_, binding_span) = + cause.code.peel_derives() + { + if matches!(terr, TypeError::RegionsPlaceholderMismatch) { + err.span_note(*binding_span, "the lifetime requirement is introduced here"); + } + } + } } } @@ -1724,7 +1733,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // It reads better to have the error origin as the final // thing. - self.note_error_origin(diag, cause, exp_found); + self.note_error_origin(diag, cause, exp_found, terr); } pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option> { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index b003a504691bb..d5541d7890c77 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -309,6 +309,9 @@ pub struct ClosureOutlivesRequirement<'tcx> { pub category: ConstraintCategory, } +// Make sure this enum doesn't unintentionally grow +rustc_data_structures::static_assert_size!(ConstraintCategory, 12); + /// Outlives-constraints can be categorized to determine whether and why they /// are interesting (for error reporting). Order of variants indicates sort /// order of the category, thereby influencing diagnostic output. @@ -338,6 +341,11 @@ pub enum ConstraintCategory { OpaqueType, ClosureUpvar(hir::HirId), + /// A constraint from a user-written predicate + /// with the provided span, written on the item + /// with the given `DefId` + Predicate(Span), + /// A "boring" constraint (caused by the given location) is one that /// the user probably doesn't want to see described in diagnostics, /// because it is kind of an artifact of the type system setup. diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 48c46c3069328..8612499623be6 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -19,7 +19,7 @@ mod normalize_erasing_regions; mod normalize_projection_ty; mod type_op; -pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span}; +pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; use rustc_middle::ty::query::Providers; diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index f954cab240ca2..cc0b7d5817b43 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -257,7 +257,7 @@ fn type_op_prove_predicate<'tcx>( canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { - type_op_prove_predicate_with_span(infcx, fulfill_cx, key, None); + type_op_prove_predicate_with_cause(infcx, fulfill_cx, key, ObligationCause::dummy()); Ok(()) }) } @@ -265,17 +265,12 @@ fn type_op_prove_predicate<'tcx>( /// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors, /// this query can be re-run to better track the span of the obligation cause, and improve the error /// message. Do not call directly unless you're in that very specific context. -pub fn type_op_prove_predicate_with_span<'a, 'tcx: 'a>( +pub fn type_op_prove_predicate_with_cause<'a, 'tcx: 'a>( infcx: &'a InferCtxt<'a, 'tcx>, fulfill_cx: &'a mut dyn TraitEngine<'tcx>, key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>, - span: Option, + cause: ObligationCause<'tcx>, ) { - let cause = if let Some(span) = span { - ObligationCause::dummy_with_span(span) - } else { - ObligationCause::dummy() - }; let (param_env, ProvePredicate { predicate }) = key.into_parts(); fulfill_cx.register_predicate_obligation(infcx, Obligation::new(cause, param_env, predicate)); } diff --git a/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr index e3bd0c2276e48..de254b7a1636c 100644 --- a/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr +++ b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr @@ -6,6 +6,11 @@ LL | foo(()); | = note: expected reference `&'a ()` found reference `&()` +note: the lifetime requirement is introduced here + --> $DIR/higher-ranked-projection.rs:15:33 + | +LL | where for<'a> &'a T: Mirror + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/generator/resume-arg-late-bound.nll.stderr b/src/test/ui/generator/resume-arg-late-bound.nll.stderr index 25bc6afc550b3..b5144c607a880 100644 --- a/src/test/ui/generator/resume-arg-late-bound.nll.stderr +++ b/src/test/ui/generator/resume-arg-late-bound.nll.stderr @@ -6,6 +6,11 @@ LL | test(gen); | = note: expected type `for<'a> Generator<&'a mut bool>` found type `Generator<&mut bool>` +note: the lifetime requirement is introduced here + --> $DIR/resume-arg-late-bound.rs:8:17 + | +LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/lifetimes/issue-79187-2.nll.stderr b/src/test/ui/lifetimes/issue-79187-2.nll.stderr index 907b43d6762e9..04d9b64d64fdd 100644 --- a/src/test/ui/lifetimes/issue-79187-2.nll.stderr +++ b/src/test/ui/lifetimes/issue-79187-2.nll.stderr @@ -38,6 +38,11 @@ note: this closure does not fulfill the lifetime requirements | LL | take_foo(|a| a); | ^^^^^ +note: the lifetime requirement is introduced here + --> $DIR/issue-79187-2.rs:5:21 + | +LL | fn take_foo(_: impl Foo) {} + | ^^^ error[E0308]: mismatched types --> $DIR/issue-79187-2.rs:9:5 @@ -47,6 +52,11 @@ LL | take_foo(|a: &i32| a); | = note: expected reference `&i32` found reference `&i32` +note: the lifetime requirement is introduced here + --> $DIR/issue-79187-2.rs:5:21 + | +LL | fn take_foo(_: impl Foo) {} + | ^^^ error[E0308]: mismatched types --> $DIR/issue-79187-2.rs:10:5 @@ -56,6 +66,11 @@ LL | take_foo(|a: &i32| -> &i32 { a }); | = note: expected reference `&i32` found reference `&i32` +note: the lifetime requirement is introduced here + --> $DIR/issue-79187-2.rs:5:21 + | +LL | fn take_foo(_: impl Foo) {} + | ^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/lifetimes/issue-79187.nll.stderr b/src/test/ui/lifetimes/issue-79187.nll.stderr index 725b132e83a12..3a993e88d8a92 100644 --- a/src/test/ui/lifetimes/issue-79187.nll.stderr +++ b/src/test/ui/lifetimes/issue-79187.nll.stderr @@ -11,6 +11,11 @@ note: this closure does not fulfill the lifetime requirements | LL | let f = |_| (); | ^^^^^^ +note: the lifetime requirement is introduced here + --> $DIR/issue-79187.rs:1:18 + | +LL | fn thing(x: impl FnOnce(&u32)) {} + | ^^^^^^^^^^^^ error: implementation of `FnOnce` is not general enough --> $DIR/issue-79187.rs:5:5 diff --git a/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr index 5a1294f948f1c..5509226cb1cdd 100644 --- a/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr @@ -14,6 +14,11 @@ LL | f(data, identity) | = note: expected type `for<'r> Fn<(&'r T,)>` found type `Fn<(&T,)>` +note: the lifetime requirement is introduced here + --> $DIR/issue_74400.rs:8:34 + | +LL | fn f(data: &[T], key: impl Fn(&T) -> S) { + | ^^^^^^^^^^^ error: implementation of `FnOnce` is not general enough --> $DIR/issue_74400.rs:12:5 diff --git a/src/test/ui/mismatched_types/closure-mismatch.nll.stderr b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr index f29126e6afc76..bd36fab92886d 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.nll.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr @@ -20,6 +20,11 @@ note: this closure does not fulfill the lifetime requirements | LL | baz(|_| ()); | ^^^^^^ +note: the lifetime requirement is introduced here + --> $DIR/closure-mismatch.rs:5:11 + | +LL | fn baz(_: T) {} + | ^^^ error: aborting due to 2 previous errors