blob: b93b8dc03f8a4f6a2b8d38ee74e574e963a307ac [file] [log] [blame]
//! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate
//! to hold.
use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq};
use crate::errors::{
DoesNotOutliveStaticFromImpl, ImplicitStaticLifetimeSubdiag, MismatchedStaticLifetime,
};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::ObligationCauseCode;
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
use rustc_middle::ty::TypeVisitor;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
pub(super) fn try_report_mismatched_static_lifetime(&self) -> Option<ErrorGuaranteed> {
let error = self.error.as_ref()?;
debug!("try_report_mismatched_static_lifetime {:?}", error);
let RegionResolutionError::ConcreteFailure(origin, sub, sup) = error.clone() else {
return None;
};
if !sub.is_static() {
return None;
}
let SubregionOrigin::Subtype(box TypeTrace { ref cause, .. }) = origin else {
return None;
};
// If we added a "points at argument expression" obligation, we remove it here, we care
// about the original obligation only.
let code = match cause.code() {
ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code,
code => code,
};
let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else {
return None;
};
let (ObligationCauseCode::BindingObligation(_, binding_span)
| ObligationCauseCode::ExprBindingObligation(_, binding_span, ..)) = *parent.code()
else {
return None;
};
// FIXME: we should point at the lifetime
let multi_span: MultiSpan = vec![binding_span].into();
let multispan_subdiag = IntroducesStaticBecauseUnmetLifetimeReq {
unmet_requirements: multi_span,
binding_span,
};
let expl = note_and_explain::RegionExplanation::new(
self.tcx(),
sup,
Some(binding_span),
note_and_explain::PrefixKind::Empty,
note_and_explain::SuffixKind::Continues,
);
let mut impl_span = None;
let mut implicit_static_lifetimes = Vec::new();
if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
// If an impl is local, then maybe this isn't what they want. Try to
// be as helpful as possible with implicit lifetimes.
// First, let's get the hir self type of the impl
let hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, .. }),
..
}) = impl_node
else {
bug!("Node not an impl.");
};
// Next, let's figure out the set of trait objects with implicit static bounds
let ty = self.tcx().type_of(*impl_def_id).instantiate_identity();
let mut v = super::static_impl_trait::TraitObjectVisitor(FxIndexSet::default());
v.visit_ty(ty);
let mut traits = vec![];
for matching_def_id in v.0 {
let mut hir_v =
super::static_impl_trait::HirTraitObjectVisitor(&mut traits, matching_def_id);
hir_v.visit_ty(impl_self_ty);
}
if traits.is_empty() {
// If there are no trait object traits to point at, either because
// there aren't trait objects or because none are implicit, then just
// write a single note on the impl itself.
impl_span = Some(self.tcx().def_span(*impl_def_id));
} else {
// Otherwise, point at all implicit static lifetimes
for span in &traits {
implicit_static_lifetimes
.push(ImplicitStaticLifetimeSubdiag::Note { span: *span });
// It would be nice to put this immediately under the above note, but they get
// pushed to the end.
implicit_static_lifetimes
.push(ImplicitStaticLifetimeSubdiag::Sugg { span: span.shrink_to_hi() });
}
}
} else {
// Otherwise just point out the impl.
impl_span = Some(self.tcx().def_span(*impl_def_id));
}
let err = MismatchedStaticLifetime {
cause_span: cause.span,
unmet_lifetime_reqs: multispan_subdiag,
expl,
does_not_outlive_static_from_impl: impl_span
.map(|span| DoesNotOutliveStaticFromImpl::Spanned { span })
.unwrap_or(DoesNotOutliveStaticFromImpl::Unspanned),
implicit_static_lifetimes,
};
let reported = self.tcx().dcx().emit_err(err);
Some(reported)
}
}