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);
30 self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id.expect_local());
31 if fn_returns.is_empty() {
34 debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
35 if **sub_r == RegionKind::ReStatic {
36 let sp = var_origin.span();
37 let return_sp = sub_origin.span();
38 let param_info = self.find_param_with_region(sup_r, sub_r)?;
39 let (lifetime_name, lifetime) = if sup_r.has_name() {
40 (sup_r.to_string(), format!("lifetime `{}`", sup_r))
42 ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
44 let mut err = struct_span_err!(
48 "cannot infer an appropriate lifetime"
51 param_info.param_ty_span,
52 &format!("this data with {}...", lifetime),
54 debug!("try_report_static_impl_trait: param_info={:?}", param_info);
56 // We try to make the output have fewer overlapping spans if possible.
57 if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
58 && sup_origin.span() != return_sp
60 // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
62 // Customize the spans and labels depending on their relative order so
63 // that split sentences flow correctly.
64 if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
65 // Avoid the following:
67 // error: cannot infer an appropriate lifetime
68 // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
70 // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
75 // error: cannot infer an appropriate lifetime
76 // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
78 // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
82 "...is captured here, requiring it to live as long as `'static`",
85 err.span_label(sup_origin.span(), "...is captured here...");
86 if return_sp < sup_origin.span() {
89 "...and is required to live as long as `'static` here",
94 "...and is required to live as long as `'static` here",
101 "...is captured and required to live as long as `'static` here",
105 // FIXME: account for the need of parens in `&(dyn Trait + '_)`
106 let consider = "consider changing the";
107 let declare = "to declare that the";
108 let arg = match param_info.param.pat.simple_ident() {
109 Some(simple_ident) => format!("argument `{}`", simple_ident),
110 None => "the argument".to_string(),
113 format!("you can add an explicit `{}` lifetime bound", lifetime_name);
114 let explicit_static =
115 format!("explicit `'static` bound to the lifetime of {}", arg);
116 let captures = format!("captures data from {}", arg);
117 let add_static_bound =
118 "alternatively, add an explicit `'static` bound to this reference";
119 let plus_lt = format!(" + {}", lifetime_name);
120 for fn_return in fn_returns {
121 if fn_return.span.desugaring_kind().is_some() {
122 // Skip `async` desugaring `impl Future`.
125 match fn_return.kind {
126 TyKind::OpaqueDef(item_id, _) => {
127 let item = self.tcx().hir().item(item_id.id);
128 let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
132 return Some(ErrorReported);
135 if let Some(span) = opaque
138 .filter_map(|arg| match arg {
139 GenericBound::Outlives(Lifetime {
140 name: LifetimeName::Static,
148 err.span_suggestion_verbose(
150 &format!("{} `impl Trait`'s {}", consider, explicit_static),
151 lifetime_name.clone(),
152 Applicability::MaybeIncorrect,
154 err.span_suggestion_verbose(
155 param_info.param_ty_span,
157 param_info.param_ty.to_string(),
158 Applicability::MaybeIncorrect,
160 } else if let Some(_) = opaque
163 .filter_map(|arg| match arg {
164 GenericBound::Outlives(Lifetime { name, span, .. })
165 if name.ident().to_string() == lifetime_name =>
174 err.span_suggestion_verbose(
175 fn_return.span.shrink_to_hi(),
177 "{declare} `impl Trait` {captures}, {explicit}",
183 Applicability::MaybeIncorrect,
187 TyKind::TraitObject(_, lt) => match lt.name {
188 LifetimeName::ImplicitObjectLifetimeDefault => {
189 err.span_suggestion_verbose(
190 fn_return.span.shrink_to_hi(),
192 "{declare} trait object {captures}, {explicit}",
198 Applicability::MaybeIncorrect,
201 name if name.ident().to_string() != lifetime_name => {
202 // With this check we avoid suggesting redundant bounds. This
203 // would happen if there are nested impl/dyn traits and only
204 // one of them has the bound we'd suggest already there, like
205 // in `impl Foo<X = dyn Bar> + '_`.
206 err.span_suggestion_verbose(
208 &format!("{} trait object's {}", consider, explicit_static),
209 lifetime_name.clone(),
210 Applicability::MaybeIncorrect,
212 err.span_suggestion_verbose(
213 param_info.param_ty_span,
215 param_info.param_ty.to_string(),
216 Applicability::MaybeIncorrect,
225 return Some(ErrorReported);