use crate::error_reporting::infer::nice_region_error::find_anon_type::find_anon_type;
use crate::error_reporting::infer::nice_region_error::util::AnonymousParamInfo;
use crate::error_reporting::infer::nice_region_error::NiceRegionError;
use crate::errors::AddLifetimeParamsSuggestion;
use crate::errors::LifetimeMismatch;
use crate::errors::LifetimeMismatchLabels;
use crate::infer::RegionResolutionError;
use crate::infer::SubregionOrigin;
use rustc_errors::Subdiagnostic;
use rustc_errors::{Diag, ErrorGuaranteed};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::Ty;
use rustc_middle::ty::{Region, TyCtxt};
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorGuaranteed> {
let (span, sub, sup) = self.regions()?;
if let Some(RegionResolutionError::ConcreteFailure(
SubregionOrigin::ReferenceOutlivesReferent(..),
..,
)) = self.error
{
return None;
}
let anon_reg_sup = self.tcx().is_suitable_region(self.generic_param_scope, sup)?;
let anon_reg_sub = self.tcx().is_suitable_region(self.generic_param_scope, sub)?;
let scope_def_id_sup = anon_reg_sup.def_id;
let bregion_sup = anon_reg_sup.bound_region;
let scope_def_id_sub = anon_reg_sub.def_id;
let bregion_sub = anon_reg_sub.bound_region;
let ty_sup = find_anon_type(self.tcx(), self.generic_param_scope, sup, &bregion_sup)?;
let ty_sub = find_anon_type(self.tcx(), self.generic_param_scope, sub, &bregion_sub)?;
debug!(
"try_report_anon_anon_conflict: found_param1={:?} sup={:?} br1={:?}",
ty_sub, sup, bregion_sup
);
debug!(
"try_report_anon_anon_conflict: found_param2={:?} sub={:?} br2={:?}",
ty_sup, sub, bregion_sub
);
let (ty_sup, ty_fndecl_sup) = ty_sup;
let (ty_sub, ty_fndecl_sub) = ty_sub;
let AnonymousParamInfo { param: anon_param_sup, .. } =
self.find_param_with_region(sup, sup)?;
let AnonymousParamInfo { param: anon_param_sub, .. } =
self.find_param_with_region(sub, sub)?;
let sup_is_ret_type =
self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup);
let sub_is_ret_type =
self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
debug!(
"try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}",
sub_is_ret_type, sup_is_ret_type
);
let labels = match (sup_is_ret_type, sub_is_ret_type) {
(ret_capture @ Some(ret_span), _) | (_, ret_capture @ Some(ret_span)) => {
let param_span =
if sup_is_ret_type == ret_capture { ty_sub.span } else { ty_sup.span };
LifetimeMismatchLabels::InRet {
param_span,
ret_span,
span,
label_var1: anon_param_sup.pat.simple_ident(),
}
}
(None, None) => LifetimeMismatchLabels::Normal {
hir_equal: ty_sup.hir_id == ty_sub.hir_id,
ty_sup: ty_sup.span,
ty_sub: ty_sub.span,
span,
sup: anon_param_sup.pat.simple_ident(),
sub: anon_param_sub.pat.simple_ident(),
},
};
let suggestion = AddLifetimeParamsSuggestion {
tcx: self.tcx(),
sub,
ty_sup,
ty_sub,
add_note: true,
generic_param_scope: self.generic_param_scope,
};
let err = LifetimeMismatch { span, labels, suggestion };
let reported = self.tcx().dcx().emit_err(err);
Some(reported)
}
}
pub fn suggest_adding_lifetime_params<'tcx>(
tcx: TyCtxt<'tcx>,
err: &mut Diag<'_>,
generic_param_scope: LocalDefId,
sub: Region<'tcx>,
ty_sup: &'tcx Ty<'_>,
ty_sub: &'tcx Ty<'_>,
) {
let suggestion = AddLifetimeParamsSuggestion {
tcx,
sub,
ty_sup,
ty_sub,
add_note: false,
generic_param_scope,
};
suggestion.add_to_diag(err);
}