diff options
Diffstat (limited to 'compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs')
-rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs new file mode 100644 index 000000000..76cb76d9f --- /dev/null +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -0,0 +1,116 @@ +//! Error Reporting for Anonymous Region Lifetime Errors +//! where one region is named and the other is anonymous. +use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; +use crate::infer::error_reporting::nice_region_error::NiceRegionError; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_middle::ty; +use rustc_span::symbol::kw; + +impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { + /// When given a `ConcreteFailure` for a function with parameters containing a named region and + /// an anonymous region, emit an descriptive diagnostic error. + pub(super) fn try_report_named_anon_conflict( + &self, + ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { + let (span, sub, sup) = self.regions()?; + + debug!( + "try_report_named_anon_conflict(sub={:?}, sup={:?}, error={:?})", + sub, sup, self.error, + ); + + // Determine whether the sub and sup consist of one named region ('a) + // and one anonymous (elided) region. If so, find the parameter arg + // where the anonymous region appears (there must always be one; we + // only introduced anonymous regions in parameters) as well as a + // version new_ty of its type where the anonymous region is replaced + // with the named one. + let (named, anon, anon_param_info, region_info) = if sub.has_name() + && self.tcx().is_suitable_region(sup).is_some() + && self.find_param_with_region(sup, sub).is_some() + { + ( + sub, + sup, + self.find_param_with_region(sup, sub).unwrap(), + self.tcx().is_suitable_region(sup).unwrap(), + ) + } else if sup.has_name() + && self.tcx().is_suitable_region(sub).is_some() + && self.find_param_with_region(sub, sup).is_some() + { + ( + sup, + sub, + self.find_param_with_region(sub, sup).unwrap(), + self.tcx().is_suitable_region(sub).unwrap(), + ) + } else { + return None; // inapplicable + }; + + // Suggesting to add a `'static` lifetime to a parameter is nearly always incorrect, + // and can steer users down the wrong path. + if named.is_static() { + return None; + } + + debug!("try_report_named_anon_conflict: named = {:?}", named); + debug!("try_report_named_anon_conflict: anon_param_info = {:?}", anon_param_info); + debug!("try_report_named_anon_conflict: region_info = {:?}", region_info); + + let param = anon_param_info.param; + let new_ty = anon_param_info.param_ty; + let new_ty_span = anon_param_info.param_ty_span; + let br = anon_param_info.bound_region; + let is_first = anon_param_info.is_first; + let scope_def_id = region_info.def_id; + let is_impl_item = region_info.is_impl_item; + + match br { + ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) => {} + _ => { + /* not an anonymous region */ + debug!("try_report_named_anon_conflict: not an anonymous region"); + return None; + } + } + + if is_impl_item { + debug!("try_report_named_anon_conflict: impl item, bail out"); + return None; + } + + if find_anon_type(self.tcx(), anon, &br).is_some() + && self.is_self_anon(is_first, scope_def_id) + { + return None; + } + + let (error_var, span_label_var) = match param.pat.simple_ident() { + Some(simple_ident) => ( + format!("the type of `{}`", simple_ident), + format!("the type of `{}`", simple_ident), + ), + None => ("parameter type".to_owned(), "type".to_owned()), + }; + + let mut diag = struct_span_err!( + self.tcx().sess, + span, + E0621, + "explicit lifetime required in {}", + error_var + ); + + diag.span_label(span, format!("lifetime `{}` required", named)); + diag.span_suggestion( + new_ty_span, + &format!("add explicit lifetime `{}` to {}", named, span_label_var), + new_ty, + Applicability::Unspecified, + ); + + Some(diag) + } +} |