1 #![deny(rustc::untranslatable_diagnostic)]
2 #![deny(rustc::diagnostic_outside_of_impl)]
3 //! Error reporting machinery for lifetime errors.
5 use rustc_data_structures
::fx
::FxIndexSet
;
6 use rustc_errors
::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}
;
8 use rustc_hir
::def
::Res
::Def
;
9 use rustc_hir
::def_id
::DefId
;
10 use rustc_hir
::intravisit
::Visitor
;
11 use rustc_hir
::GenericBound
::Trait
;
12 use rustc_hir
::QPath
::Resolved
;
13 use rustc_hir
::WherePredicate
::BoundPredicate
;
14 use rustc_hir
::{PolyTraitRef, TyKind, WhereBoundPredicate}
;
15 use rustc_infer
::infer
::{
16 error_reporting
::nice_region_error
::{
17 self, find_anon_type
, find_param_with_region
, suggest_adding_lifetime_params
,
18 HirTraitObjectVisitor
, NiceRegionError
, TraitObjectVisitor
,
20 error_reporting
::unexpected_hidden_region_diagnostic
,
21 NllRegionVariableOrigin
, RelateParamBound
,
23 use rustc_middle
::hir
::place
::PlaceBase
;
24 use rustc_middle
::mir
::{ConstraintCategory, ReturnConstraint}
;
25 use rustc_middle
::ty
::subst
::InternalSubsts
;
26 use rustc_middle
::ty
::TypeVisitor
;
27 use rustc_middle
::ty
::{self, RegionVid, Ty}
;
28 use rustc_middle
::ty
::{Region, TyCtxt}
;
29 use rustc_span
::symbol
::{kw, Ident}
;
30 use rustc_span
::{Span, DUMMY_SP}
;
32 use crate::borrowck_errors
;
33 use crate::session_diagnostics
::{
34 FnMutError
, FnMutReturnTypeErr
, GenericDoesNotLiveLongEnough
, LifetimeOutliveErr
,
35 LifetimeReturnCategoryErr
, RequireStaticErr
, VarHereDenote
,
38 use super::{OutlivesSuggestionBuilder, RegionName}
;
39 use crate::region_infer
::{BlameConstraint, ExtraConstraintInfo}
;
41 nll
::ConstraintDescription
,
42 region_infer
::{values::RegionElement, TypeTest}
,
43 universal_regions
::DefiningTy
,
47 impl<'tcx
> ConstraintDescription
for ConstraintCategory
<'tcx
> {
48 fn description(&self) -> &'
static str {
49 // Must end with a space. Allows for empty names to be provided.
51 ConstraintCategory
::Assignment
=> "assignment ",
52 ConstraintCategory
::Return(_
) => "returning this value ",
53 ConstraintCategory
::Yield
=> "yielding this value ",
54 ConstraintCategory
::UseAsConst
=> "using this value as a constant ",
55 ConstraintCategory
::UseAsStatic
=> "using this value as a static ",
56 ConstraintCategory
::Cast
=> "cast ",
57 ConstraintCategory
::CallArgument(_
) => "argument ",
58 ConstraintCategory
::TypeAnnotation
=> "type annotation ",
59 ConstraintCategory
::ClosureBounds
=> "closure body ",
60 ConstraintCategory
::SizedBound
=> "proving this value is `Sized` ",
61 ConstraintCategory
::CopyBound
=> "copying this value ",
62 ConstraintCategory
::OpaqueType
=> "opaque type ",
63 ConstraintCategory
::ClosureUpvar(_
) => "closure capture ",
64 ConstraintCategory
::Usage
=> "this usage ",
65 ConstraintCategory
::Predicate(_
)
66 | ConstraintCategory
::Boring
67 | ConstraintCategory
::BoringNoLocation
68 | ConstraintCategory
::Internal
=> "",
73 /// A collection of errors encountered during region inference. This is needed to efficiently
74 /// report errors after borrow checking.
76 /// Usually we expect this to either be empty or contain a small number of items, so we can avoid
77 /// allocation most of the time.
78 pub(crate) struct RegionErrors
<'tcx
>(Vec
<RegionErrorKind
<'tcx
>>, TyCtxt
<'tcx
>);
80 impl<'tcx
> RegionErrors
<'tcx
> {
81 pub fn new(tcx
: TyCtxt
<'tcx
>) -> Self {
85 pub fn push(&mut self, val
: impl Into
<RegionErrorKind
<'tcx
>>) {
87 self.1.sess
.delay_span_bug(DUMMY_SP
, format
!("{val:?}"));
90 pub fn is_empty(&self) -> bool
{
93 pub fn into_iter(self) -> impl Iterator
<Item
= RegionErrorKind
<'tcx
>> {
98 #[derive(Clone, Debug)]
99 pub(crate) enum RegionErrorKind
<'tcx
> {
100 /// A generic bound failure for a type test (`T: 'a`).
101 TypeTestError { type_test: TypeTest<'tcx> }
,
103 /// An unexpected hidden region for an opaque type.
104 UnexpectedHiddenRegion
{
105 /// The span for the member constraint.
110 key
: ty
::OpaqueTypeKey
<'tcx
>,
111 /// The unexpected region.
112 member_region
: ty
::Region
<'tcx
>,
115 /// Higher-ranked subtyping error.
116 BoundUniversalRegionError
{
117 /// The placeholder free region.
118 longer_fr
: RegionVid
,
119 /// The region element that erroneously must be outlived by `longer_fr`.
120 error_element
: RegionElement
,
121 /// The placeholder region.
122 placeholder
: ty
::PlaceholderRegion
,
125 /// Any other lifetime error.
127 /// The origin of the region.
128 fr_origin
: NllRegionVariableOrigin
,
129 /// The region that should outlive `shorter_fr`.
130 longer_fr
: RegionVid
,
131 /// The region that should be shorter, but we can't prove it.
132 shorter_fr
: RegionVid
,
133 /// Indicates whether this is a reported error. We currently only report the first error
134 /// encountered and leave the rest unreported so as not to overwhelm the user.
139 /// Information about the various region constraints involved in a borrow checker error.
140 #[derive(Clone, Debug)]
141 pub struct ErrorConstraintInfo
<'tcx
> {
143 pub(super) fr
: RegionVid
,
144 pub(super) fr_is_local
: bool
,
145 pub(super) outlived_fr
: RegionVid
,
146 pub(super) outlived_fr_is_local
: bool
,
148 // Category and span for best blame constraint
149 pub(super) category
: ConstraintCategory
<'tcx
>,
150 pub(super) span
: Span
,
153 impl<'a
, 'tcx
> MirBorrowckCtxt
<'a
, 'tcx
> {
154 /// Converts a region inference variable into a `ty::Region` that
155 /// we can use for error reporting. If `r` is universally bound,
156 /// then we use the name that we have on record for it. If `r` is
157 /// existentially bound, then we check its inferred value and try
158 /// to find a good name from that. Returns `None` if we can't find
159 /// one (e.g., this is just some random part of the CFG).
160 pub(super) fn to_error_region(&self, r
: RegionVid
) -> Option
<ty
::Region
<'tcx
>> {
161 self.to_error_region_vid(r
).and_then(|r
| self.regioncx
.region_definition(r
).external_name
)
164 /// Returns the `RegionVid` corresponding to the region returned by
165 /// `to_error_region`.
166 pub(super) fn to_error_region_vid(&self, r
: RegionVid
) -> Option
<RegionVid
> {
167 if self.regioncx
.universal_regions().is_universal_region(r
) {
170 // We just want something nameable, even if it's not
171 // actually an upper bound.
172 let upper_bound
= self.regioncx
.approx_universal_upper_bound(r
);
174 if self.regioncx
.upper_bound_in_region_scc(r
, upper_bound
) {
175 self.to_error_region_vid(upper_bound
)
182 /// Returns `true` if a closure is inferred to be an `FnMut` closure.
183 fn is_closure_fn_mut(&self, fr
: RegionVid
) -> bool
{
184 if let Some(ty
::ReFree(free_region
)) = self.to_error_region(fr
).as_deref()
185 && let ty
::BoundRegionKind
::BrEnv
= free_region
.bound_region
186 && let DefiningTy
::Closure(_
, substs
) = self.regioncx
.universal_regions().defining_ty
188 return substs
.as_closure().kind() == ty
::ClosureKind
::FnMut
;
194 // For generic associated types (GATs) which implied 'static requirement
195 // from higher-ranked trait bounds (HRTB). Try to locate span of the trait
196 // and the span which bounded to the trait for adding 'static lifetime suggestion
197 fn suggest_static_lifetime_for_gat_from_hrtb(
199 diag
: &mut DiagnosticBuilder
<'_
, ErrorGuaranteed
>,
200 lower_bound
: RegionVid
,
202 let mut suggestions
= vec
![];
203 let hir
= self.infcx
.tcx
.hir();
205 // find generic associated types in the given region 'lower_bound'
206 let gat_id_and_generics
= self
208 .placeholders_contained_in(lower_bound
)
210 if let Some(id
) = placeholder
.bound
.kind
.get_id()
211 && let Some(placeholder_id
) = id
.as_local()
212 && let gat_hir_id
= hir
.local_def_id_to_hir_id(placeholder_id
)
213 && let Some(generics_impl
) = hir
.get_parent(gat_hir_id
).generics()
215 Some((gat_hir_id
, generics_impl
))
220 .collect
::<Vec
<_
>>();
221 debug
!(?gat_id_and_generics
);
223 // find higher-ranked trait bounds bounded to the generic associated types
224 let mut hrtb_bounds
= vec
![];
225 gat_id_and_generics
.iter().flatten().for_each(|(gat_hir_id
, generics
)| {
226 for pred
in generics
.predicates
{
228 WhereBoundPredicate
{
229 bound_generic_params
,
232 }) = pred
else { continue; }
;
233 if bound_generic_params
235 .rfind(|bgp
| hir
.local_def_id_to_hir_id(bgp
.def_id
) == *gat_hir_id
)
238 for bound
in *bounds
{
239 hrtb_bounds
.push(bound
);
244 debug
!(?hrtb_bounds
);
246 hrtb_bounds
.iter().for_each(|bound
| {
247 let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }
, _
) = bound
else { return; }
;
250 format
!("due to current limitations in the borrow checker, this implies a `'static` lifetime")
252 let Some(generics_fn
) = hir
.get_generics(self.body
.source
.def_id().expect_local()) else { return; }
;
253 let Def(_
, trait_res_defid
) = trait_ref
.path
.res
else { return; }
;
254 debug
!(?generics_fn
);
255 generics_fn
.predicates
.iter().for_each(|predicate
| {
257 WhereBoundPredicate
{
263 ) = predicate
else { return; }
;
264 bounds
.iter().for_each(|bd
| {
265 if let Trait(PolyTraitRef { trait_ref: tr_ref, .. }
, _
) = bd
266 && let Def(_
, res_defid
) = tr_ref
.path
.res
267 && res_defid
== trait_res_defid
// trait id matches
268 && let TyKind
::Path(Resolved(_
, path
)) = bounded_ty
.kind
269 && let Def(_
, defid
) = path
.res
270 && generics_fn
.params
272 .rfind(|param
| param
.def_id
.to_def_id() == defid
)
274 suggestions
.push((bounded_span
.shrink_to_hi(), format
!(" + 'static")));
279 if suggestions
.len() > 0 {
281 diag
.multipart_suggestion_verbose(
282 format
!("consider restricting the type parameter to the `'static` lifetime"),
284 Applicability
::MaybeIncorrect
,
289 /// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`.
290 pub(crate) fn report_region_errors(&mut self, nll_errors
: RegionErrors
<'tcx
>) {
291 // Iterate through all the errors, producing a diagnostic for each one. The diagnostics are
292 // buffered in the `MirBorrowckCtxt`.
294 let mut outlives_suggestion
= OutlivesSuggestionBuilder
::default();
295 let mut last_unexpected_hidden_region
: Option
<(Span
, Ty
<'_
>, ty
::OpaqueTypeKey
<'tcx
>)> =
298 for nll_error
in nll_errors
.into_iter() {
300 RegionErrorKind
::TypeTestError { type_test }
=> {
301 // Try to convert the lower-bound region into something named we can print for the user.
302 let lower_bound_region
= self.to_error_region(type_test
.lower_bound
);
304 let type_test_span
= type_test
.span
;
306 if let Some(lower_bound_region
) = lower_bound_region
{
307 let generic_ty
= type_test
.generic_kind
.to_ty(self.infcx
.tcx
);
308 let origin
= RelateParamBound(type_test_span
, generic_ty
, None
);
309 self.buffer_error(self.infcx
.err_ctxt().construct_generic_bound_failure(
310 self.body
.source
.def_id().expect_local(),
313 type_test
.generic_kind
,
317 // FIXME. We should handle this case better. It
318 // indicates that we have e.g., some region variable
319 // whose value is like `'a+'b` where `'a` and `'b` are
320 // distinct unrelated universal regions that are not
321 // known to outlive one another. It'd be nice to have
322 // some examples where this arises to decide how best
323 // to report it; we could probably handle it by
324 // iterating over the universal regions and reporting
325 // an error that multiple bounds are required.
327 self.infcx
.tcx
.sess
.create_err(GenericDoesNotLiveLongEnough
{
328 kind
: type_test
.generic_kind
.to_string(),
329 span
: type_test_span
,
332 // Add notes and suggestions for the case of 'static lifetime
333 // implied but not specified when a generic associated types
334 // are from higher-ranked trait bounds
335 self.suggest_static_lifetime_for_gat_from_hrtb(
337 type_test
.lower_bound
,
340 self.buffer_error(diag
);
344 RegionErrorKind
::UnexpectedHiddenRegion { span, hidden_ty, key, member_region }
=> {
345 let named_ty
= self.regioncx
.name_regions(self.infcx
.tcx
, hidden_ty
);
346 let named_key
= self.regioncx
.name_regions(self.infcx
.tcx
, key
);
347 let named_region
= self.regioncx
.name_regions(self.infcx
.tcx
, member_region
);
348 let mut diag
= unexpected_hidden_region_diagnostic(
355 if last_unexpected_hidden_region
!= Some((span
, named_ty
, named_key
)) {
356 self.buffer_error(diag
);
357 last_unexpected_hidden_region
= Some((span
, named_ty
, named_key
));
363 RegionErrorKind
::BoundUniversalRegionError
{
368 let error_vid
= self.regioncx
.region_from_element(longer_fr
, &error_element
);
370 // Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
371 let (_
, cause
) = self.regioncx
.find_outlives_blame_span(
373 NllRegionVariableOrigin
::Placeholder(placeholder
),
377 let universe
= placeholder
.universe
;
378 let universe_info
= self.regioncx
.universe_info(universe
);
380 universe_info
.report_error(self, placeholder
, error_element
, cause
);
383 RegionErrorKind
::RegionError { fr_origin, longer_fr, shorter_fr, is_reported }
=> {
385 self.report_region_error(
389 &mut outlives_suggestion
,
392 // We only report the first error, so as not to overwhelm the user. See
393 // `RegRegionErrorKind` docs.
395 // FIXME: currently we do nothing with these, but perhaps we can do better?
396 // FIXME: try collecting these constraints on the outlives suggestion
397 // builder. Does it make the suggestions any better?
399 "Unreported region error: can't prove that {:?}: {:?}",
400 longer_fr
, shorter_fr
407 // Emit one outlives suggestions for each MIR def we borrowck
408 outlives_suggestion
.add_suggestion(self);
411 /// Report an error because the universal region `fr` was required to outlive
412 /// `outlived_fr` but it is not known to do so. For example:
415 /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
418 /// Here we would be invoked with `fr = 'a` and `outlived_fr = 'b`.
419 pub(crate) fn report_region_error(
422 fr_origin
: NllRegionVariableOrigin
,
423 outlived_fr
: RegionVid
,
424 outlives_suggestion
: &mut OutlivesSuggestionBuilder
,
426 debug
!("report_region_error(fr={:?}, outlived_fr={:?})", fr
, outlived_fr
);
428 let (blame_constraint
, extra_info
) =
429 self.regioncx
.best_blame_constraint(fr
, fr_origin
, |r
| {
430 self.regioncx
.provides_universal_region(r
, fr
, outlived_fr
)
432 let BlameConstraint { category, cause, variance_info, .. }
= blame_constraint
;
434 debug
!("report_region_error: category={:?} {:?} {:?}", category
, cause
, variance_info
);
436 // Check if we can use one of the "nice region errors".
437 if let (Some(f
), Some(o
)) = (self.to_error_region(fr
), self.to_error_region(outlived_fr
)) {
438 let infer_err
= self.infcx
.err_ctxt();
439 let nice
= NiceRegionError
::new_from_span(&infer_err
, cause
.span
, o
, f
);
440 if let Some(diag
) = nice
.try_report_from_nll() {
441 self.buffer_error(diag
);
446 let (fr_is_local
, outlived_fr_is_local
): (bool
, bool
) = (
447 self.regioncx
.universal_regions().is_local_free_region(fr
),
448 self.regioncx
.universal_regions().is_local_free_region(outlived_fr
),
452 "report_region_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
453 fr_is_local
, outlived_fr_is_local
, category
456 let errci
= ErrorConstraintInfo
{
460 outlived_fr_is_local
,
465 let mut diag
= match (category
, fr_is_local
, outlived_fr_is_local
) {
466 (ConstraintCategory
::Return(kind
), true, false) if self.is_closure_fn_mut(fr
) => {
467 self.report_fnmut_error(&errci
, kind
)
469 (ConstraintCategory
::Assignment
, true, false)
470 | (ConstraintCategory
::CallArgument(_
), true, false) => {
471 let mut db
= self.report_escaping_data_error(&errci
);
473 outlives_suggestion
.intermediate_suggestion(self, &errci
, &mut db
);
474 outlives_suggestion
.collect_constraint(fr
, outlived_fr
);
479 let mut db
= self.report_general_error(&errci
);
481 outlives_suggestion
.intermediate_suggestion(self, &errci
, &mut db
);
482 outlives_suggestion
.collect_constraint(fr
, outlived_fr
);
488 match variance_info
{
489 ty
::VarianceDiagInfo
::None
=> {}
490 ty
::VarianceDiagInfo
::Invariant { ty, param_index }
=> {
491 let (desc
, note
) = match ty
.kind() {
492 ty
::RawPtr(ty_mut
) => {
493 assert_eq
!(ty_mut
.mutbl
, rustc_hir
::Mutability
::Mut
);
495 format
!("a mutable pointer to `{}`", ty_mut
.ty
),
496 "mutable pointers are invariant over their type parameter".to_string(),
499 ty
::Ref(_
, inner_ty
, mutbl
) => {
500 assert_eq
!(*mutbl
, rustc_hir
::Mutability
::Mut
);
502 format
!("a mutable reference to `{inner_ty}`"),
503 "mutable references are invariant over their type parameter"
507 ty
::Adt(adt
, substs
) => {
508 let generic_arg
= substs
[param_index
as usize];
509 let identity_substs
=
510 InternalSubsts
::identity_for_item(self.infcx
.tcx
, adt
.did());
511 let base_ty
= self.infcx
.tcx
.mk_adt(*adt
, identity_substs
);
512 let base_generic_arg
= identity_substs
[param_index
as usize];
513 let adt_desc
= adt
.descr();
516 "the type `{ty}`, which makes the generic argument `{generic_arg}` invariant"
519 "the {adt_desc} `{base_ty}` is invariant over the parameter `{base_generic_arg}`"
523 ty
::FnDef(def_id
, _
) => {
524 let name
= self.infcx
.tcx
.item_name(*def_id
);
525 let identity_substs
=
526 InternalSubsts
::identity_for_item(self.infcx
.tcx
, *def_id
);
527 let desc
= format
!("a function pointer to `{name}`");
529 "the function `{name}` is invariant over the parameter `{}`",
530 identity_substs
[param_index
as usize]
534 _
=> panic
!("Unexpected type {ty:?}"),
536 diag
.note(&format
!("requirement occurs because of {desc}",));
538 diag
.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance");
542 for extra
in extra_info
{
544 ExtraConstraintInfo
::PlaceholderFromPredicate(span
) => {
545 diag
.span_note(span
, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
550 self.buffer_error(diag
);
553 /// Report a specialized error when `FnMut` closures return a reference to a captured variable.
554 /// This function expects `fr` to be local and `outlived_fr` to not be local.
557 /// error: captured variable cannot escape `FnMut` closure body
558 /// --> $DIR/issue-53040.rs:15:8
561 /// | -- ^^^^^^ creates a reference to a captured variable which escapes the closure body
563 /// | inferred to be a `FnMut` closure
565 /// = note: `FnMut` closures only have access to their captured variables while they are
567 /// = note: ...therefore, returned references to captured variables will escape the closure
569 fn report_fnmut_error(
571 errci
: &ErrorConstraintInfo
<'tcx
>,
572 kind
: ReturnConstraint
,
573 ) -> DiagnosticBuilder
<'tcx
, ErrorGuaranteed
> {
574 let ErrorConstraintInfo { outlived_fr, span, .. }
= errci
;
576 let mut output_ty
= self.regioncx
.universal_regions().unnormalized_output_ty
;
577 if let ty
::Alias(ty
::Opaque
, ty
::AliasTy { def_id, .. }
) = *output_ty
.kind() {
578 output_ty
= self.infcx
.tcx
.type_of(def_id
).subst_identity()
581 debug
!("report_fnmut_error: output_ty={:?}", output_ty
);
583 let err
= FnMutError
{
585 ty_err
: match output_ty
.kind() {
586 ty
::Generator(def
, ..) if self.infcx
.tcx
.generator_is_async(*def
) => {
587 FnMutReturnTypeErr
::ReturnAsyncBlock { span: *span }
589 _
if output_ty
.contains_closure() => {
590 FnMutReturnTypeErr
::ReturnClosure { span: *span }
592 _
=> FnMutReturnTypeErr
::ReturnRef { span: *span }
,
596 let mut diag
= self.infcx
.tcx
.sess
.create_err(err
);
598 if let ReturnConstraint
::ClosureUpvar(upvar_field
) = kind
{
599 let def_id
= match self.regioncx
.universal_regions().defining_ty
{
600 DefiningTy
::Closure(def_id
, _
) => def_id
,
601 ty
=> bug
!("unexpected DefiningTy {:?}", ty
),
604 let captured_place
= &self.upvars
[upvar_field
.index()].place
;
605 let defined_hir
= match captured_place
.place
.base
{
606 PlaceBase
::Local(hirid
) => Some(hirid
),
607 PlaceBase
::Upvar(upvar
) => Some(upvar
.var_path
.hir_id
),
611 if let Some(def_hir
) = defined_hir
{
612 let upvars_map
= self.infcx
.tcx
.upvars_mentioned(def_id
).unwrap();
613 let upvar_def_span
= self.infcx
.tcx
.hir().span(def_hir
);
614 let upvar_span
= upvars_map
.get(&def_hir
).unwrap().span
;
615 diag
.subdiagnostic(VarHereDenote
::Defined { span: upvar_def_span }
);
616 diag
.subdiagnostic(VarHereDenote
::Captured { span: upvar_span }
);
620 if let Some(fr_span
) = self.give_region_a_name(*outlived_fr
).unwrap().span() {
621 diag
.subdiagnostic(VarHereDenote
::FnMutInferred { span: fr_span }
);
624 self.suggest_move_on_borrowing_closure(&mut diag
);
629 /// Reports an error specifically for when data is escaping a closure.
632 /// error: borrowed data escapes outside of function
633 /// --> $DIR/lifetime-bound-will-change-warning.rs:44:5
635 /// LL | fn test2<'a>(x: &'a Box<Fn()+'a>) {
636 /// | - `x` is a reference that is only valid in the function body
637 /// LL | // but ref_obj will not, so warn.
639 /// | ^^^^^^^^^^ `x` escapes the function body here
641 #[instrument(level = "debug", skip(self))]
642 fn report_escaping_data_error(
644 errci
: &ErrorConstraintInfo
<'tcx
>,
645 ) -> DiagnosticBuilder
<'tcx
, ErrorGuaranteed
> {
646 let ErrorConstraintInfo { span, category, .. }
= errci
;
648 let fr_name_and_span
= self.regioncx
.get_var_name_and_span_for_region(
655 let outlived_fr_name_and_span
= self.regioncx
.get_var_name_and_span_for_region(
664 self.infcx
.tcx
.def_descr(self.regioncx
.universal_regions().defining_ty
.def_id());
666 // Revert to the normal error in these cases.
667 // Assignments aren't "escapes" in function items.
668 if (fr_name_and_span
.is_none() && outlived_fr_name_and_span
.is_none())
669 || (*category
== ConstraintCategory
::Assignment
670 && self.regioncx
.universal_regions().defining_ty
.is_fn_def())
671 || self.regioncx
.universal_regions().defining_ty
.is_const()
673 return self.report_general_error(&ErrorConstraintInfo
{
675 outlived_fr_is_local
: false,
681 borrowck_errors
::borrowed_data_escapes_closure(self.infcx
.tcx
, *span
, escapes_from
);
683 if let Some((Some(outlived_fr_name
), outlived_fr_span
)) = outlived_fr_name_and_span
{
686 format
!("`{outlived_fr_name}` declared here, outside of the {escapes_from} body",),
690 if let Some((Some(fr_name
), fr_span
)) = fr_name_and_span
{
694 "`{fr_name}` is a reference that is only valid in the {escapes_from} body",
698 diag
.span_label(*span
, format
!("`{fr_name}` escapes the {escapes_from} body here"));
701 // Only show an extra note if we can find an 'error region' for both of the region
702 // variables. This avoids showing a noisy note that just mentions 'synthetic' regions
703 // that don't help the user understand the error.
704 match (self.to_error_region(errci
.fr
), self.to_error_region(errci
.outlived_fr
)) {
705 (Some(f
), Some(o
)) => {
706 self.maybe_suggest_constrain_dyn_trait_impl(&mut diag
, f
, o
, category
);
708 let fr_region_name
= self.give_region_a_name(errci
.fr
).unwrap();
709 fr_region_name
.highlight_region_name(&mut diag
);
710 let outlived_fr_region_name
= self.give_region_a_name(errci
.outlived_fr
).unwrap();
711 outlived_fr_region_name
.highlight_region_name(&mut diag
);
716 "{}requires that `{}` must outlive `{}`",
717 category
.description(),
719 outlived_fr_region_name
,
729 /// Reports a region inference error for the general case with named/synthesized lifetimes to
730 /// explain what is happening.
733 /// error: unsatisfied lifetime constraints
734 /// --> $DIR/regions-creating-enums3.rs:17:5
736 /// LL | fn mk_add_bad1<'a,'b>(x: &'a ast<'a>, y: &'b ast<'b>) -> ast<'a> {
737 /// | -- -- lifetime `'b` defined here
739 /// | lifetime `'a` defined here
740 /// LL | ast::add(x, y)
741 /// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
742 /// | is returning data with lifetime `'b`
744 fn report_general_error(
746 errci
: &ErrorConstraintInfo
<'tcx
>,
747 ) -> DiagnosticBuilder
<'tcx
, ErrorGuaranteed
> {
748 let ErrorConstraintInfo
{
752 outlived_fr_is_local
,
758 let mir_def_name
= self.infcx
.tcx
.def_descr(self.mir_def_id().to_def_id());
760 let err
= LifetimeOutliveErr { span: *span }
;
761 let mut diag
= self.infcx
.tcx
.sess
.create_err(err
);
763 let fr_name
= self.give_region_a_name(*fr
).unwrap();
764 fr_name
.highlight_region_name(&mut diag
);
765 let outlived_fr_name
= self.give_region_a_name(*outlived_fr
).unwrap();
766 outlived_fr_name
.highlight_region_name(&mut diag
);
768 let err_category
= match (category
, outlived_fr_is_local
, fr_is_local
) {
769 (ConstraintCategory
::Return(_
), true, _
) => LifetimeReturnCategoryErr
::WrongReturn
{
775 _
=> LifetimeReturnCategoryErr
::ShortReturn
{
777 category_desc
: category
.description(),
778 free_region_name
: &fr_name
,
783 diag
.subdiagnostic(err_category
);
785 self.add_static_impl_trait_suggestion(&mut diag
, *fr
, fr_name
, *outlived_fr
);
786 self.suggest_adding_lifetime_params(&mut diag
, *fr
, *outlived_fr
);
787 self.suggest_move_on_borrowing_closure(&mut diag
);
792 /// Adds a suggestion to errors where an `impl Trait` is returned.
795 /// help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as
798 /// LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
799 /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
801 fn add_static_impl_trait_suggestion(
803 diag
: &mut Diagnostic
,
805 // We need to pass `fr_name` - computing it again will label it twice.
807 outlived_fr
: RegionVid
,
809 if let (Some(f
), Some(outlived_f
)) =
810 (self.to_error_region(fr
), self.to_error_region(outlived_fr
))
812 if *outlived_f
!= ty
::ReStatic
{
815 let suitable_region
= self.infcx
.tcx
.is_suitable_region(f
);
816 let Some(suitable_region
) = suitable_region
else { return; }
;
818 let fn_returns
= self.infcx
.tcx
.return_type_impl_or_dyn_traits(suitable_region
.def_id
);
820 let param
= if let Some(param
) = find_param_with_region(self.infcx
.tcx
, f
, outlived_f
) {
826 let lifetime
= if f
.has_name() { fr_name.name }
else { kw::UnderscoreLifetime }
;
828 let arg
= match param
.param
.pat
.simple_ident() {
829 Some(simple_ident
) => format
!("argument `{simple_ident}`"),
830 None
=> "the argument".to_string(),
832 let captures
= format
!("captures data from {arg}");
834 if !fn_returns
.is_empty() {
835 nice_region_error
::suggest_new_region_bound(
839 lifetime
.to_string(),
842 Some((param
.param_ty_span
, param
.param_ty
.to_string())),
843 Some(suitable_region
.def_id
),
848 let Some((alias_tys
, alias_span
)) = self
851 .return_type_impl_or_dyn_traits_with_type_alias(suitable_region
.def_id
) else { return; }
;
853 // in case the return type of the method is a type alias
854 let mut spans_suggs
: Vec
<_
> = Vec
::new();
855 for alias_ty
in alias_tys
{
856 if alias_ty
.span
.desugaring_kind().is_some() {
857 // Skip `async` desugaring `impl Future`.
860 if let TyKind
::TraitObject(_
, lt
, _
) = alias_ty
.kind
{
861 spans_suggs
.push((lt
.ident
.span
.shrink_to_hi(), " + 'a".to_string()));
864 spans_suggs
.push((alias_span
.shrink_to_hi(), "<'a>".to_string()));
865 diag
.multipart_suggestion_verbose(
867 "to declare that the trait object {captures}, you can add a lifetime parameter `'a` in the type alias"
870 Applicability
::MaybeIncorrect
,
875 fn maybe_suggest_constrain_dyn_trait_impl(
877 diag
: &mut Diagnostic
,
880 category
: &ConstraintCategory
<'tcx
>,
886 let tcx
= self.infcx
.tcx
;
888 let instance
= if let ConstraintCategory
::CallArgument(Some(func_ty
)) = category
{
889 let (fn_did
, substs
) = match func_ty
.kind() {
890 ty
::FnDef(fn_did
, substs
) => (fn_did
, substs
),
893 debug
!(?fn_did
, ?substs
);
895 // Only suggest this on function calls, not closures
896 let ty
= tcx
.type_of(fn_did
).subst_identity();
897 debug
!("ty: {:?}, ty.kind: {:?}", ty
, ty
.kind());
898 if let ty
::Closure(_
, _
) = ty
.kind() {
902 if let Ok(Some(instance
)) = ty
::Instance
::resolve(
906 self.infcx
.resolve_vars_if_possible(substs
),
916 let param
= match find_param_with_region(tcx
, f
, o
) {
917 Some(param
) => param
,
922 let mut visitor
= TraitObjectVisitor(FxIndexSet
::default());
923 visitor
.visit_ty(param
.param_ty
);
925 let Some((ident
, self_ty
)) =
926 NiceRegionError
::get_impl_ident_and_self_ty_from_trait(tcx
, instance
.def_id(), &visitor
.0) else { return; }
;
928 self.suggest_constrain_dyn_trait_in_impl(diag
, &visitor
.0, ident
, self_ty
);
931 #[instrument(skip(self, err), level = "debug")]
932 fn suggest_constrain_dyn_trait_in_impl(
934 err
: &mut Diagnostic
,
935 found_dids
: &FxIndexSet
<DefId
>,
937 self_ty
: &hir
::Ty
<'_
>,
939 debug
!("err: {:#?}", err
);
940 let mut suggested
= false;
941 for found_did
in found_dids
{
942 let mut traits
= vec
![];
943 let mut hir_v
= HirTraitObjectVisitor(&mut traits
, *found_did
);
944 hir_v
.visit_ty(&self_ty
);
945 debug
!("trait spans found: {:?}", traits
);
946 for span
in &traits
{
947 let mut multi_span
: MultiSpan
= vec
![*span
].into();
949 .push_span_label(*span
, "this has an implicit `'static` lifetime requirement");
950 multi_span
.push_span_label(
952 "calling this method introduces the `impl`'s `'static` requirement",
954 err
.subdiagnostic(RequireStaticErr
::UsedImpl { multi_span }
);
955 err
.span_suggestion_verbose(
957 "consider relaxing the implicit `'static` requirement",
959 Applicability
::MaybeIncorrect
,
967 fn suggest_adding_lifetime_params(
969 diag
: &mut Diagnostic
,
973 let (Some(sub
), Some(sup
)) = (self.to_error_region(sub
), self.to_error_region(sup
)) else {
977 let Some((ty_sub
, _
)) = self
980 .is_suitable_region(sub
)
981 .and_then(|anon_reg
| find_anon_type(self.infcx
.tcx
, sub
, &anon_reg
.boundregion
)) else {
985 let Some((ty_sup
, _
)) = self
988 .is_suitable_region(sup
)
989 .and_then(|anon_reg
| find_anon_type(self.infcx
.tcx
, sup
, &anon_reg
.boundregion
)) else {
993 suggest_adding_lifetime_params(self.infcx
.tcx
, sub
, ty_sup
, ty_sub
, diag
);
996 fn suggest_move_on_borrowing_closure(&self, diag
: &mut Diagnostic
) {
997 let map
= self.infcx
.tcx
.hir();
998 let body_id
= map
.body_owned_by(self.mir_def_id());
999 let expr
= &map
.body(body_id
).value
.peel_blocks();
1000 let mut closure_span
= None
::<rustc_span
::Span
>;
1002 hir
::ExprKind
::MethodCall(.., args
, _
) => {
1004 if let hir
::ExprKind
::Closure(hir
::Closure
{
1005 capture_clause
: hir
::CaptureBy
::Ref
,
1009 closure_span
= Some(arg
.span
.shrink_to_lo());
1014 hir
::ExprKind
::Closure(hir
::Closure
{
1015 capture_clause
: hir
::CaptureBy
::Ref
,
1019 let body
= map
.body(*body
);
1020 if !matches
!(body
.generator_kind
, Some(hir
::GeneratorKind
::Async(..))) {
1021 closure_span
= Some(expr
.span
.shrink_to_lo());
1026 if let Some(closure_span
) = closure_span
{
1027 diag
.span_suggestion_verbose(
1029 "consider adding 'move' keyword before the nested closure",
1031 Applicability
::MaybeIncorrect
,