implement outlive suggestions

This commit is contained in:
Mark Mansi 2018-11-28 15:05:36 -06:00
parent b7176b44a2
commit 3a1847b07d
39 changed files with 807 additions and 6 deletions

View File

@ -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<SubDiagnostic>,
pub suggestions: Vec<CodeSuggestion>,
/// 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<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
self.span = sp.into();
if let Some(span) = self.span.primary_span() {
self.sort_span = span;
}
self
}

View File

@ -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);

View File

@ -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
}
}
}

View File

@ -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<RegionVid, Vec<RegionVid>>,
}
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<RegionName> {
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::<Vec<_>>();
// 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::<SmallVec<_>>();
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<Diagnostic>,
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);
}
}

View File

@ -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<Diagnostic>,
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<ClosureOutlivesRequirement<'tcx>>>,
outlives_suggestion: &mut OutlivesSuggestionBuilder,
errors_buffer: &mut Vec<Diagnostic>,
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<ClosureOutlivesRequirement<'tcx>>>,
outlives_suggestion: &mut OutlivesSuggestionBuilder,
errors_buffer: &mut Vec<Diagnostic>,
region_naming: &mut RegionErrorNamingCtx,
) -> Option<ErrorReported> {
@ -1497,6 +1508,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
longer_fr,
NLLRegionVariableOrigin::FreeRegion,
shorter_fr,
outlives_suggestion,
region_naming,
);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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
|

View File

@ -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
|

View File

@ -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
|

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
|

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -9,5 +9,9 @@ LL | fn with_assoc<'a,'b>() {
LL | let _: &'a WithAssoc<TheType<'b>> = 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

View File

@ -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

View File

@ -9,6 +9,10 @@ LL | fn with_assoc<'a,'b>() {
LL | let _: &'a WithHrAssoc<TheType<'b>> = 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<TheType<'b>> = 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

View File

@ -9,5 +9,9 @@ LL | fn with_assoc<'a,'b>() {
LL | let _: &'a WithAssoc<TheType<'b>> = 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

View File

@ -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
|