1
Fork 0

Improved closure errors.

This commit is contained in:
David Wood 2018-07-20 17:30:31 +01:00
parent 24c5751197
commit 571eec627c
No known key found for this signature in database
GPG key ID: 01760B4F9F53F154
11 changed files with 299 additions and 131 deletions

View file

@ -119,6 +119,37 @@ impl<'tcx> Place<'tcx> {
proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem), proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem),
} }
} }
/// If this is a field projection, and the field is being projected from a closure type,
/// then returns the index of the field being projected. Note that this closure will always
/// be `self` in the current MIR, because that is the only time we directly access the fields
/// of a closure type.
pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>,
tcx: &TyCtxt<'cx, 'gcx, 'tcx>,
recurse: bool) -> Option<Field> {
match *self {
Place::Projection(ref proj) => match proj.elem {
ProjectionElem::Field(field, _ty) => {
let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx);
if base_ty.is_closure() || base_ty.is_generator() {
Some(field)
} else {
None
}
},
ProjectionElem::Deref => {
if recurse {
proj.base.is_upvar_field_projection(mir, tcx, recurse)
} else {
None
}
},
_ => None,
},
_ => None,
}
}
} }
pub enum RvalueInitializationState { pub enum RvalueInitializationState {

View file

@ -726,7 +726,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Place::Projection(ref proj) => { Place::Projection(ref proj) => {
match proj.elem { match proj.elem {
ProjectionElem::Deref => { ProjectionElem::Deref => {
if let Some(field) = self.is_upvar_field_projection(&proj.base) { let upvar_field_projection = proj.base.is_upvar_field_projection(
self.mir, &self.tcx, false);
if let Some(field) = upvar_field_projection {
let var_index = field.index(); let var_index = field.index();
let name = self.mir.upvar_decls[var_index].debug_name.to_string(); let name = self.mir.upvar_decls[var_index].debug_name.to_string();
if self.mir.upvar_decls[var_index].by_ref { if self.mir.upvar_decls[var_index].by_ref {
@ -785,7 +787,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
ProjectionElem::Field(field, _ty) => { ProjectionElem::Field(field, _ty) => {
autoderef = true; autoderef = true;
if let Some(field) = self.is_upvar_field_projection(place) { let upvar_field_projection = place.is_upvar_field_projection(
self.mir, &self.tcx, false);
if let Some(field) = upvar_field_projection {
let var_index = field.index(); let var_index = field.index();
let name = self.mir.upvar_decls[var_index].debug_name.to_string(); let name = self.mir.upvar_decls[var_index].debug_name.to_string();
buf.push_str(&name); buf.push_str(&name);

View file

@ -1214,7 +1214,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
} }
Operand::Move(ref place @ Place::Projection(_)) Operand::Move(ref place @ Place::Projection(_))
| Operand::Copy(ref place @ Place::Projection(_)) => { | Operand::Copy(ref place @ Place::Projection(_)) => {
if let Some(field) = self.is_upvar_field_projection(place) { if let Some(field) = place.is_upvar_field_projection(
self.mir, &self.tcx, false) {
self.used_mut_upvars.push(field); self.used_mut_upvars.push(field);
} }
} }
@ -1803,7 +1804,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
place: place @ Place::Projection(_), place: place @ Place::Projection(_),
is_local_mutation_allowed: _, is_local_mutation_allowed: _,
} => { } => {
if let Some(field) = self.is_upvar_field_projection(&place) { if let Some(field) = place.is_upvar_field_projection(self.mir, &self.tcx, false) {
self.used_mut_upvars.push(field); self.used_mut_upvars.push(field);
} }
} }
@ -1866,7 +1867,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// Mutably borrowed data is mutable, but only if we have a // Mutably borrowed data is mutable, but only if we have a
// unique path to the `&mut` // unique path to the `&mut`
hir::MutMutable => { hir::MutMutable => {
let mode = match self.is_upvar_field_projection(&proj.base) let mode = match proj.base.is_upvar_field_projection(
self.mir, &self.tcx, false)
{ {
Some(field) Some(field)
if { if {
@ -1911,7 +1913,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..) => { | ProjectionElem::Downcast(..) => {
if let Some(field) = self.is_upvar_field_projection(place) { let upvar_field_projection = place.is_upvar_field_projection(
self.mir, &self.tcx, false);
if let Some(field) = upvar_field_projection {
let decl = &self.mir.upvar_decls[field.index()]; let decl = &self.mir.upvar_decls[field.index()];
debug!( debug!(
"decl.mutability={:?} local_mutation_is_allowed={:?} place={:?}", "decl.mutability={:?} local_mutation_is_allowed={:?} place={:?}",
@ -1965,28 +1969,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
} }
} }
} }
/// If this is a field projection, and the field is being projected from a closure type,
/// then returns the index of the field being projected. Note that this closure will always
/// be `self` in the current MIR, because that is the only time we directly access the fields
/// of a closure type.
fn is_upvar_field_projection(&self, place: &Place<'tcx>) -> Option<Field> {
match *place {
Place::Projection(ref proj) => match proj.elem {
ProjectionElem::Field(field, _ty) => {
let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
if base_ty.is_closure() || base_ty.is_generator() {
Some(field)
} else {
None
}
}
_ => None,
},
_ => None,
}
}
} }
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]

View file

@ -22,6 +22,7 @@ use std::fmt;
use syntax_pos::Span; use syntax_pos::Span;
mod region_name; mod region_name;
mod var_name;
/// Constraints that are considered interesting can be categorized to /// Constraints that are considered interesting can be categorized to
/// determine why they are interesting. Order of variants indicates /// determine why they are interesting. Order of variants indicates
@ -30,6 +31,7 @@ mod region_name;
enum ConstraintCategory { enum ConstraintCategory {
Cast, Cast,
Assignment, Assignment,
AssignmentToUpvar,
Return, Return,
CallArgument, CallArgument,
Other, Other,
@ -39,7 +41,8 @@ enum ConstraintCategory {
impl fmt::Display for ConstraintCategory { impl fmt::Display for ConstraintCategory {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
ConstraintCategory::Assignment => write!(f, "assignment"), ConstraintCategory::Assignment |
ConstraintCategory::AssignmentToUpvar => write!(f, "assignment"),
ConstraintCategory::Return => write!(f, "return"), ConstraintCategory::Return => write!(f, "return"),
ConstraintCategory::Cast => write!(f, "cast"), ConstraintCategory::Cast => write!(f, "cast"),
ConstraintCategory::CallArgument => write!(f, "argument"), ConstraintCategory::CallArgument => write!(f, "argument"),
@ -130,6 +133,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
&self, &self,
index: ConstraintIndex, index: ConstraintIndex,
mir: &Mir<'tcx>, mir: &Mir<'tcx>,
infcx: &InferCtxt<'_, '_, 'tcx>,
) -> (ConstraintCategory, Span) { ) -> (ConstraintCategory, Span) {
let constraint = self.constraints[index]; let constraint = self.constraints[index];
debug!("classify_constraint: constraint={:?}", constraint); debug!("classify_constraint: constraint={:?}", constraint);
@ -159,7 +163,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
match statement.kind { match statement.kind {
StatementKind::Assign(ref place, ref rvalue) => { StatementKind::Assign(ref place, ref rvalue) => {
debug!("classify_constraint: place={:?} rvalue={:?}", place, rvalue); debug!("classify_constraint: place={:?} rvalue={:?}", place, rvalue);
if *place == Place::Local(mir::RETURN_PLACE) { let initial_category = if *place == Place::Local(mir::RETURN_PLACE) {
ConstraintCategory::Return ConstraintCategory::Return
} else { } else {
match rvalue { match rvalue {
@ -168,6 +172,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
Rvalue::Aggregate(..) => ConstraintCategory::Assignment, Rvalue::Aggregate(..) => ConstraintCategory::Assignment,
_ => ConstraintCategory::Other, _ => ConstraintCategory::Other,
} }
};
if initial_category == ConstraintCategory::Assignment
&& place.is_upvar_field_projection(mir, &infcx.tcx, true).is_some() {
ConstraintCategory::AssignmentToUpvar
} else {
initial_category
} }
} }
_ => ConstraintCategory::Other, _ => ConstraintCategory::Other,
@ -214,7 +225,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// Classify each of the constraints along the path. // Classify each of the constraints along the path.
let mut categorized_path: Vec<(ConstraintCategory, Span)> = path.iter() let mut categorized_path: Vec<(ConstraintCategory, Span)> = path.iter()
.map(|&index| self.classify_constraint(index, mir)) .map(|&index| self.classify_constraint(index, mir, infcx))
.collect(); .collect();
debug!("report_error: categorized_path={:?}", categorized_path); debug!("report_error: categorized_path={:?}", categorized_path);
@ -224,30 +235,75 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// Get a span // Get a span
let (category, span) = categorized_path.first().unwrap(); let (category, span) = categorized_path.first().unwrap();
match category {
ConstraintCategory::AssignmentToUpvar =>
self.report_closure_error(mir, infcx, fr, outlived_fr, span),
_ =>
self.report_general_error(mir, infcx, mir_def_id, fr, outlived_fr, category, span),
}
}
fn report_closure_error(
&self,
mir: &Mir<'tcx>,
infcx: &InferCtxt<'_, '_, 'tcx>,
fr: RegionVid,
outlived_fr: RegionVid,
span: &Span,
) {
let diag = &mut infcx.tcx.sess.struct_span_err( let diag = &mut infcx.tcx.sess.struct_span_err(
*span, *span, &format!("borrowed data escapes outside of closure"),
&format!("unsatisfied lifetime constraints"), // FIXME );
let (outlived_fr_name, outlived_fr_span) = self.get_var_name_and_span_for_region(
infcx.tcx, mir, outlived_fr);
if let Some(name) = outlived_fr_name {
diag.span_label(
outlived_fr_span,
format!("`{}` is declared here, outside of the closure body", name),
);
}
let (fr_name, fr_span) = self.get_var_name_and_span_for_region(infcx.tcx, mir, fr);
if let Some(name) = fr_name {
diag.span_label(
fr_span,
format!("`{}` is a reference that is only valid in the closure body", name),
);
diag.span_label(*span, format!("`{}` escapes the closure body here", name));
}
diag.emit();
}
fn report_general_error(
&self,
mir: &Mir<'tcx>,
infcx: &InferCtxt<'_, '_, 'tcx>,
mir_def_id: DefId,
fr: RegionVid,
outlived_fr: RegionVid,
category: &ConstraintCategory,
span: &Span,
) {
let diag = &mut infcx.tcx.sess.struct_span_err(
*span, &format!("unsatisfied lifetime constraints"), // FIXME
); );
// Figure out how we can refer
let counter = &mut 1; let counter = &mut 1;
let fr_name = self.give_region_a_name(infcx.tcx, mir, mir_def_id, fr, counter, diag); let fr_name = self.give_region_a_name(
infcx.tcx, mir, mir_def_id, fr, counter, diag);
let outlived_fr_name = self.give_region_a_name( let outlived_fr_name = self.give_region_a_name(
infcx.tcx, infcx.tcx, mir, mir_def_id, outlived_fr, counter, diag);
mir,
mir_def_id,
outlived_fr,
counter,
diag,
);
diag.span_label( diag.span_label(*span, format!(
*span, "{} requires that `{}` must outlive `{}`",
format!( category, fr_name, outlived_fr_name,
"{} requires that `{}` must outlive `{}`", ));
category, fr_name, outlived_fr_name,
),
);
diag.emit(); diag.emit();
} }

View file

@ -12,10 +12,9 @@ use borrow_check::nll::region_infer::RegionInferenceContext;
use borrow_check::nll::ToRegionVid; use borrow_check::nll::ToRegionVid;
use rustc::hir; use rustc::hir;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::mir::{Local, Mir}; use rustc::mir::Mir;
use rustc::ty::subst::{Substs, UnpackedKind}; use rustc::ty::subst::{Substs, UnpackedKind};
use rustc::ty::{self, RegionVid, Ty, TyCtxt}; use rustc::ty::{self, RegionVid, Ty, TyCtxt};
use rustc_data_structures::indexed_vec::Idx;
use rustc_errors::DiagnosticBuilder; use rustc_errors::DiagnosticBuilder;
use syntax::ast::Name; use syntax::ast::Name;
use syntax::symbol::keywords; use syntax::symbol::keywords;
@ -63,11 +62,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.give_name_from_error_region(tcx, mir_def_id, fr, counter, diag) self.give_name_from_error_region(tcx, mir_def_id, fr, counter, diag)
.or_else(|| { .or_else(|| {
self.give_name_if_anonymous_region_appears_in_arguments( self.give_name_if_anonymous_region_appears_in_arguments(
tcx, mir, mir_def_id, fr, counter, diag, tcx, mir, mir_def_id, fr, counter, diag)
)
}) })
.or_else(|| { .or_else(|| {
self.give_name_if_anonymous_region_appears_in_upvars(tcx, mir, fr, counter, diag) self.give_name_if_anonymous_region_appears_in_upvars(
tcx, mir, fr, counter, diag)
}) })
.or_else(|| { .or_else(|| {
self.give_name_if_anonymous_region_appears_in_output(tcx, mir, fr, counter, diag) self.give_name_if_anonymous_region_appears_in_output(tcx, mir, fr, counter, diag)
@ -139,24 +138,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
diag: &mut DiagnosticBuilder<'_>, diag: &mut DiagnosticBuilder<'_>,
) -> Option<InternedString> { ) -> Option<InternedString> {
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs(); let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
let argument_index = self let argument_index = self.get_argument_index_for_region(tcx, fr)?;
.universal_regions
.unnormalized_input_tys
.iter()
.skip(implicit_inputs)
.position(|arg_ty| {
debug!(
"give_name_if_anonymous_region_appears_in_arguments: arg_ty = {:?}",
arg_ty
);
tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr)
})?;
debug!(
"give_name_if_anonymous_region_appears_in_arguments: \
found {:?} in argument {} which has type {:?}",
fr, argument_index, self.universal_regions.unnormalized_input_tys[argument_index],
);
let arg_ty = let arg_ty =
self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index]; self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index];
@ -172,10 +154,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
return Some(region_name); return Some(region_name);
} }
let (_argument_name, argument_span) = self.get_argument_name_and_span_for_region(
mir, argument_index);
let region_name = self.synthesize_region_name(counter); let region_name = self.synthesize_region_name(counter);
let argument_local = Local::new(argument_index + implicit_inputs + 1);
let argument_span = mir.local_decls[argument_local].source_info.span;
diag.span_label( diag.span_label(
argument_span, argument_span,
format!("lifetime `{}` appears in this argument", region_name,), format!("lifetime `{}` appears in this argument", region_name,),
@ -440,41 +423,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
counter: &mut usize, counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>, diag: &mut DiagnosticBuilder<'_>,
) -> Option<InternedString> { ) -> Option<InternedString> {
let upvar_index = self let upvar_index = self.get_upvar_index_for_region(tcx, fr)?;
.universal_regions let (upvar_name, upvar_span) = self.get_upvar_name_and_span_for_region(tcx, mir,
.defining_ty upvar_index);
.upvar_tys(tcx)
.position(|upvar_ty| {
debug!(
"give_name_if_anonymous_region_appears_in_upvars: upvar_ty = {:?}",
upvar_ty,
);
tcx.any_free_region_meets(&upvar_ty, |r| r.to_region_vid() == fr)
})?;
let upvar_ty = self
.universal_regions
.defining_ty
.upvar_tys(tcx)
.nth(upvar_index);
debug!(
"give_name_if_anonymous_region_appears_in_upvars: \
found {:?} in upvar {} which has type {:?}",
fr, upvar_index, upvar_ty,
);
let region_name = self.synthesize_region_name(counter); let region_name = self.synthesize_region_name(counter);
let upvar_hir_id = mir.upvar_decls[upvar_index].var_hir_id.assert_crate_local();
let upvar_node_id = tcx.hir.hir_to_node_id(upvar_hir_id);
let upvar_span = tcx.hir.span(upvar_node_id);
let upvar_name = tcx.hir.name(upvar_node_id);
diag.span_label( diag.span_label(
upvar_span, upvar_span,
format!( format!(
"lifetime `{}` appears in the type of `{}`", "lifetime `{}` appears in the type of `{}`",
region_name, upvar_name, region_name, upvar_name.unwrap(),
), ),
); );

View file

@ -0,0 +1,137 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use borrow_check::nll::region_infer::RegionInferenceContext;
use borrow_check::nll::ToRegionVid;
use rustc::mir::{Local, Mir};
use rustc::ty::{RegionVid, TyCtxt};
use rustc_data_structures::indexed_vec::Idx;
use syntax::codemap::Span;
use syntax_pos::symbol::Symbol;
impl<'tcx> RegionInferenceContext<'tcx> {
crate fn get_var_name_and_span_for_region(
&self,
tcx: TyCtxt<'_, '_, 'tcx>,
mir: &Mir<'tcx>,
fr: RegionVid,
) -> (Option<Symbol>, Span) {
debug!("get_var_name_and_span_for_region(fr={:?})", fr);
assert!(self.universal_regions.is_universal_region(fr));
debug!("get_var_name_and_span_for_region: attempting upvar");
self.get_upvar_index_for_region(tcx, fr)
.map(|index| self.get_upvar_name_and_span_for_region(tcx, mir, index))
.or_else(|| {
debug!("get_var_name_and_span_for_region: attempting argument");
self.get_argument_index_for_region(tcx, fr)
.map(|index| self.get_argument_name_and_span_for_region(mir, index))
})
.unwrap_or_else(|| span_bug!(mir.span, "can't find var name for free region {:?}", fr))
}
/// Get upvar index for a region.
crate fn get_upvar_index_for_region(
&self,
tcx: TyCtxt<'_, '_, 'tcx>,
fr: RegionVid,
) -> Option<usize> {
let upvar_index = self
.universal_regions
.defining_ty
.upvar_tys(tcx)
.position(|upvar_ty| {
debug!(
"get_upvar_index_for_region: upvar_ty = {:?}",
upvar_ty,
);
tcx.any_free_region_meets(&upvar_ty, |r| r.to_region_vid() == fr)
})?;
let upvar_ty = self
.universal_regions
.defining_ty
.upvar_tys(tcx)
.nth(upvar_index);
debug!(
"get_upvar_index_for_region: found {:?} in upvar {} which has type {:?}",
fr, upvar_index, upvar_ty,
);
Some(upvar_index)
}
/// Get upvar name and span for a region.
crate fn get_upvar_name_and_span_for_region(
&self,
tcx: TyCtxt<'_, '_, 'tcx>,
mir: &Mir<'tcx>,
upvar_index: usize,
) -> (Option<Symbol>, Span) {
let upvar_hir_id = mir.upvar_decls[upvar_index].var_hir_id.assert_crate_local();
let upvar_node_id = tcx.hir.hir_to_node_id(upvar_hir_id);
debug!("get_upvar_name_and_span_for_region: upvar_node_id={:?}", upvar_node_id);
let upvar_name = tcx.hir.name(upvar_node_id);
let upvar_span = tcx.hir.span(upvar_node_id);
debug!("get_upvar_name_and_span_for_region: upvar_name={:?} upvar_span={:?}",
upvar_name, upvar_span);
(Some(upvar_name), upvar_span)
}
/// Get argument index for a region.
crate fn get_argument_index_for_region(
&self,
tcx: TyCtxt<'_, '_, 'tcx>,
fr: RegionVid,
) -> Option<usize> {
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
let argument_index = self
.universal_regions
.unnormalized_input_tys
.iter()
.skip(implicit_inputs)
.position(|arg_ty| {
debug!(
"get_argument_index_for_region: arg_ty = {:?}",
arg_ty
);
tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr)
})?;
debug!(
"get_argument_index_for_region: found {:?} in argument {} which has type {:?}",
fr, argument_index, self.universal_regions.unnormalized_input_tys[argument_index],
);
Some(argument_index)
}
/// Get argument name and span for a region.
crate fn get_argument_name_and_span_for_region(
&self,
mir: &Mir<'tcx>,
argument_index: usize,
) -> (Option<Symbol>, Span) {
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
let argument_local = Local::new(implicit_inputs + argument_index + 1);
debug!("get_argument_name_and_span_for_region: argument_local={:?}", argument_local);
let argument_name = mir.local_decls[argument_local].name;
let argument_span = mir.local_decls[argument_local].source_info.span;
debug!("get_argument_name_and_span_for_region: argument_name={:?} argument_span={:?}",
argument_name, argument_span);
(argument_name, argument_span)
}
}

View file

@ -4,15 +4,15 @@ warning: not reporting region error due to nll
LL | give_any(|y| x = Some(y)); LL | give_any(|y| x = Some(y));
| ^ | ^
error: unsatisfied lifetime constraints error: borrowed data escapes outside of closure
--> $DIR/issue-45983.rs:17:18 --> $DIR/issue-45983.rs:17:18
| |
LL | let x = None; LL | let x = None;
| - lifetime `'2` appears in the type of `x` | - `x` is declared here, outside of the closure body
LL | give_any(|y| x = Some(y)); LL | give_any(|y| x = Some(y));
| - ^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` | - ^^^^^^^^^^^ `y` escapes the closure body here
| | | |
| lifetime `'1` appears in this argument | `y` is a reference that is only valid in the closure body
error[E0594]: cannot assign to `x`, as it is not declared as mutable error[E0594]: cannot assign to `x`, as it is not declared as mutable
--> $DIR/issue-45983.rs:17:18 --> $DIR/issue-45983.rs:17:18

View file

@ -4,15 +4,15 @@ warning: not reporting region error due to nll
LL | with_int(|y| x = Some(y)); LL | with_int(|y| x = Some(y));
| ^ | ^
error: unsatisfied lifetime constraints error: borrowed data escapes outside of closure
--> $DIR/regions-escape-bound-fn-2.rs:18:18 --> $DIR/regions-escape-bound-fn-2.rs:18:18
| |
LL | let mut x = None; LL | let mut x = None;
| ----- lifetime `'2` appears in the type of `x` | ----- `x` is declared here, outside of the closure body
LL | with_int(|y| x = Some(y)); LL | with_int(|y| x = Some(y));
| - ^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` | - ^^^^^^^^^^^ `y` escapes the closure body here
| | | |
| lifetime `'1` appears in this argument | `y` is a reference that is only valid in the closure body
error: aborting due to previous error error: aborting due to previous error

View file

@ -4,15 +4,15 @@ warning: not reporting region error due to nll
LL | with_int(|y| x = Some(y)); LL | with_int(|y| x = Some(y));
| ^^^^^^^ | ^^^^^^^
error: unsatisfied lifetime constraints error: borrowed data escapes outside of closure
--> $DIR/regions-escape-bound-fn.rs:18:18 --> $DIR/regions-escape-bound-fn.rs:18:18
| |
LL | let mut x: Option<&isize> = None; LL | let mut x: Option<&isize> = None;
| ----- lifetime `'2` appears in the type of `x` | ----- `x` is declared here, outside of the closure body
LL | with_int(|y| x = Some(y)); LL | with_int(|y| x = Some(y));
| - ^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` | - ^^^^^^^^^^^ `y` escapes the closure body here
| | | |
| lifetime `'1` appears in this argument | `y` is a reference that is only valid in the closure body
error: aborting due to previous error error: aborting due to previous error

View file

@ -4,15 +4,15 @@ warning: not reporting region error due to nll
LL | with_int(&mut |y| x = Some(y)); LL | with_int(&mut |y| x = Some(y));
| ^^^^^^^ | ^^^^^^^
error: unsatisfied lifetime constraints error: borrowed data escapes outside of closure
--> $DIR/regions-escape-unboxed-closure.rs:16:23 --> $DIR/regions-escape-unboxed-closure.rs:16:23
| |
LL | let mut x: Option<&isize> = None; LL | let mut x: Option<&isize> = None;
| ----- lifetime `'2` appears in the type of `x` | ----- `x` is declared here, outside of the closure body
LL | with_int(&mut |y| x = Some(y)); LL | with_int(&mut |y| x = Some(y));
| - ^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` | - ^^^^^^^^^^^ `y` escapes the closure body here
| | | |
| lifetime `'1` appears in this argument | `y` is a reference that is only valid in the closure body
error: aborting due to previous error error: aborting due to previous error

View file

@ -22,37 +22,37 @@ warning: not reporting region error due to nll
LL | f = Some(x); LL | f = Some(x);
| ^^^^^^^ | ^^^^^^^
error: unsatisfied lifetime constraints error: borrowed data escapes outside of closure
--> $DIR/expect-region-supply-region.rs:28:9 --> $DIR/expect-region-supply-region.rs:28:9
| |
LL | let mut f: Option<&u32> = None; LL | let mut f: Option<&u32> = None;
| ----- lifetime `'2` appears in the type of `f` | ----- `f` is declared here, outside of the closure body
LL | closure_expecting_bound(|x| { LL | closure_expecting_bound(|x| {
| - lifetime `'1` appears in this argument | - `x` is a reference that is only valid in the closure body
LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
| ^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` | ^^^^^^^^^^^ `x` escapes the closure body here
error: unsatisfied lifetime constraints error: borrowed data escapes outside of closure
--> $DIR/expect-region-supply-region.rs:38:9 --> $DIR/expect-region-supply-region.rs:38:9
| |
LL | let mut f: Option<&u32> = None; LL | let mut f: Option<&u32> = None;
| ----- lifetime `'2` appears in the type of `f` | ----- `f` is declared here, outside of the closure body
LL | closure_expecting_bound(|x: &u32| { LL | closure_expecting_bound(|x: &u32| {
| - let's call the lifetime of this reference `'1` | - `x` is a reference that is only valid in the closure body
LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
| ^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` | ^^^^^^^^^^^ `x` escapes the closure body here
error: unsatisfied lifetime constraints error: borrowed data escapes outside of closure
--> $DIR/expect-region-supply-region.rs:52:9 --> $DIR/expect-region-supply-region.rs:52:9
| |
LL | let mut f: Option<&u32> = None; LL | let mut f: Option<&u32> = None;
| ----- lifetime `'2` appears in the type of `f` | ----- `f` is declared here, outside of the closure body
... ...
LL | closure_expecting_bound(|x: &'x u32| { LL | closure_expecting_bound(|x: &'x u32| {
| - let's call the lifetime of this reference `'1` | - `x` is a reference that is only valid in the closure body
... ...
LL | f = Some(x); LL | f = Some(x);
| ^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` | ^^^^^^^^^^^ `x` escapes the closure body here
error: aborting due to 3 previous errors error: aborting due to 3 previous errors