summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
diff options
context:
space:
mode:
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.rs116
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)
+ }
+}