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:
Aaron Hill 2021-08-28 18:45:37 -05:00
parent 3e8f32e1c5
commit 93ab12eeab
No known key found for this signature in database
GPG Key ID: B4087E510E98B164
16 changed files with 194 additions and 82 deletions

View File

@ -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,
)
},
)
}
}

View File

@ -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

View File

@ -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) {

View File

@ -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>,
}

View File

@ -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));
}
}

View File

@ -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(),
);

View File

@ -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>> {

View File

@ -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.

View File

@ -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;

View File

@ -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));
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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