Auto merge of #52572 - davidtwco:issue-51027, r=nikomatsakis
NLL diagnostics replaced nice closure errors w/ indecipherable free region errors Fixes #51027. r? @nikomatsakis
This commit is contained in:
commit
32772fddd5
19 changed files with 367 additions and 157 deletions
|
|
@ -119,6 +119,39 @@ impl<'tcx> Place<'tcx> {
|
|||
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>) -> Option<Field> {
|
||||
let place = if let Place::Projection(ref proj) = self {
|
||||
if let ProjectionElem::Deref = proj.elem {
|
||||
&proj.base
|
||||
} else {
|
||||
self
|
||||
}
|
||||
} else {
|
||||
self
|
||||
};
|
||||
|
||||
match place {
|
||||
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
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum RvalueInitializationState {
|
||||
|
|
|
|||
|
|
@ -726,7 +726,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
Place::Projection(ref proj) => {
|
||||
match proj.elem {
|
||||
ProjectionElem::Deref => {
|
||||
if let Some(field) = self.is_upvar_field_projection(&proj.base) {
|
||||
let upvar_field_projection = place.is_upvar_field_projection(
|
||||
self.mir, &self.tcx);
|
||||
if let Some(field) = upvar_field_projection {
|
||||
let var_index = field.index();
|
||||
let name = self.mir.upvar_decls[var_index].debug_name.to_string();
|
||||
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) => {
|
||||
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);
|
||||
if let Some(field) = upvar_field_projection {
|
||||
let var_index = field.index();
|
||||
let name = self.mir.upvar_decls[var_index].debug_name.to_string();
|
||||
buf.push_str(&name);
|
||||
|
|
|
|||
|
|
@ -1214,7 +1214,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
Operand::Move(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) {
|
||||
self.used_mut_upvars.push(field);
|
||||
}
|
||||
}
|
||||
|
|
@ -1803,7 +1804,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
place: place @ Place::Projection(_),
|
||||
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) {
|
||||
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
|
||||
// unique path to the `&mut`
|
||||
hir::MutMutable => {
|
||||
let mode = match self.is_upvar_field_projection(&proj.base)
|
||||
let mode = match place.is_upvar_field_projection(
|
||||
self.mir, &self.tcx)
|
||||
{
|
||||
Some(field)
|
||||
if {
|
||||
|
|
@ -1911,7 +1913,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| 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);
|
||||
if let Some(field) = upvar_field_projection {
|
||||
let decl = &self.mir.upvar_decls[field.index()];
|
||||
debug!(
|
||||
"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)]
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ use std::fmt;
|
|||
use syntax_pos::Span;
|
||||
|
||||
mod region_name;
|
||||
mod var_name;
|
||||
|
||||
/// Constraints that are considered interesting can be categorized to
|
||||
/// determine why they are interesting. Order of variants indicates
|
||||
|
|
@ -30,7 +31,9 @@ mod region_name;
|
|||
enum ConstraintCategory {
|
||||
Cast,
|
||||
Assignment,
|
||||
AssignmentToUpvar,
|
||||
Return,
|
||||
CallArgumentToUpvar,
|
||||
CallArgument,
|
||||
Other,
|
||||
Boring,
|
||||
|
|
@ -39,10 +42,12 @@ enum ConstraintCategory {
|
|||
impl fmt::Display for ConstraintCategory {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
ConstraintCategory::Assignment => write!(f, "assignment"),
|
||||
ConstraintCategory::Assignment |
|
||||
ConstraintCategory::AssignmentToUpvar => write!(f, "assignment"),
|
||||
ConstraintCategory::Return => write!(f, "return"),
|
||||
ConstraintCategory::Cast => write!(f, "cast"),
|
||||
ConstraintCategory::CallArgument => write!(f, "argument"),
|
||||
ConstraintCategory::CallArgument |
|
||||
ConstraintCategory::CallArgumentToUpvar => write!(f, "argument"),
|
||||
_ => write!(f, "free region"),
|
||||
}
|
||||
}
|
||||
|
|
@ -130,8 +135,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
&self,
|
||||
index: ConstraintIndex,
|
||||
mir: &Mir<'tcx>,
|
||||
_infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||
) -> (ConstraintCategory, Span) {
|
||||
let constraint = self.constraints[index];
|
||||
debug!("classify_constraint: constraint={:?}", constraint);
|
||||
let span = constraint.locations.span(mir);
|
||||
let location = constraint.locations.from_location().unwrap_or(Location::START);
|
||||
|
||||
|
|
@ -140,8 +147,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
|
||||
let data = &mir[location.block];
|
||||
debug!("classify_constraint: location={:?} data={:?}", location, data);
|
||||
let category = if location.statement_index == data.statements.len() {
|
||||
if let Some(ref terminator) = data.terminator {
|
||||
debug!("classify_constraint: terminator.kind={:?}", terminator.kind);
|
||||
match terminator.kind {
|
||||
TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment,
|
||||
TerminatorKind::Call { .. } => ConstraintCategory::CallArgument,
|
||||
|
|
@ -152,14 +161,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
} else {
|
||||
let statement = &data.statements[location.statement_index];
|
||||
debug!("classify_constraint: statement.kind={:?}", statement.kind);
|
||||
match statement.kind {
|
||||
StatementKind::Assign(ref place, ref rvalue) => {
|
||||
debug!("classify_constraint: place={:?} rvalue={:?}", place, rvalue);
|
||||
if *place == Place::Local(mir::RETURN_PLACE) {
|
||||
ConstraintCategory::Return
|
||||
} else {
|
||||
match rvalue {
|
||||
Rvalue::Cast(..) => ConstraintCategory::Cast,
|
||||
Rvalue::Use(..) => ConstraintCategory::Assignment,
|
||||
Rvalue::Use(..) |
|
||||
Rvalue::Aggregate(..) => ConstraintCategory::Assignment,
|
||||
_ => ConstraintCategory::Other,
|
||||
}
|
||||
}
|
||||
|
|
@ -208,7 +220,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
// Classify each of the constraints along the path.
|
||||
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();
|
||||
debug!("report_error: categorized_path={:?}", categorized_path);
|
||||
|
||||
|
|
@ -218,30 +230,100 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
// Get a span
|
||||
let (category, span) = categorized_path.first().unwrap();
|
||||
|
||||
let category = match (
|
||||
category,
|
||||
self.universal_regions.is_local_free_region(fr),
|
||||
self.universal_regions.is_local_free_region(outlived_fr),
|
||||
) {
|
||||
(ConstraintCategory::Assignment, true, false) =>
|
||||
&ConstraintCategory::AssignmentToUpvar,
|
||||
(ConstraintCategory::CallArgument, true, false) =>
|
||||
&ConstraintCategory::CallArgumentToUpvar,
|
||||
(category, _, _) => category,
|
||||
};
|
||||
|
||||
debug!("report_error: category={:?}", category);
|
||||
match category {
|
||||
ConstraintCategory::AssignmentToUpvar |
|
||||
ConstraintCategory::CallArgumentToUpvar =>
|
||||
self.report_closure_error(mir, infcx, mir_def_id, fr, outlived_fr, category, 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>,
|
||||
mir_def_id: DefId,
|
||||
fr: RegionVid,
|
||||
outlived_fr: RegionVid,
|
||||
category: &ConstraintCategory,
|
||||
span: &Span,
|
||||
) {
|
||||
let fr_name_and_span = self.get_var_name_and_span_for_region(
|
||||
infcx.tcx, mir, fr);
|
||||
let outlived_fr_name_and_span = self.get_var_name_and_span_for_region(
|
||||
infcx.tcx, mir,outlived_fr);
|
||||
|
||||
if fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none() {
|
||||
return self.report_general_error(mir, infcx, mir_def_id, fr, outlived_fr, category,
|
||||
span);
|
||||
}
|
||||
|
||||
let diag = &mut infcx.tcx.sess.struct_span_err(
|
||||
*span,
|
||||
&format!("unsatisfied lifetime constraints"), // FIXME
|
||||
*span, &format!("borrowed data escapes outside of closure"),
|
||||
);
|
||||
|
||||
if let Some((outlived_fr_name, outlived_fr_span)) = outlived_fr_name_and_span {
|
||||
if let Some(name) = outlived_fr_name {
|
||||
diag.span_label(
|
||||
outlived_fr_span,
|
||||
format!("`{}` is declared here, outside of the closure body", name),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((fr_name, fr_span)) = fr_name_and_span {
|
||||
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 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(
|
||||
infcx.tcx,
|
||||
mir,
|
||||
mir_def_id,
|
||||
outlived_fr,
|
||||
counter,
|
||||
diag,
|
||||
);
|
||||
infcx.tcx, mir, mir_def_id, outlived_fr, counter, diag);
|
||||
|
||||
diag.span_label(
|
||||
*span,
|
||||
format!(
|
||||
"{} requires that `{}` must outlive `{}`",
|
||||
category, fr_name, outlived_fr_name,
|
||||
),
|
||||
);
|
||||
diag.span_label(*span, format!(
|
||||
"{} requires that `{}` must outlive `{}`",
|
||||
category, fr_name, outlived_fr_name,
|
||||
));
|
||||
|
||||
diag.emit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,9 @@ use borrow_check::nll::region_infer::RegionInferenceContext;
|
|||
use borrow_check::nll::ToRegionVid;
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir::{Local, Mir};
|
||||
use rustc::mir::Mir;
|
||||
use rustc::ty::subst::{Substs, UnpackedKind};
|
||||
use rustc::ty::{self, RegionVid, Ty, TyCtxt};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use syntax::ast::Name;
|
||||
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)
|
||||
.or_else(|| {
|
||||
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(|| {
|
||||
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(|| {
|
||||
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<'_>,
|
||||
) -> Option<InternedString> {
|
||||
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!(
|
||||
"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 argument_index = self.get_argument_index_for_region(tcx, fr)?;
|
||||
|
||||
let arg_ty =
|
||||
self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index];
|
||||
|
|
@ -172,10 +154,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
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 argument_local = Local::new(argument_index + implicit_inputs + 1);
|
||||
let argument_span = mir.local_decls[argument_local].source_info.span;
|
||||
diag.span_label(
|
||||
argument_span,
|
||||
format!("lifetime `{}` appears in this argument", region_name,),
|
||||
|
|
@ -440,42 +423,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
counter: &mut usize,
|
||||
diag: &mut DiagnosticBuilder<'_>,
|
||||
) -> Option<InternedString> {
|
||||
let upvar_index = self
|
||||
.universal_regions
|
||||
.defining_ty
|
||||
.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 upvar_index = self.get_upvar_index_for_region(tcx, fr)?;
|
||||
let (upvar_name, upvar_span) = self.get_upvar_name_and_span_for_region(tcx, mir,
|
||||
upvar_index);
|
||||
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(
|
||||
upvar_span,
|
||||
format!(
|
||||
"lifetime `{}` appears in the type of `{}`",
|
||||
region_name, upvar_name,
|
||||
),
|
||||
format!("lifetime `{}` appears in the type of `{}`", region_name, upvar_name),
|
||||
);
|
||||
|
||||
Some(region_name)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,145 @@
|
|||
// 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<(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| {
|
||||
let (name, span) = self.get_upvar_name_and_span_for_region(tcx, mir, index);
|
||||
(Some(name), span)
|
||||
})
|
||||
.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))
|
||||
})
|
||||
}
|
||||
|
||||
/// Search the upvars (if any) to find one that references fr. Return its index.
|
||||
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)
|
||||
}
|
||||
|
||||
/// Given the index of an upvar, finds its name and the span from where it was
|
||||
/// declared.
|
||||
crate fn get_upvar_name_and_span_for_region(
|
||||
&self,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
upvar_index: usize,
|
||||
) -> (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);
|
||||
|
||||
(upvar_name, upvar_span)
|
||||
}
|
||||
|
||||
/// Search the argument types for one that references fr (which should be a free region).
|
||||
/// Returns Some(_) with the index of the input if one is found.
|
||||
///
|
||||
/// NB: In the case of a closure, the index is indexing into the signature as seen by the
|
||||
/// user - in particular, index 0 is not the implicit self parameter.
|
||||
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)
|
||||
}
|
||||
|
||||
/// Given the index of an argument, finds its name (if any) and the span from where it was
|
||||
/// declared.
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -4,15 +4,15 @@ warning: not reporting region error due to nll
|
|||
LL | give_any(|y| x = Some(y));
|
||||
| ^
|
||||
|
||||
error: unsatisfied lifetime constraints
|
||||
error: borrowed data escapes outside of closure
|
||||
--> $DIR/issue-45983.rs:17:18
|
||||
|
|
||||
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));
|
||||
| - ^^^^^^^^^^^ free region 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
|
||||
--> $DIR/issue-45983.rs:17:18
|
||||
|
|
|
|||
|
|
@ -4,17 +4,17 @@ warning: not reporting region error due to nll
|
|||
LL | let mut lines_to_use: Vec<&CrateId> = Vec::new();
|
||||
| ^
|
||||
|
||||
error: unsatisfied lifetime constraints
|
||||
error: borrowed data escapes outside of closure
|
||||
--> $DIR/issue-7573.rs:32:9
|
||||
|
|
||||
LL | let mut lines_to_use: Vec<&CrateId> = Vec::new();
|
||||
| ---------------- lifetime `'2` appears in the type of `lines_to_use`
|
||||
| ---------------- `lines_to_use` is declared here, outside of the closure body
|
||||
LL | //~^ NOTE cannot infer an appropriate lifetime
|
||||
LL | let push_id = |installed_id: &CrateId| {
|
||||
| - let's call the lifetime of this reference `'1`
|
||||
| ------------ `installed_id` is a reference that is only valid in the closure body
|
||||
...
|
||||
LL | lines_to_use.push(installed_id);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `installed_id` escapes the closure body here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@ warning: not reporting region error due to nll
|
|||
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
|
||||
|
|
||||
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));
|
||||
| - ^^^^^^^^^^^ free region 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
|
||||
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@ warning: not reporting region error due to nll
|
|||
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
|
||||
|
|
||||
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));
|
||||
| - ^^^^^^^^^^^ free region 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
|
||||
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@ warning: not reporting region error due to nll
|
|||
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
|
||||
|
|
||||
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));
|
||||
| - ^^^^^^^^^^^ free region 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
|
||||
|
||||
|
|
|
|||
|
|
@ -22,37 +22,37 @@ warning: not reporting region error due to nll
|
|||
LL | f = Some(x);
|
||||
| ^^^^^^^
|
||||
|
||||
error: unsatisfied lifetime constraints
|
||||
error: borrowed data escapes outside of closure
|
||||
--> $DIR/expect-region-supply-region.rs:28:9
|
||||
|
|
||||
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| {
|
||||
| - 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
|
||||
| ^^^^^^^^^^^ free region 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
|
||||
|
|
||||
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| {
|
||||
| - 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
|
||||
| ^^^^^^^^^^^ free region 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
|
||||
|
|
||||
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| {
|
||||
| - 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);
|
||||
| ^^^^^^^^^^^ free region requires that `'1` must outlive `'2`
|
||||
| ^^^^^^^^^^^ `x` escapes the closure body here
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ warning: not reporting region error due to nll
|
|||
LL | static_val(x); //~ ERROR cannot infer
|
||||
| ^
|
||||
|
||||
error: unsatisfied lifetime constraints
|
||||
error: borrowed data escapes outside of closure
|
||||
--> $DIR/dyn-trait.rs:32:5
|
||||
|
|
||||
LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
|
||||
| - `x` is a reference that is only valid in the closure body
|
||||
LL | static_val(x); //~ ERROR cannot infer
|
||||
| ^^^^^^^^^^^^^ argument requires that `'a` must outlive `'static`
|
||||
| ^^^^^^^^^^^^^ `x` escapes the closure body here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ warning: not reporting region error due to nll
|
|||
LL | self.a(); //~ ERROR cannot infer
|
||||
| ^
|
||||
|
||||
error: unsatisfied lifetime constraints
|
||||
error: borrowed data escapes outside of closure
|
||||
--> $DIR/issue-16683.rs:14:9
|
||||
|
|
||||
LL | fn b(&self) {
|
||||
| - let's call the lifetime of this reference `'1`
|
||||
| ----- `self` is a reference that is only valid in the closure body
|
||||
LL | self.a(); //~ ERROR cannot infer
|
||||
| ^^^^^^^^ argument requires that `'1` must outlive `'a`
|
||||
| ^^^^^^^^ `self` escapes the closure body here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ warning: not reporting region error due to nll
|
|||
LL | self.foo();
|
||||
| ^^^
|
||||
|
||||
error: unsatisfied lifetime constraints
|
||||
error: borrowed data escapes outside of closure
|
||||
--> $DIR/issue-17758.rs:17:9
|
||||
|
|
||||
LL | fn bar(&self) {
|
||||
| - let's call the lifetime of this reference `'1`
|
||||
| ----- `self` is a reference that is only valid in the closure body
|
||||
LL | self.foo();
|
||||
| ^^^^^^^^^^ argument requires that `'1` must outlive `'a`
|
||||
| ^^^^^^^^^^ `self` escapes the closure body here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@ warning: not reporting region error due to nll
|
|||
LL | foo(cell, |cell_a, cell_x| {
|
||||
| ^^^
|
||||
|
||||
error: unsatisfied lifetime constraints
|
||||
error: borrowed data escapes outside of closure
|
||||
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:20
|
||||
|
|
||||
LL | foo(cell, |cell_a, cell_x| {
|
||||
| ------ ------ lifetime `'1` appears in this argument
|
||||
| ------ ------ `cell_x` is a reference that is only valid in the closure body
|
||||
| |
|
||||
| lifetime `'2` appears in this argument
|
||||
| `cell_a` is declared here, outside of the closure body
|
||||
LL | //~^ WARNING not reporting region error due to nll
|
||||
LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
|
||||
| ^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
|
||||
| ^^^^^^^^^^^^ `cell_x` escapes the closure body here
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:31:15
|
||||
|
|
|
|||
|
|
@ -23,16 +23,18 @@ LL | | });
|
|||
= note: number of external vids: 2
|
||||
= note: where '_#1r: '_#0r
|
||||
|
||||
error: unsatisfied lifetime constraints
|
||||
error: borrowed data escapes outside of closure
|
||||
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:5
|
||||
|
|
||||
LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
|
||||
| ------ `cell_a` is a reference that is only valid in the closure body
|
||||
LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
|
||||
LL | | //~^ ERROR
|
||||
LL | |
|
||||
LL | | // Only works if 'x: 'y:
|
||||
LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
|
||||
LL | | });
|
||||
| |______^ argument requires that `'a` must outlive `'static`
|
||||
| |______^ `cell_a` escapes the closure body here
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:44:1
|
||||
|
|
|
|||
|
|
@ -23,16 +23,18 @@ LL | | });
|
|||
= note: number of external vids: 3
|
||||
= note: where '_#1r: '_#0r
|
||||
|
||||
error: unsatisfied lifetime constraints
|
||||
error: borrowed data escapes outside of closure
|
||||
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:5
|
||||
|
|
||||
LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
|
||||
| ------ `cell_a` is a reference that is only valid in the closure body
|
||||
LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
|
||||
LL | | //~^ ERROR
|
||||
LL | | // Only works if 'x: 'y:
|
||||
LL | | demand_y(x, y, x.get())
|
||||
LL | | //~^ WARNING not reporting region error due to nll
|
||||
LL | | });
|
||||
| |______^ argument requires that `'a` must outlive `'static`
|
||||
| |______^ `cell_a` escapes the closure body here
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:47:1
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
error: unsatisfied lifetime constraints
|
||||
error: borrowed data escapes outside of closure
|
||||
--> $DIR/issue-50716.rs:25:14
|
||||
|
|
||||
LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
|
||||
| - `s` is a reference that is only valid in the closure body
|
||||
...
|
||||
LL | let _x = *s; //~ ERROR
|
||||
| ^^ assignment requires that `'a` must outlive `'static`
|
||||
| ^^ `s` escapes the closure body here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue