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(RegionResolutionError::SubSupConflict(
23 "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
24 var_origin, sub_origin, sub_r, sup_origin, sup_r
26 let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
27 debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
28 let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
29 if fn_returns.is_empty() {
32 debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
33 if *sub_r == RegionKind::ReStatic {
34 let sp = var_origin.span();
35 let return_sp = sub_origin.span();
36 let param_info = self.find_param_with_region(sup_r, sub_r)?;
37 let (lifetime_name, lifetime) = if sup_r.has_name() {
38 (sup_r.to_string(), format!("lifetime `{}`", sup_r))
40 ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
42 let mut err = struct_span_err!(
46 "cannot infer an appropriate lifetime"
49 param_info.param_ty_span,
50 &format!("this data with {}...", lifetime),
52 debug!("try_report_static_impl_trait: param_info={:?}", param_info);
54 // We try to make the output have fewer overlapping spans if possible.
55 if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
56 && sup_origin.span() != return_sp
58 // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
60 // Customize the spans and labels depending on their relative order so
61 // that split sentences flow correctly.
62 if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
63 // Avoid the following:
65 // error: cannot infer an appropriate lifetime
66 // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
68 // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
73 // error: cannot infer an appropriate lifetime
74 // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
76 // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
80 "...is captured here, requiring it to live as long as `'static`",
83 err.span_label(sup_origin.span(), "...is captured here...");
84 if return_sp < sup_origin.span() {
87 "...and is required to live as long as `'static` here",
92 "...and is required to live as long as `'static` here",
99 "...is captured and required to live as long as `'static` here",
103 // FIXME: account for the need of parens in `&(dyn Trait + '_)`
104 let consider = "consider changing the";
105 let declare = "to declare that the";
106 let arg = match param_info.param.pat.simple_ident() {
107 Some(simple_ident) => format!("argument `{}`", simple_ident),
108 None => "the argument".to_string(),
111 format!("you can add an explicit `{}` lifetime bound", lifetime_name);
112 let explicit_static =
113 format!("explicit `'static` bound to the lifetime of {}", arg);
114 let captures = format!("captures data from {}", arg);
115 let add_static_bound =
116 "alternatively, add an explicit `'static` bound to this reference";
117 let plus_lt = format!(" + {}", lifetime_name);
118 for fn_return in fn_returns {
119 if fn_return.span.desugaring_kind().is_some() {
120 // Skip `async` desugaring `impl Future`.
123 match fn_return.kind {
124 TyKind::OpaqueDef(item_id, _) => {
125 let item = self.tcx().hir().item(item_id.id);
126 let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
130 return Some(ErrorReported);
133 if let Some(span) = opaque
136 .filter_map(|arg| match arg {
137 GenericBound::Outlives(Lifetime {
138 name: LifetimeName::Static,
146 err.span_suggestion_verbose(
148 &format!("{} `impl Trait`'s {}", consider, explicit_static),
149 lifetime_name.clone(),
150 Applicability::MaybeIncorrect,
152 err.span_suggestion_verbose(
153 param_info.param_ty_span,
155 param_info.param_ty.to_string(),
156 Applicability::MaybeIncorrect,
158 } else if let Some(_) = opaque
161 .filter_map(|arg| match arg {
162 GenericBound::Outlives(Lifetime { name, span, .. })
163 if name.ident().to_string() == lifetime_name =>
172 err.span_suggestion_verbose(
173 fn_return.span.shrink_to_hi(),
175 "{declare} `impl Trait` {captures}, {explicit}",
181 Applicability::MaybeIncorrect,
185 TyKind::TraitObject(_, lt) => match lt.name {
186 LifetimeName::ImplicitObjectLifetimeDefault => {
187 err.span_suggestion_verbose(
188 fn_return.span.shrink_to_hi(),
190 "{declare} trait object {captures}, {explicit}",
196 Applicability::MaybeIncorrect,
199 name if name.ident().to_string() != lifetime_name => {
200 // With this check we avoid suggesting redundant bounds. This
201 // would happen if there are nested impl/dyn traits and only
202 // one of them has the bound we'd suggest already there, like
203 // in `impl Foo<X = dyn Bar> + '_`.
204 err.span_suggestion_verbose(
206 &format!("{} trait object's {}", consider, explicit_static),
207 lifetime_name.clone(),
208 Applicability::MaybeIncorrect,
210 err.span_suggestion_verbose(
211 param_info.param_ty_span,
213 param_info.param_ty.to_string(),
214 Applicability::MaybeIncorrect,
223 return Some(ErrorReported);