1 //! Error Reporting for static impl Traits.
3 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
4 use crate::infer::lexical_region_resolve::RegionResolutionError;
5 use rustc_errors::{struct_span_err, Applicability, ErrorReported};
6 use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};
7 use rustc_middle::ty::RegionKind;
9 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
10 /// Print the error message for lifetime errors when the return type is a static impl Trait.
11 pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
12 debug!("try_report_static_impl_trait(error={:?})", self.error);
13 if let Some(ref error) = self.error {
14 if let RegionResolutionError::SubSupConflict(
24 "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
25 var_origin, sub_origin, sub_r, sup_origin, sup_r
27 let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
28 debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
29 let fn_returns = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id);
30 if fn_returns.is_empty() {
33 debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
34 if **sub_r == RegionKind::ReStatic {
35 let sp = var_origin.span();
36 let return_sp = sub_origin.span();
37 let param_info = self.find_param_with_region(sup_r, sub_r)?;
38 let (lifetime_name, lifetime) = if sup_r.has_name() {
39 (sup_r.to_string(), format!("lifetime `{}`", sup_r))
41 ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
43 let mut err = struct_span_err!(
47 "cannot infer an appropriate lifetime"
50 param_info.param_ty_span,
51 &format!("this data with {}...", lifetime),
53 debug!("try_report_static_impl_trait: param_info={:?}", param_info);
55 // We try to make the output have fewer overlapping spans if possible.
56 if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
57 && sup_origin.span() != return_sp
59 // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
61 // Customize the spans and labels depending on their relative order so
62 // that split sentences flow correctly.
63 if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
64 // Avoid the following:
66 // error: cannot infer an appropriate lifetime
67 // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
69 // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
74 // error: cannot infer an appropriate lifetime
75 // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
77 // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
81 "...is captured here, requiring it to live as long as `'static`",
84 err.span_label(sup_origin.span(), "...is captured here...");
85 if return_sp < sup_origin.span() {
88 "...and is required to live as long as `'static` here",
93 "...and is required to live as long as `'static` here",
100 "...is captured and required to live as long as `'static` here",
104 // FIXME: account for the need of parens in `&(dyn Trait + '_)`
105 let consider = "consider changing the";
106 let declare = "to declare that the";
107 let arg = match param_info.param.pat.simple_ident() {
108 Some(simple_ident) => format!("argument `{}`", simple_ident),
109 None => "the argument".to_string(),
112 format!("you can add an explicit `{}` lifetime bound", lifetime_name);
113 let explicit_static =
114 format!("explicit `'static` bound to the lifetime of {}", arg);
115 let captures = format!("captures data from {}", arg);
116 let add_static_bound =
117 "alternatively, add an explicit `'static` bound to this reference";
118 let plus_lt = format!(" + {}", lifetime_name);
119 for fn_return in fn_returns {
120 if fn_return.span.desugaring_kind().is_some() {
121 // Skip `async` desugaring `impl Future`.
124 match fn_return.kind {
125 TyKind::OpaqueDef(item_id, _) => {
126 let item = self.tcx().hir().item(item_id.id);
127 let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
131 return Some(ErrorReported);
134 if let Some(span) = opaque
137 .filter_map(|arg| match arg {
138 GenericBound::Outlives(Lifetime {
139 name: LifetimeName::Static,
147 err.span_suggestion_verbose(
149 &format!("{} `impl Trait`'s {}", consider, explicit_static),
150 lifetime_name.clone(),
151 Applicability::MaybeIncorrect,
153 err.span_suggestion_verbose(
154 param_info.param_ty_span,
156 param_info.param_ty.to_string(),
157 Applicability::MaybeIncorrect,
159 } else if let Some(_) = opaque
162 .filter_map(|arg| match arg {
163 GenericBound::Outlives(Lifetime { name, span, .. })
164 if name.ident().to_string() == lifetime_name =>
173 err.span_suggestion_verbose(
174 fn_return.span.shrink_to_hi(),
176 "{declare} `impl Trait` {captures}, {explicit}",
182 Applicability::MaybeIncorrect,
186 TyKind::TraitObject(_, lt) => match lt.name {
187 LifetimeName::ImplicitObjectLifetimeDefault => {
188 err.span_suggestion_verbose(
189 fn_return.span.shrink_to_hi(),
191 "{declare} trait object {captures}, {explicit}",
197 Applicability::MaybeIncorrect,
200 name if name.ident().to_string() != lifetime_name => {
201 // With this check we avoid suggesting redundant bounds. This
202 // would happen if there are nested impl/dyn traits and only
203 // one of them has the bound we'd suggest already there, like
204 // in `impl Foo<X = dyn Bar> + '_`.
205 err.span_suggestion_verbose(
207 &format!("{} trait object's {}", consider, explicit_static),
208 lifetime_name.clone(),
209 Applicability::MaybeIncorrect,
211 err.span_suggestion_verbose(
212 param_info.param_ty_span,
214 param_info.param_ty.to_string(),
215 Applicability::MaybeIncorrect,
224 return Some(ErrorReported);