diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 1781f2e1650..3c4539b597b 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -6,7 +6,7 @@ use crate::Applicability; use crate::Level; use crate::snippet::Style; use std::fmt; -use syntax_pos::{MultiSpan, Span}; +use syntax_pos::{MultiSpan, Span, DUMMY_SP}; #[must_use] #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] @@ -17,6 +17,11 @@ pub struct Diagnostic { pub span: MultiSpan, pub children: Vec, pub suggestions: Vec, + + /// This is not used for highlighting or rendering any error message. Rather, it can be used + /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of + /// `span` if there is one. Otherwise, it is `DUMMY_SP`. + pub sort_span: Span, } #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] @@ -87,6 +92,7 @@ impl Diagnostic { span: MultiSpan::new(), children: vec![], suggestions: vec![], + sort_span: DUMMY_SP, } } @@ -118,6 +124,11 @@ impl Diagnostic { self.level == Level::Cancelled } + /// Set the sorting span. + pub fn set_sort_span(&mut self, sp: Span) { + self.sort_span = sp; + } + /// Adds a span/label to be included in the resulting snippet. /// This label will be shown together with the original span/label used when creating the /// diagnostic, *not* a span added by one of the `span_*` methods. @@ -457,6 +468,9 @@ impl Diagnostic { pub fn set_span>(&mut self, sp: S) -> &mut Self { self.span = sp.into(); + if let Some(span) = self.span.primary_span() { + self.sort_span = span; + } self } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index c3369e87215..4bfd0844f84 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -367,7 +367,7 @@ fn do_mir_borrowck<'a, 'tcx>( } if !mbcx.errors_buffer.is_empty() { - mbcx.errors_buffer.sort_by_key(|diag| diag.span.primary_span()); + mbcx.errors_buffer.sort_by_key(|diag| diag.sort_span); for diag in mbcx.errors_buffer.drain(..) { mbcx.infcx.tcx.sess.diagnostic().emit_diagnostic(&diag); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs index 7362ae9c638..26b288cb4b2 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs @@ -18,6 +18,10 @@ use syntax::errors::Applicability; use syntax::symbol::kw; use syntax_pos::Span; +use self::outlives_suggestion::OutlivesSuggestionBuilder; + +pub mod outlives_suggestion; + mod region_name; mod var_name; @@ -56,7 +60,6 @@ enum Trace { /// Various pieces of state used when reporting borrow checker errors. pub struct ErrorReportingCtx<'a, 'b, 'tcx> { /// The region inference context used for borrow chekcing this MIR body. - #[allow(dead_code)] // FIXME(mark-i-m): used by outlives suggestions region_infcx: &'b RegionInferenceContext<'tcx>, /// The inference context used for type checking. @@ -370,6 +373,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fr: RegionVid, fr_origin: NLLRegionVariableOrigin, outlived_fr: RegionVid, + outlives_suggestion: &mut OutlivesSuggestionBuilder, renctx: &mut RegionErrorNamingCtx, ) -> DiagnosticBuilder<'a> { debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); @@ -415,9 +419,22 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.report_fnmut_error(&errctx, &errci, renctx) } (ConstraintCategory::Assignment, true, false) - | (ConstraintCategory::CallArgument, true, false) => - self.report_escaping_data_error(&errctx, &errci, renctx), - _ => self.report_general_error(&errctx, &errci, renctx), + | (ConstraintCategory::CallArgument, true, false) => { + let mut db = self.report_escaping_data_error(&errctx, &errci, renctx); + + outlives_suggestion.intermediate_suggestion(&errctx, &errci, renctx, &mut db); + outlives_suggestion.collect_constraint(fr, outlived_fr); + + db + } + _ => { + let mut db = self.report_general_error(&errctx, &errci, renctx); + + outlives_suggestion.intermediate_suggestion(&errctx, &errci, renctx, &mut db); + outlives_suggestion.collect_constraint(fr, outlived_fr); + + db + } } } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/outlives_suggestion.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/outlives_suggestion.rs new file mode 100644 index 00000000000..a55a3a40604 --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/outlives_suggestion.rs @@ -0,0 +1,315 @@ +//! Contains utilities for generating suggestions for borrowck errors related to unsatisified +//! outlives constraints. + +use std::collections::BTreeMap; + +use log::debug; +use rustc::{hir::def_id::DefId, infer::InferCtxt, mir::Body, ty::RegionVid}; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::{Diagnostic, DiagnosticBuilder, Level}; + +use smallvec::SmallVec; + +use crate::borrow_check::nll::region_infer::{ + error_reporting::{ + region_name::{RegionName, RegionNameSource}, + ErrorConstraintInfo, ErrorReportingCtx, RegionErrorNamingCtx, + }, + RegionInferenceContext, +}; + +/// The different things we could suggest. +enum SuggestedConstraint { + /// Outlives(a, [b, c, d, ...]) => 'a: 'b + 'c + 'd + ... + Outlives(RegionName, SmallVec<[RegionName; 2]>), + + /// 'a = 'b + Equal(RegionName, RegionName), + + /// 'a: 'static i.e. 'a = 'static and the user should just use 'static + Static(RegionName), +} + +/// Collects information about outlives constraints that needed to be added for a given MIR node +/// corresponding to a function definition. +/// +/// Adds a help note suggesting adding a where clause with the needed constraints. +pub struct OutlivesSuggestionBuilder { + /// The MIR DefId of the fn with the lifetime error. + mir_def_id: DefId, + + /// The list of outlives constraints that need to be added. Specifically, we map each free + /// region to all other regions that it must outlive. I will use the shorthand `fr: + /// outlived_frs`. Not all of these regions will already have names necessarily. Some could be + /// implicit free regions that we inferred. These will need to be given names in the final + /// suggestion message. + constraints_to_add: BTreeMap>, +} + +impl OutlivesSuggestionBuilder { + /// Create a new builder for the given MIR node representing a fn definition. + crate fn new(mir_def_id: DefId) -> Self { + OutlivesSuggestionBuilder { mir_def_id, constraints_to_add: BTreeMap::default() } + } + + /// Returns `true` iff the `RegionNameSource` is a valid source for an outlives + /// suggestion. + // + // FIXME: Currently, we only report suggestions if the `RegionNameSource` is an early-bound + // region or a named region, avoiding using regions with synthetic names altogether. This + // allows us to avoid giving impossible suggestions (e.g. adding bounds to closure args). + // We can probably be less conservative, since some inferred free regions are namable (e.g. + // the user can explicitly name them. To do this, we would allow some regions whose names + // come from `MatchedAdtAndSegment`, being careful to filter out bad suggestions, such as + // naming the `'self` lifetime in methods, etc. + fn region_name_is_suggestable(name: &RegionName) -> bool { + match name.source { + RegionNameSource::NamedEarlyBoundRegion(..) + | RegionNameSource::NamedFreeRegion(..) + | RegionNameSource::Static => { + debug!("Region {:?} is suggestable", name); + true + } + + // Don't give suggestions for upvars, closure return types, or other unnamable + // regions. + RegionNameSource::SynthesizedFreeEnvRegion(..) + | RegionNameSource::CannotMatchHirTy(..) + | RegionNameSource::MatchedHirTy(..) + | RegionNameSource::MatchedAdtAndSegment(..) + | RegionNameSource::AnonRegionFromUpvar(..) + | RegionNameSource::AnonRegionFromOutput(..) + | RegionNameSource::AnonRegionFromYieldTy(..) => { + debug!("Region {:?} is NOT suggestable", name); + false + } + } + } + + /// Returns a name for the region if it is suggestable. See `region_name_is_suggestable`. + fn region_vid_to_name( + &self, + errctx: &ErrorReportingCtx<'_, '_, '_>, + renctx: &mut RegionErrorNamingCtx, + region: RegionVid, + ) -> Option { + errctx + .region_infcx + .give_region_a_name(errctx, renctx, region) + .filter(Self::region_name_is_suggestable) + } + + /// Compiles a list of all suggestions to be printed in the final big suggestion. + fn compile_all_suggestions<'tcx>( + &self, + body: &Body<'tcx>, + region_infcx: &RegionInferenceContext<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + renctx: &mut RegionErrorNamingCtx, + ) -> SmallVec<[SuggestedConstraint; 2]> { + let mut suggested = SmallVec::new(); + + // Keep track of variables that we have already suggested unifying so that we don't print + // out silly duplicate messages. + let mut unified_already = FxHashSet::default(); + + let errctx = ErrorReportingCtx { + region_infcx, + infcx, + body, + mir_def_id: self.mir_def_id, + + // We should not be suggesting naming upvars, so we pass in a dummy set of upvars that + // should never be used. + upvars: &[], + }; + + for (fr, outlived) in &self.constraints_to_add { + let fr_name = if let Some(fr_name) = self.region_vid_to_name(&errctx, renctx, *fr) { + fr_name + } else { + continue; + }; + + let outlived = outlived + .iter() + // if there is a `None`, we will just omit that constraint + .filter_map(|fr| { + self.region_vid_to_name(&errctx, renctx, *fr).map(|rname| (fr, rname)) + }) + .collect::>(); + + // No suggestable outlived lifetimes. + if outlived.is_empty() { + continue; + } + + // There are three types of suggestions we can make: + // 1) Suggest a bound: 'a: 'b + // 2) Suggest replacing 'a with 'static. If any of `outlived` is `'static`, then we + // should just replace 'a with 'static. + // 3) Suggest unifying 'a with 'b if we have both 'a: 'b and 'b: 'a + + if outlived.iter().any(|(_, outlived_name)| { + if let RegionNameSource::Static = outlived_name.source { + true + } else { + false + } + }) { + suggested.push(SuggestedConstraint::Static(fr_name)); + } else { + // We want to isolate out all lifetimes that should be unified and print out + // separate messages for them. + + let (unified, other): (Vec<_>, Vec<_>) = outlived.into_iter().partition( + // Do we have both 'fr: 'r and 'r: 'fr? + |(r, _)| { + self.constraints_to_add + .get(r) + .map(|r_outlived| r_outlived.as_slice().contains(fr)) + .unwrap_or(false) + }, + ); + + for (r, bound) in unified.into_iter() { + if !unified_already.contains(fr) { + suggested.push(SuggestedConstraint::Equal(fr_name.clone(), bound)); + unified_already.insert(r); + } + } + + if !other.is_empty() { + let other = + other.iter().map(|(_, rname)| rname.clone()).collect::>(); + suggested.push(SuggestedConstraint::Outlives(fr_name, other)) + } + } + } + + suggested + } + + /// Add the outlives constraint `fr: outlived_fr` to the set of constraints we need to suggest. + crate fn collect_constraint(&mut self, fr: RegionVid, outlived_fr: RegionVid) { + debug!("Collected {:?}: {:?}", fr, outlived_fr); + + // Add to set of constraints for final help note. + self.constraints_to_add.entry(fr).or_insert(Vec::new()).push(outlived_fr); + } + + /// Emit an intermediate note on the given `Diagnostic` if the involved regions are + /// suggestable. + crate fn intermediate_suggestion( + &mut self, + errctx: &ErrorReportingCtx<'_, '_, '_>, + errci: &ErrorConstraintInfo, + renctx: &mut RegionErrorNamingCtx, + diag: &mut DiagnosticBuilder<'_>, + ) { + // Emit an intermediate note. + let fr_name = self.region_vid_to_name(errctx, renctx, errci.fr); + let outlived_fr_name = self.region_vid_to_name(errctx, renctx, errci.outlived_fr); + + if let (Some(fr_name), Some(outlived_fr_name)) = (fr_name, outlived_fr_name) { + if let RegionNameSource::Static = outlived_fr_name.source { + diag.help(&format!("consider replacing `{}` with `'static`", fr_name)); + } else { + diag.help(&format!( + "consider adding the following bound: `{}: {}`", + fr_name, outlived_fr_name + )); + } + } + } + + /// If there is a suggestion to emit, add a diagnostic to the buffer. This is the final + /// suggestion including all collected constraints. + crate fn add_suggestion<'tcx>( + &self, + body: &Body<'tcx>, + region_infcx: &RegionInferenceContext<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + errors_buffer: &mut Vec, + renctx: &mut RegionErrorNamingCtx, + ) { + // No constraints to add? Done. + if self.constraints_to_add.is_empty() { + debug!("No constraints to suggest."); + return; + } + + // If there is only one constraint to suggest, then we already suggested it in the + // intermediate suggestion above. + if self.constraints_to_add.len() == 1 { + debug!("Only 1 suggestion. Skipping."); + return; + } + + // Get all suggestable constraints. + let suggested = self.compile_all_suggestions(body, region_infcx, infcx, renctx); + + // If there are no suggestable constraints... + if suggested.is_empty() { + debug!("Only 1 suggestable constraint. Skipping."); + return; + } + + // If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a + // list of diagnostics. + let mut diag = if suggested.len() == 1 { + DiagnosticBuilder::new( + infcx.tcx.sess.diagnostic(), + Level::Help, + &match suggested.last().unwrap() { + SuggestedConstraint::Outlives(a, bs) => { + let bs: SmallVec<[String; 2]> = + bs.iter().map(|r| format!("{}", r)).collect(); + format!("add bound `{}: {}`", a, bs.join(" + ")) + } + + SuggestedConstraint::Equal(a, b) => { + format!("`{}` and `{}` must be the same: replace one with the other", a, b) + } + SuggestedConstraint::Static(a) => format!("replace `{}` with `'static`", a), + }, + ) + } else { + // Create a new diagnostic. + let mut diag = DiagnosticBuilder::new( + infcx.tcx.sess.diagnostic(), + Level::Help, + "the following changes may resolve your lifetime errors", + ); + + // Add suggestions. + for constraint in suggested { + match constraint { + SuggestedConstraint::Outlives(a, bs) => { + let bs: SmallVec<[String; 2]> = + bs.iter().map(|r| format!("{}", r)).collect(); + diag.help(&format!("add bound `{}: {}`", a, bs.join(" + "))); + } + SuggestedConstraint::Equal(a, b) => { + diag.help(&format!( + "`{}` and `{}` must be the same: replace one with the other", + a, b + )); + } + SuggestedConstraint::Static(a) => { + diag.help(&format!("replace `{}` with `'static`", a)); + } + } + } + + diag + }; + + // We want this message to appear after other messages on the mir def. + let mir_span = infcx.tcx.def_span(self.mir_def_id); + diag.sort_span = mir_span.shrink_to_hi(); + + // Buffer the diagnostic + diag.buffer(errors_buffer); + } +} diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index dbb810db555..4de8200e6a0 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -11,6 +11,7 @@ use crate::borrow_check::nll::{ region_infer::values::{ PlaceholderIndices, RegionElement, ToElementIndex }, + region_infer::error_reporting::outlives_suggestion::OutlivesSuggestionBuilder, type_check::{free_region_relations::UniversalRegionRelations, Locations}, }; use crate::borrow_check::Upvar; @@ -1326,6 +1327,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { errors_buffer: &mut Vec, region_naming: &mut RegionErrorNamingCtx, ) { + let mut outlives_suggestion = OutlivesSuggestionBuilder::new(mir_def_id); + for (fr, fr_definition) in self.definitions.iter_enumerated() { match fr_definition.origin { NLLRegionVariableOrigin::FreeRegion => { @@ -1339,6 +1342,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { mir_def_id, fr, &mut propagated_outlives_requirements, + &mut outlives_suggestion, errors_buffer, region_naming, ); @@ -1353,6 +1357,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } } + + // Emit outlives suggestions + outlives_suggestion.add_suggestion(body, self, infcx, errors_buffer, region_naming); } /// Checks the final value for the free region `fr` to see if it @@ -1371,6 +1378,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { mir_def_id: DefId, longer_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec>>, + outlives_suggestion: &mut OutlivesSuggestionBuilder, errors_buffer: &mut Vec, region_naming: &mut RegionErrorNamingCtx, ) { @@ -1399,6 +1407,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { upvars, mir_def_id, propagated_outlives_requirements, + outlives_suggestion, errors_buffer, region_naming, ); @@ -1416,6 +1425,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { upvars, mir_def_id, propagated_outlives_requirements, + outlives_suggestion, errors_buffer, region_naming, ) { @@ -1438,6 +1448,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { upvars: &[Upvar], mir_def_id: DefId, propagated_outlives_requirements: &mut Option<&mut Vec>>, + outlives_suggestion: &mut OutlivesSuggestionBuilder, errors_buffer: &mut Vec, region_naming: &mut RegionErrorNamingCtx, ) -> Option { @@ -1497,6 +1508,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { longer_fr, NLLRegionVariableOrigin::FreeRegion, shorter_fr, + outlives_suggestion, region_naming, ); diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr index fa8384311ea..61f20d1dc9a 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -43,5 +43,9 @@ LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index 601b3577e0e..e34884e9f9a 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -46,5 +46,9 @@ LL | | demand_y(x, y, x.get()) LL | | }); | |______^ `cell_a` escapes the function body here +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index 5b5440e7a96..40917135c59 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -46,5 +46,9 @@ LL | | demand_y(x, y, x.get()) LL | | }); | |______^ `cell_a` escapes the function body here +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr index a08cde2c9c6..f227e9eb413 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -43,5 +43,9 @@ LL | fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { LL | demand_y(outlives1, outlives2, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr b/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr index d0a24a267fd..5e8d9fa7882 100644 --- a/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr +++ b/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr @@ -6,5 +6,9 @@ LL | fn foo<'a>(x: &'a u32) -> &'static u32 { LL | &*x | ^^^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr b/src/test/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr index 6dc98a94408..d3edbfdae88 100644 --- a/src/test/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr +++ b/src/test/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr @@ -8,5 +8,9 @@ LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'b u32 { LL | &*x | ^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + error: aborting due to previous error diff --git a/src/test/ui/nll/issue-52113.stderr b/src/test/ui/nll/issue-52113.stderr index 590963ded78..109c7e95659 100644 --- a/src/test/ui/nll/issue-52113.stderr +++ b/src/test/ui/nll/issue-52113.stderr @@ -9,5 +9,9 @@ LL | fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> i LL | x | ^ returning this value requires that `'a` must outlive `'b` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + error: aborting due to previous error diff --git a/src/test/ui/nll/issue-58299.stderr b/src/test/ui/nll/issue-58299.stderr index aba07542d02..906a7bff00d 100644 --- a/src/test/ui/nll/issue-58299.stderr +++ b/src/test/ui/nll/issue-58299.stderr @@ -7,6 +7,10 @@ LL | fn foo<'a>(x: i32) { LL | A::<'a>::X..=A::<'static>::X => (), | ^^^^^^^^^^ requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/issue-58299.rs:24:27 | @@ -16,5 +20,9 @@ LL | fn bar<'a>(x: i32) { LL | A::<'static>::X..=A::<'a>::X => (), | ^^^^^^^^^^ requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/mir_check_cast_closure.stderr b/src/test/ui/nll/mir_check_cast_closure.stderr index e14cb074c81..40ce9e850ea 100644 --- a/src/test/ui/nll/mir_check_cast_closure.stderr +++ b/src/test/ui/nll/mir_check_cast_closure.stderr @@ -9,5 +9,9 @@ LL | let g: fn(_, _) -> _ = |_x, y| y; LL | g | ^ returning this value requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'b: 'a` + error: aborting due to previous error diff --git a/src/test/ui/nll/mir_check_cast_reify.stderr b/src/test/ui/nll/mir_check_cast_reify.stderr index 4e8eec330a5..f091161b224 100644 --- a/src/test/ui/nll/mir_check_cast_reify.stderr +++ b/src/test/ui/nll/mir_check_cast_reify.stderr @@ -7,5 +7,9 @@ LL | fn bar<'a>(x: &'a u32) -> &'static u32 { LL | f(x) | ^^^^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: aborting due to previous error diff --git a/src/test/ui/nll/mir_check_cast_unsafe_fn.stderr b/src/test/ui/nll/mir_check_cast_unsafe_fn.stderr index 52959850a33..2f76758f259 100644 --- a/src/test/ui/nll/mir_check_cast_unsafe_fn.stderr +++ b/src/test/ui/nll/mir_check_cast_unsafe_fn.stderr @@ -7,5 +7,9 @@ LL | fn bar<'a>(input: &'a u32, f: fn(&'a u32) -> &'a u32) -> &'static u32 { LL | unsafe { g(input) } | ^^^^^^^^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: aborting due to previous error diff --git a/src/test/ui/nll/mir_check_cast_unsize.stderr b/src/test/ui/nll/mir_check_cast_unsize.stderr index 364d6c17ea7..4a76fa8158e 100644 --- a/src/test/ui/nll/mir_check_cast_unsize.stderr +++ b/src/test/ui/nll/mir_check_cast_unsize.stderr @@ -6,5 +6,9 @@ LL | fn bar<'a>(x: &'a u32) -> &'static dyn Debug { LL | x | ^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: aborting due to previous error diff --git a/src/test/ui/nll/outlives-suggestion-simple.rs b/src/test/ui/nll/outlives-suggestion-simple.rs new file mode 100644 index 00000000000..91a7a1d71e8 --- /dev/null +++ b/src/test/ui/nll/outlives-suggestion-simple.rs @@ -0,0 +1,77 @@ +// Test the simplest of outlives suggestions. + +#![feature(nll)] + +fn foo1<'a, 'b>(x: &'a usize) -> &'b usize { + x //~ERROR lifetime may not live long enough +} + +fn foo2<'a>(x: &'a usize) -> &'static usize { + x //~ERROR lifetime may not live long enough +} + +fn foo3<'a, 'b>(x: &'a usize, y: &'b usize) -> (&'b usize, &'a usize) { + (x, y) //~ERROR lifetime may not live long enough + //~^ERROR lifetime may not live long enough +} + +fn foo4<'a, 'b, 'c>(x: &'a usize) -> (&'b usize, &'c usize) { + // FIXME: ideally, we suggest 'a: 'b + 'c, but as of today (may 04, 2019), the null error + // reporting stops after the first error in a MIR def so as not to produce too many errors, so + // currently we only report 'a: 'b. The user would then re-run and get another error. + (x, x) //~ERROR lifetime may not live long enough +} + +struct Foo<'a> { + x: &'a usize, +} + +impl Foo<'static> { + pub fn foo<'a>(x: &'a usize) -> Self { + Foo { x } //~ERROR lifetime may not live long enough + } +} + +struct Bar<'a> { + x: &'a usize, +} + +impl<'a> Bar<'a> { + pub fn get<'b>(&self) -> &'b usize { + self.x //~ERROR lifetime may not live long enough + } +} + +// source: https://stackoverflow.com/questions/41417057/why-do-i-get-a-lifetime-error-when-i-use-a-mutable-reference-in-a-struct-instead +struct Baz<'a> { + x: &'a mut i32, +} + +impl<'a> Baz<'a> { + fn get<'b>(&'b self) -> &'a i32 { + self.x //~ERROR lifetime may not live long enough + } +} + +// source: https://stackoverflow.com/questions/41204134/rust-lifetime-error +struct Bar2<'a> { + bar: &'a str, +} +impl<'a> Bar2<'a> { + fn new(foo: &'a Foo2<'a>) -> Bar2<'a> { + Bar2 { bar: foo.raw } + } +} + +pub struct Foo2<'a> { + raw: &'a str, + cell: std::cell::Cell<&'a str>, +} +impl<'a> Foo2<'a> { + // should not produce outlives suggestions to name 'self + fn get_bar(&self) -> Bar2 { + Bar2::new(&self) //~ERROR borrowed data escapes outside of function + } +} + +fn main() {} diff --git a/src/test/ui/nll/outlives-suggestion-simple.stderr b/src/test/ui/nll/outlives-suggestion-simple.stderr new file mode 100644 index 00000000000..90c6bf2f5b8 --- /dev/null +++ b/src/test/ui/nll/outlives-suggestion-simple.stderr @@ -0,0 +1,118 @@ +error: lifetime may not live long enough + --> $DIR/outlives-suggestion-simple.rs:6:5 + | +LL | fn foo1<'a, 'b>(x: &'a usize) -> &'b usize { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | x + | ^ returning this value requires that `'a` must outlive `'b` + +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + +error: lifetime may not live long enough + --> $DIR/outlives-suggestion-simple.rs:10:5 + | +LL | fn foo2<'a>(x: &'a usize) -> &'static usize { + | -- lifetime `'a` defined here +LL | x + | ^ returning this value requires that `'a` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + +error: lifetime may not live long enough + --> $DIR/outlives-suggestion-simple.rs:14:5 + | +LL | fn foo3<'a, 'b>(x: &'a usize, y: &'b usize) -> (&'b usize, &'a usize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | (x, y) + | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + +error: lifetime may not live long enough + --> $DIR/outlives-suggestion-simple.rs:14:5 + | +LL | fn foo3<'a, 'b>(x: &'a usize, y: &'b usize) -> (&'b usize, &'a usize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | (x, y) + | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + +help: the following changes may resolve your lifetime errors + | + = help: `'a` and `'b` must be the same; replace one with the other + +error: lifetime may not live long enough + --> $DIR/outlives-suggestion-simple.rs:22:5 + | +LL | fn foo4<'a, 'b, 'c>(x: &'a usize) -> (&'b usize, &'c usize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | (x, x) + | ^^^^^^ returning this value requires that `'a` must outlive `'b` + +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + +error: lifetime may not live long enough + --> $DIR/outlives-suggestion-simple.rs:31:9 + | +LL | pub fn foo<'a>(x: &'a usize) -> Self { + | -- lifetime `'a` defined here +LL | Foo { x } + | ^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + +error: lifetime may not live long enough + --> $DIR/outlives-suggestion-simple.rs:41:9 + | +LL | impl<'a> Bar<'a> { + | -- lifetime `'a` defined here +LL | pub fn get<'b>(&self) -> &'b usize { + | -- lifetime `'b` defined here +LL | self.x + | ^^^^^^ returning this value requires that `'a` must outlive `'b` + +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + +error: lifetime may not live long enough + --> $DIR/outlives-suggestion-simple.rs:52:9 + | +LL | impl<'a> Baz<'a> { + | -- lifetime `'a` defined here +LL | fn get<'b>(&'b self) -> &'a i32 { + | -- lifetime `'b` defined here +LL | self.x + | ^^^^^^ returning this value requires that `'b` must outlive `'a` + +help: the following changes may resolve your lifetime errors + | + = help: add bound `'b: 'a` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/outlives-suggestion-simple.rs:73:9 + | +LL | fn get_bar(&self) -> Bar2 { + | ----- + | | + | `self` is declared here, outside of the function body + | `self` is a reference that is only valid in the function body +LL | Bar2::new(&self) + | ^^^^^^^^^^^^^^^^ `self` escapes the function body here + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index 10b2bd1af47..be45c23ed83 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -51,6 +51,10 @@ LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'b: 'a` + note: External requirements --> $DIR/projection-one-region-closure.rs:56:29 | @@ -105,6 +109,10 @@ LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'b: 'a` + note: External requirements --> $DIR/projection-one-region-closure.rs:70:29 | diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index b4b74bfc128..39f9e78f889 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -42,6 +42,10 @@ LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'b: 'a` + note: External requirements --> $DIR/projection-one-region-trait-bound-closure.rs:47:29 | @@ -87,6 +91,10 @@ LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'b: 'a` + note: External requirements --> $DIR/projection-one-region-trait-bound-closure.rs:60:29 | diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index a48766cd734..15e921bdec1 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -237,6 +237,10 @@ LL | fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'b: 'a` + note: External requirements --> $DIR/projection-two-region-trait-bound-closure.rs:97:29 | diff --git a/src/test/ui/nll/ty-outlives/wf-unreachable.stderr b/src/test/ui/nll/ty-outlives/wf-unreachable.stderr index 9128fd16479..e4fa647e6cb 100644 --- a/src/test/ui/nll/ty-outlives/wf-unreachable.stderr +++ b/src/test/ui/nll/ty-outlives/wf-unreachable.stderr @@ -7,6 +7,10 @@ LL | return; LL | let x: &'static &'a (); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:13:12 | @@ -16,6 +20,10 @@ LL | return; LL | let x: &'static &'a () = &&(); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:17:12 | @@ -24,6 +32,10 @@ LL | fn uninit_infer<'a>() { LL | let x: &'static &'a _; | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:23:12 | @@ -33,6 +45,10 @@ LL | return; LL | let x: &'static &'a _ = &&(); | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:28:12 | @@ -42,6 +58,10 @@ LL | return; LL | let _: &'static &'a (); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:33:12 | @@ -51,6 +71,10 @@ LL | return; LL | let _: &'static &'a () = &&(); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:38:12 | @@ -60,6 +84,10 @@ LL | return; LL | let _: &'static &'a _ = &&(); | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:51:12 | @@ -69,5 +97,9 @@ LL | return; LL | let _: C<'static, 'a, _> = C((), &(), &()); | ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: aborting due to 8 previous errors diff --git a/src/test/ui/nll/type-check-pointer-coercions.stderr b/src/test/ui/nll/type-check-pointer-coercions.stderr index 9aa78dfbd4a..9c7601c3a60 100644 --- a/src/test/ui/nll/type-check-pointer-coercions.stderr +++ b/src/test/ui/nll/type-check-pointer-coercions.stderr @@ -8,6 +8,10 @@ LL | fn shared_to_const<'a, 'b>(x: &&'a i32) -> *const &'b i32 { LL | x | ^ returning this value requires that `'a` must outlive `'b` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + error: lifetime may not live long enough --> $DIR/type-check-pointer-coercions.rs:8:5 | @@ -18,6 +22,10 @@ LL | fn unique_to_const<'a, 'b>(x: &mut &'a i32) -> *const &'b i32 { LL | x | ^ returning this value requires that `'a` must outlive `'b` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + error: lifetime may not live long enough --> $DIR/type-check-pointer-coercions.rs:13:5 | @@ -40,6 +48,10 @@ LL | // Two errors because *mut is invariant LL | x | ^ returning this value requires that `'a` must outlive `'b` +help: the following changes may resolve your lifetime errors + | + = help: `'b` and `'a` must be the same; replace one with the other + error: lifetime may not live long enough --> $DIR/type-check-pointer-coercions.rs:18:5 | @@ -50,6 +62,10 @@ LL | fn mut_to_const<'a, 'b>(x: *mut &'a i32) -> *const &'b i32 { LL | x | ^ returning this value requires that `'a` must outlive `'b` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + error: lifetime may not live long enough --> $DIR/type-check-pointer-coercions.rs:24:5 | @@ -61,6 +77,10 @@ LL | fn array_elem<'a, 'b>(x: &'a i32) -> *const &'b i32 { LL | y | ^ returning this value requires that `'a` must outlive `'b` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + error: lifetime may not live long enough --> $DIR/type-check-pointer-coercions.rs:30:5 | @@ -72,6 +92,10 @@ LL | fn array_coerce<'a, 'b>(x: &'a i32) -> *const [&'b i32; 3] { LL | y | ^ returning this value requires that `'a` must outlive `'b` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + error: lifetime may not live long enough --> $DIR/type-check-pointer-coercions.rs:36:5 | @@ -83,5 +107,9 @@ LL | fn nested_array<'a, 'b>(x: &'a i32) -> *const [&'b i32; 2] { LL | y | ^ returning this value requires that `'a` must outlive `'b` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + error: aborting due to 8 previous errors diff --git a/src/test/ui/nll/type-check-pointer-comparisons.stderr b/src/test/ui/nll/type-check-pointer-comparisons.stderr index c0a994cfb63..5293f48116e 100644 --- a/src/test/ui/nll/type-check-pointer-comparisons.stderr +++ b/src/test/ui/nll/type-check-pointer-comparisons.stderr @@ -18,6 +18,10 @@ LL | fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) { LL | x == y; | ^ requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: `'b` and `'a` must be the same; replace one with the other + error: lifetime may not live long enough --> $DIR/type-check-pointer-comparisons.rs:12:5 | @@ -38,6 +42,10 @@ LL | fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) { LL | x == y; | ^ requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: `'a` and `'b` must be the same; replace one with the other + error: lifetime may not live long enough --> $DIR/type-check-pointer-comparisons.rs:18:5 | @@ -58,5 +66,9 @@ LL | fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32 LL | f == g; | ^ requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: `'a` and `'b` must be the same; replace one with the other + error: aborting due to 6 previous errors diff --git a/src/test/ui/nll/user-annotations/closure-substs.stderr b/src/test/ui/nll/user-annotations/closure-substs.stderr index 384d53f0e4b..ff0cda9114a 100644 --- a/src/test/ui/nll/user-annotations/closure-substs.stderr +++ b/src/test/ui/nll/user-annotations/closure-substs.stderr @@ -7,6 +7,10 @@ LL | fn foo<'a>() { LL | return x; | ^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/closure-substs.rs:15:16 | @@ -24,6 +28,10 @@ LL | fn bar<'a>() { LL | b(x); | ^^^^ argument requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error[E0521]: borrowed data escapes outside of closure --> $DIR/closure-substs.rs:29:9 | diff --git a/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr b/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr index 76845469898..48d56fc1c02 100644 --- a/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr +++ b/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr @@ -6,5 +6,9 @@ LL | fn non_wf_associated_const<'a>(x: i32) { LL | A::<'a>::IC; | ^^^^^^^^^^^ requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/issue-54124.stderr b/src/test/ui/nll/user-annotations/issue-54124.stderr index 6cfccf7cb69..64df1264d27 100644 --- a/src/test/ui/nll/user-annotations/issue-54124.stderr +++ b/src/test/ui/nll/user-annotations/issue-54124.stderr @@ -16,5 +16,9 @@ LL | fn test<'a>() { LL | let _:fn(&()) = |_:&'a ()| {}; | ^ requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr index 5929707e41e..a629cc26763 100644 --- a/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr +++ b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr @@ -7,6 +7,10 @@ LL | fn coupled_regions_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { LL | y | ^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/issue-55748-pat-types-constrain-bindings.rs:49:5 | @@ -16,6 +20,10 @@ LL | fn coupled_types_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { LL | y | ^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/issue-55748-pat-types-constrain-bindings.rs:62:5 | @@ -25,5 +33,9 @@ LL | fn coupled_wilds_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { LL | y | ^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: aborting due to 3 previous errors diff --git a/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr b/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr index c99f53c5aa4..937db377573 100644 --- a/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr +++ b/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr @@ -7,6 +7,10 @@ LL | let ((y, _z),) = ((s, _x),): (PairCoupledTypes<_>,); LL | y | ^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/issue-57731-ascibed-coupled-types.rs:22:5 | @@ -16,6 +20,10 @@ LL | let ((y, _z),) = ((s, _x),): (PairCoupledRegions<_>,); LL | y | ^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/issue-57731-ascibed-coupled-types.rs:32:5 | @@ -25,6 +33,10 @@ LL | let ((y, _z),) = ((s, _x),) as (PairCoupledTypes<_>,); LL | y | ^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/issue-57731-ascibed-coupled-types.rs:37:5 | @@ -34,5 +46,9 @@ LL | let ((y, _z),) = ((s, _x),) as (PairCoupledRegions<_>,); LL | y | ^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: aborting due to 4 previous errors diff --git a/src/test/ui/nll/user-annotations/patterns.stderr b/src/test/ui/nll/user-annotations/patterns.stderr index 7ebd0ae227a..981e59c08c5 100644 --- a/src/test/ui/nll/user-annotations/patterns.stderr +++ b/src/test/ui/nll/user-annotations/patterns.stderr @@ -157,6 +157,10 @@ LL | fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 { LL | y | ^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/patterns.rs:125:5 | @@ -166,6 +170,10 @@ LL | fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 { LL | y | ^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/patterns.rs:130:5 | @@ -175,6 +183,10 @@ LL | let Single { value: y }: Single<&'a u32> = Single { value: &22 }; LL | y | ^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: lifetime may not live long enough --> $DIR/patterns.rs:134:18 | @@ -183,6 +195,10 @@ LL | fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 { LL | let (y, _z): (&'static u32, u32) = (x, 44); | ^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error: aborting due to 19 previous errors Some errors have detailed explanations: E0597, E0716. diff --git a/src/test/ui/nll/user-annotations/wf-self-type.stderr b/src/test/ui/nll/user-annotations/wf-self-type.stderr index 8f8e1bc28f6..c3b32865b01 100644 --- a/src/test/ui/nll/user-annotations/wf-self-type.stderr +++ b/src/test/ui/nll/user-annotations/wf-self-type.stderr @@ -8,5 +8,9 @@ LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () { LL | Foo::xmute(u) | ^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'b: 'a` + error: aborting due to previous error diff --git a/src/test/ui/nll/where_clauses_in_functions.stderr b/src/test/ui/nll/where_clauses_in_functions.stderr index f3b65ec31ac..c01101cf1f6 100644 --- a/src/test/ui/nll/where_clauses_in_functions.stderr +++ b/src/test/ui/nll/where_clauses_in_functions.stderr @@ -8,5 +8,9 @@ LL | fn bar<'a, 'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) { LL | foo(x, y) | ^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + error: aborting due to previous error diff --git a/src/test/ui/nll/where_clauses_in_structs.stderr b/src/test/ui/nll/where_clauses_in_structs.stderr index e0feb40273f..aa15aa4ddca 100644 --- a/src/test/ui/nll/where_clauses_in_structs.stderr +++ b/src/test/ui/nll/where_clauses_in_structs.stderr @@ -8,5 +8,9 @@ LL | fn bar<'a, 'b>(x: Cell<&'a u32>, y: Cell<&'b u32>) { LL | Foo { x, y }; | ^ requires that `'a` must outlive `'b` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + error: aborting due to previous error diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr index 4944f2649b7..79ea4caa343 100644 --- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr +++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr @@ -9,5 +9,9 @@ LL | fn with_assoc<'a,'b>() { LL | let _: &'a WithAssoc> = loop { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'b: 'a` + error: aborting due to previous error diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr index 16eda2844c6..594ea755e3d 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr @@ -8,6 +8,10 @@ LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { LL | let z: Option<&'b &'a usize> = None; | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + error: lifetime may not live long enough --> $DIR/regions-free-region-ordering-caller.rs:17:12 | @@ -19,6 +23,10 @@ LL | let y: Paramd<'a> = Paramd { x: a }; LL | let z: Option<&'b Paramd<'a>> = None; | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'b` + error: lifetime may not live long enough --> $DIR/regions-free-region-ordering-caller.rs:22:12 | @@ -29,5 +37,9 @@ LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { LL | let z: Option<&'a &'b usize> = None; | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'b: 'a` + error: aborting due to 3 previous errors diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr index eed9934be12..fb836d32a2b 100644 --- a/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr +++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr @@ -9,6 +9,10 @@ LL | fn with_assoc<'a,'b>() { LL | let _: &'a WithHrAssoc> = loop { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'b: 'a` + error: lifetime may not live long enough --> $DIR/regions-outlives-projection-container-hrtb.rs:50:12 | @@ -20,5 +24,9 @@ LL | fn with_assoc_sub<'a,'b>() { LL | let _: &'a WithHrAssocSub> = loop { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'b: 'a` + error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr index 8c54d8da0a0..3f5088c12d6 100644 --- a/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr +++ b/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr @@ -9,5 +9,9 @@ LL | fn with_assoc<'a,'b>() { LL | let _: &'a WithAssoc> = loop { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` +help: the following changes may resolve your lifetime errors + | + = help: add bound `'b: 'a` + error: aborting due to previous error diff --git a/src/test/ui/regions/regions-static-bound.nll.stderr b/src/test/ui/regions/regions-static-bound.nll.stderr index b5f3e6cfaba..281683ac1da 100644 --- a/src/test/ui/regions/regions-static-bound.nll.stderr +++ b/src/test/ui/regions/regions-static-bound.nll.stderr @@ -6,6 +6,10 @@ LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { LL | t | ^ returning this value requires that `'a` must outlive `'static` +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + error[E0621]: explicit lifetime required in the type of `u` --> $DIR/regions-static-bound.rs:14:5 |