Improve cause information for NLL higher-ranked errors
This PR has several interconnected pieces: 1. In some of the NLL region error code, we now pass around an `ObligationCause`, instead of just a plain `Span`. This gets forwarded into `fulfill_cx.register_predicate_obligation` during error reporting. 2. The general InferCtxt error reporting code is extended to handle `ObligationCauseCode::BindingObligation` 3. A new enum variant `ConstraintCategory::Predicate` is added. We try to avoid using this as the 'best blame constraint' - instead, we use it to enhance the `ObligationCause` of the `BlameConstraint` that we do end up choosing. As a result, several NLL error messages now contain the same "the lifetime requirement is introduced here" message as non-NLL errors. Having an `ObligationCause` available will likely prove useful for future improvements to NLL error messages.
This commit is contained in:
parent
3e8f32e1c5
commit
93ab12eeab
@ -9,7 +9,7 @@
|
||||
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<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>>;
|
||||
@ -140,7 +139,7 @@ fn report_error(
|
||||
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 @@ fn report_error(
|
||||
{
|
||||
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 @@ fn report_error(
|
||||
|
||||
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 @@ fn base_universe(&self) -> ty::UniverseIndex {
|
||||
fn nice_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::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 = <dyn TraitEngine<'_>>::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 @@ fn base_universe(&self) -> ty::UniverseIndex {
|
||||
fn nice_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
|
||||
tcx.infer_ctxt().enter_with_canonical(
|
||||
cause.span,
|
||||
&self.canonical_query,
|
||||
|ref infcx, key, _| {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
|
||||
|
||||
let mut selcx = SelectionContext::new(infcx);
|
||||
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);
|
||||
// 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)
|
||||
})
|
||||
try_extract_error_from_fulfill_cx(
|
||||
fulfill_cx,
|
||||
infcx,
|
||||
placeholder_region,
|
||||
error_region,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,15 +305,25 @@ fn base_universe(&self) -> ty::UniverseIndex {
|
||||
fn nice_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::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 = <dyn TraitEngine<'_>>::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,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -300,7 +300,7 @@ fn free_region_constraint_info(
|
||||
borrow_region: RegionVid,
|
||||
outlived_region: RegionVid,
|
||||
) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
|
||||
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 @@ fn free_region_constraint_info(
|
||||
|
||||
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
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
use crate::borrowck_errors;
|
||||
|
||||
use super::{OutlivesSuggestionBuilder, RegionName};
|
||||
use crate::region_infer::BlameConstraint;
|
||||
use crate::{
|
||||
nll::ConstraintDescription,
|
||||
@ -21,8 +22,6 @@
|
||||
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 @@ fn description(&self) -> &'static str {
|
||||
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 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'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 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'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 @@ pub(crate) fn report_region_error(
|
||||
) {
|
||||
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 @@ pub(crate) fn report_region_error(
|
||||
fr_is_local,
|
||||
outlived_fr_is_local,
|
||||
category,
|
||||
span,
|
||||
span: cause.span,
|
||||
};
|
||||
|
||||
let mut diag = match (category, fr_is_local, outlived_fr_is_local) {
|
||||
|
@ -6,6 +6,7 @@
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::graph::scc::Sccs;
|
||||
use rustc_hir::def_id::DefId;
|
||||
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 @@
|
||||
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 @@ fn try_propagate_universal_region_error(
|
||||
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 @@ fn check_member_constraints(
|
||||
return BlameConstraint {
|
||||
category: constraint.category,
|
||||
from_closure: false,
|
||||
span,
|
||||
cause: ObligationCause::dummy_with_span(span),
|
||||
variance_info: constraint.variance_info,
|
||||
};
|
||||
}
|
||||
@ -1751,30 +1754,30 @@ fn check_member_constraints(
|
||||
.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,21 @@ fn check_member_constraints(
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
// 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(def_id, predicate_span) = constraint.category {
|
||||
Some(ObligationCauseCode::BindingObligation(def_id, predicate_span))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| ObligationCauseCode::MiscObligation);
|
||||
|
||||
// Classify each of the constraints along the path.
|
||||
let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
|
||||
.iter()
|
||||
@ -2000,7 +2018,11 @@ fn check_member_constraints(
|
||||
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 +2105,8 @@ fn check_member_constraints(
|
||||
ConstraintCategory::OpaqueType
|
||||
| ConstraintCategory::Boring
|
||||
| ConstraintCategory::BoringNoLocation
|
||||
| ConstraintCategory::Internal => false,
|
||||
| ConstraintCategory::Internal
|
||||
| ConstraintCategory::Predicate(_, _) => false,
|
||||
ConstraintCategory::TypeAnnotation
|
||||
| ConstraintCategory::Return(_)
|
||||
| ConstraintCategory::Yield => true,
|
||||
@ -2094,7 +2117,8 @@ fn check_member_constraints(
|
||||
ConstraintCategory::OpaqueType
|
||||
| ConstraintCategory::Boring
|
||||
| ConstraintCategory::BoringNoLocation
|
||||
| ConstraintCategory::Internal => false,
|
||||
| ConstraintCategory::Internal
|
||||
| ConstraintCategory::Predicate(_, _) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
@ -2249,6 +2273,6 @@ fn apply_requirements(
|
||||
pub struct BlameConstraint<'tcx> {
|
||||
pub category: ConstraintCategory,
|
||||
pub from_closure: bool,
|
||||
pub span: Span,
|
||||
pub cause: ObligationCause<'tcx>,
|
||||
pub variance_info: ty::VarianceDiagInfo<'tcx>,
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
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,17 @@ pub(super) fn prove_trait_ref(
|
||||
|
||||
pub(super) fn normalize_and_prove_instantiated_predicates(
|
||||
&mut self,
|
||||
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(def_id, span));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
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 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
|
||||
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 @@ fn prove_aggregate_predicates(
|
||||
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 @@ fn prove_aggregate_predicates(
|
||||
// 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(),
|
||||
);
|
||||
|
@ -609,6 +609,7 @@ fn note_error_origin(
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
|
||||
terr: &TypeError<'tcx>,
|
||||
) {
|
||||
match cause.code {
|
||||
ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
|
||||
@ -785,7 +786,15 @@ fn note_error_origin(
|
||||
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 @@ enum Mismatch<'a> {
|
||||
|
||||
// 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<Ty<'tcx>> {
|
||||
|
@ -338,6 +338,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(DefId, 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.
|
||||
|
@ -19,7 +19,7 @@
|
||||
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;
|
||||
|
||||
|
@ -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<Span>,
|
||||
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));
|
||||
}
|
||||
|
@ -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<Image=U>
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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<T, S>(data: &[T], key: impl Fn(&T) -> S) {
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: implementation of `FnOnce` is not general enough
|
||||
--> $DIR/issue_74400.rs:12:5
|
||||
|
@ -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: Foo>(_: T) {}
|
||||
| ^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user