diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 23be1bbf6c6..04b763f773d 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -133,41 +133,6 @@ 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 { - let (place, by_ref) = if let Place::Projection(ref proj) = self { - if let ProjectionElem::Deref = proj.elem { - (&proj.base, true) - } else { - (self, false) - } - } else { - (self, false) - }; - - match place { - Place::Projection(ref proj) => match proj.elem { - ProjectionElem::Field(field, _ty) => { - let base_ty = proj.base.ty(mir, *tcx).ty; - - if (base_ty.is_closure() || base_ty.is_generator()) && - (!by_ref || mir.upvar_decls[field.index()].by_ref) - { - Some(field) - } else { - None - } - }, - _ => None, - } - _ => None, - } - } } pub enum RvalueInitializationState { diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 3ab0996d3a1..12dcea7bd59 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -1088,7 +1088,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | LocalKind::Temp => bug!("temporary or return pointer with a name"), LocalKind::Var => "local variable ", LocalKind::Arg - if !self.mir.upvar_decls.is_empty() + if !self.upvars.is_empty() && local == Local::new(1) => { "variable captured by `move` " } @@ -1632,11 +1632,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { match proj.elem { ProjectionElem::Deref => { let upvar_field_projection = - place.is_upvar_field_projection(self.mir, &self.infcx.tcx); + self.is_upvar_field_projection(place); 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 { + let name = self.upvars[var_index].name.to_string(); + if self.upvars[var_index].by_ref { buf.push_str(&name); } else { buf.push_str(&format!("*{}", &name)); @@ -1694,10 +1694,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { autoderef = true; let upvar_field_projection = - place.is_upvar_field_projection(self.mir, &self.infcx.tcx); + self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { let var_index = field.index(); - let name = self.mir.upvar_decls[var_index].debug_name.to_string(); + let name = self.upvars[var_index].name.to_string(); buf.push_str(&name); } else { let field_name = self.describe_field(&proj.base, field); diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 4a3159d8a9d..14cafdef67d 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1,7 +1,7 @@ //! This query borrow-checks the MIR to (further) ensure it is not broken. use crate::borrow_check::nll::region_infer::RegionInferenceContext; -use rustc::hir; +use rustc::hir::{self, HirId}; use rustc::hir::Node; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; @@ -27,6 +27,7 @@ use std::collections::BTreeMap; use std::mem; use std::rc::Rc; +use syntax::ast::Name; use syntax_pos::{Span, DUMMY_SP}; use crate::dataflow::indexes::{BorrowIndex, InitIndex, MoveOutIndex, MovePathIndex}; @@ -63,6 +64,19 @@ mod used_muts; pub(crate) mod nll; +// FIXME(eddyb) perhaps move this somewhere more centrally. +#[derive(Debug)] +crate struct Upvar { + name: Name, + + var_hir_id: HirId, + + /// If true, the capture is behind a reference. + by_ref: bool, + + mutability: Mutability, +} + pub fn provide(providers: &mut Providers<'_>) { *providers = Providers { mir_borrowck, @@ -126,6 +140,36 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( .as_local_hir_id(def_id) .expect("do_mir_borrowck: non-local DefId"); + // Gather the upvars of a closure, if any. + let tables = tcx.typeck_tables_of(def_id); + let upvars: Vec<_> = tables + .upvar_list + .get(&def_id) + .into_iter() + .flatten() + .map(|upvar_id| { + let var_hir_id = upvar_id.var_path.hir_id; + let var_node_id = tcx.hir().hir_to_node_id(var_hir_id); + let capture = tables.upvar_capture(*upvar_id); + let by_ref = match capture { + ty::UpvarCapture::ByValue => false, + ty::UpvarCapture::ByRef(..) => true, + }; + let mut upvar = Upvar { + name: tcx.hir().name(var_node_id), + var_hir_id, + by_ref, + mutability: Mutability::Not, + }; + let bm = *tables.pat_binding_modes().get(var_hir_id) + .expect("missing binding mode"); + if bm == ty::BindByValue(hir::MutMutable) { + upvar.mutability = Mutability::Mut; + } + upvar + }) + .collect(); + // Replace all regions with fresh inference variables. This // requires first making our own copy of the MIR. This copy will // be modified (in place) to contain non-lexical lifetimes. It @@ -168,6 +212,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( def_id, free_regions, mir, + &upvars, location_table, param_env, &mut flow_inits, @@ -240,6 +285,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( used_mut_upvars: SmallVec::new(), borrow_set, dominators, + upvars, }; let mut state = Flows::new( @@ -475,6 +521,9 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { /// Dominators for MIR dominators: Dominators, + + /// Information about upvars not necessarily preserved in types or MIR + upvars: Vec, } // Check that: @@ -1287,8 +1336,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'tcx>| { match *place { Place::Projection { .. } => { - if let Some(field) = place.is_upvar_field_projection( - this.mir, &this.infcx.tcx) { + if let Some(field) = this.is_upvar_field_projection(place) { this.used_mut_upvars.push(field); } } @@ -2057,7 +2105,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { place: place @ Place::Projection(_), is_local_mutation_allowed: _, } => { - if let Some(field) = place.is_upvar_field_projection(self.mir, &self.infcx.tcx) { + if let Some(field) = self.is_upvar_field_projection(place) { self.used_mut_upvars.push(field); } } @@ -2127,13 +2175,9 @@ 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 place.is_upvar_field_projection( - self.mir, &self.infcx.tcx) - { + let mode = match self.is_upvar_field_projection(place) { Some(field) - if { - self.mir.upvar_decls[field.index()].by_ref - } => + if self.upvars[field.index()].by_ref => { is_local_mutation_allowed } @@ -2173,15 +2217,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..) => { - let upvar_field_projection = place.is_upvar_field_projection( - self.mir, &self.infcx.tcx); + let upvar_field_projection = self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { - let decl = &self.mir.upvar_decls[field.index()]; + let upvar = &self.upvars[field.index()]; debug!( - "decl.mutability={:?} local_mutation_is_allowed={:?} place={:?}", - decl, is_local_mutation_allowed, place + "upvar.mutability={:?} local_mutation_is_allowed={:?} place={:?}", + upvar, is_local_mutation_allowed, place ); - match (decl.mutability, is_local_mutation_allowed) { + match (upvar.mutability, is_local_mutation_allowed) { (Mutability::Not, LocalMutationIsAllowed::No) | (Mutability::Not, LocalMutationIsAllowed::ExceptUpvars) => { Err(place) @@ -2229,6 +2272,41 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } } + + /// If `place` 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(&self, place: &Place<'tcx>) -> Option { + let (place, by_ref) = if let Place::Projection(ref proj) = place { + if let ProjectionElem::Deref = proj.elem { + (&proj.base, true) + } else { + (place, false) + } + } else { + (place, false) + }; + + match place { + Place::Projection(ref proj) => match proj.elem { + ProjectionElem::Field(field, _ty) => { + let tcx = self.infcx.tcx; + let base_ty = proj.base.ty(self.mir, tcx).ty; + + if (base_ty.is_closure() || base_ty.is_generator()) && + (!by_ref || self.upvars[field.index()].by_ref) + { + Some(field) + } else { + None + } + }, + _ => None, + } + _ => None, + } + } } #[derive(Copy, Clone, PartialEq, Eq, Debug)] diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 7efe1d83c2e..a7bad44c42c 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -256,7 +256,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { let origin = Origin::Mir; debug!("report: original_path={:?} span={:?}, kind={:?} \ original_path.is_upvar_field_projection={:?}", original_path, span, kind, - original_path.is_upvar_field_projection(self.mir, &self.infcx.tcx)); + self.is_upvar_field_projection(original_path)); ( match kind { IllegalMoveOriginKind::Static => { @@ -269,8 +269,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { let ty = place.ty(self.mir, self.infcx.tcx).ty; let is_upvar_field_projection = self.prefixes(&original_path, PrefixSet::All) - .any(|p| p.is_upvar_field_projection(self.mir, &self.infcx.tcx) - .is_some()); + .any(|p| self.is_upvar_field_projection(p).is_some()); debug!("report: ty={:?}", ty); match ty.sty { ty::Array(..) | ty::Slice(..) => @@ -278,7 +277,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { span, ty, None, origin ), ty::Closure(def_id, closure_substs) - if !self.mir.upvar_decls.is_empty() && is_upvar_field_projection + if def_id == self.mir_def_id && is_upvar_field_projection => { let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.infcx.tcx); @@ -303,11 +302,8 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { span, place_description, origin); for prefix in self.prefixes(&original_path, PrefixSet::All) { - if let Some(field) = prefix.is_upvar_field_projection( - self.mir, &self.infcx.tcx) { - let upvar_decl = &self.mir.upvar_decls[field.index()]; - let upvar_hir_id = - upvar_decl.var_hir_id.assert_crate_local(); + if let Some(field) = self.is_upvar_field_projection(prefix) { + let upvar_hir_id = self.upvars[field.index()].var_hir_id; let upvar_span = self.infcx.tcx.hir().span_by_hir_id( upvar_hir_id); diag.span_label(upvar_span, "captured outer variable"); diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index b780511315d..c5ad2b18c23 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -68,10 +68,10 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { )); item_msg = format!("`{}`", access_place_desc.unwrap()); - if access_place.is_upvar_field_projection(self.mir, &self.infcx.tcx).is_some() { + if self.is_upvar_field_projection(access_place).is_some() { reason = ", as it is not declared as mutable".to_string(); } else { - let name = self.mir.upvar_decls[upvar_index.index()].debug_name; + let name = self.upvars[upvar_index.index()].name; reason = format!(", as `{}` is not declared as mutable", name); } } @@ -81,15 +81,14 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { elem: ProjectionElem::Deref, }) => { if *base == Place::Base(PlaceBase::Local(Local::new(1))) && - !self.mir.upvar_decls.is_empty() { + !self.upvars.is_empty() { item_msg = format!("`{}`", access_place_desc.unwrap()); debug_assert!(self.mir.local_decls[Local::new(1)].ty.is_region_ptr()); debug_assert!(is_closure_or_generator( the_place_err.ty(self.mir, self.infcx.tcx).ty )); - reason = if access_place.is_upvar_field_projection(self.mir, - &self.infcx.tcx).is_some() { + reason = if self.is_upvar_field_projection(access_place).is_some() { ", as it is a captured variable in a `Fn` closure".to_string() } else { ", as `Fn` closures cannot mutate their captured variables".to_string() @@ -309,9 +308,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { err.span_label(span, format!("cannot {ACT}", ACT = act)); - let upvar_hir_id = self.mir.upvar_decls[upvar_index.index()] - .var_hir_id - .assert_crate_local(); + let upvar_hir_id = self.upvars[upvar_index.index()].var_hir_id; let upvar_node_id = self.infcx.tcx.hir().hir_to_node_id(upvar_hir_id); if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_node_id) { if let hir::PatKind::Binding( @@ -452,7 +449,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { base, elem: ProjectionElem::Deref, }) if *base == Place::Base(PlaceBase::Local(Local::new(1))) && - !self.mir.upvar_decls.is_empty() => + !self.upvars.is_empty() => { err.span_label(span, format!("cannot {ACT}", ACT = act)); err.span_help( diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index 5ad54080c5a..0430ad307ce 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -298,6 +298,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let (category, from_closure, span, region_name) = self.nonlexical_regioncx.free_region_constraint_info( self.mir, + &self.upvars, self.mir_def_id, self.infcx, borrow_region_vid, diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 3e1b93fb417..ad43c8ef66f 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -8,6 +8,7 @@ use crate::dataflow::move_paths::MoveData; use crate::dataflow::FlowAtLocation; use crate::dataflow::MaybeInitializedPlaces; use crate::transform::MirSource; +use crate::borrow_check::Upvar; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Mir}; @@ -72,6 +73,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( def_id: DefId, universal_regions: UniversalRegions<'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], location_table: &LocationTable, param_env: ty::ParamEnv<'gcx>, flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>, @@ -187,7 +189,8 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( }); // Solve the region constraints. - let closure_region_requirements = regioncx.solve(infcx, &mir, def_id, errors_buffer); + let closure_region_requirements = + regioncx.solve(infcx, &mir, upvars, def_id, errors_buffer); // Dump MIR results into a file, if that is enabled. This let us // write unit-tests, as well as helping with debugging. diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs index 917e383cae8..abb30d042ca 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs @@ -4,6 +4,7 @@ use crate::borrow_check::nll::type_check::Locations; use crate::borrow_check::nll::universal_regions::DefiningTy; use crate::borrow_check::nll::ConstraintDescription; use crate::util::borrowck_errors::{BorrowckErrors, Origin}; +use crate::borrow_check::Upvar; use rustc::hir::def_id::DefId; use rustc::infer::error_reporting::nice_region_error::NiceRegionError; use rustc::infer::InferCtxt; @@ -237,6 +238,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(super) fn report_error( &self, mir: &Mir<'tcx>, + upvars: &[Upvar], infcx: &InferCtxt<'_, '_, 'tcx>, mir_def_id: DefId, fr: RegionVid, @@ -273,6 +275,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { (ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(infcx, fr) => { self.report_fnmut_error( mir, + upvars, infcx, mir_def_id, fr, @@ -284,6 +287,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { (ConstraintCategory::Assignment, true, false) | (ConstraintCategory::CallArgument, true, false) => self.report_escaping_data_error( mir, + upvars, infcx, mir_def_id, fr, @@ -294,6 +298,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ), _ => self.report_general_error( mir, + upvars, infcx, mir_def_id, fr, @@ -353,6 +358,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn report_fnmut_error( &self, mir: &Mir<'tcx>, + upvars: &[Upvar], infcx: &InferCtxt<'_, '_, 'tcx>, mir_def_id: DefId, _fr: RegionVid, @@ -377,7 +383,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { diag.span_label(span, message); - match self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, &mut 1).unwrap().source { + match self.give_region_a_name(infcx, mir, upvars, mir_def_id, outlived_fr, &mut 1) + .unwrap().source + { RegionNameSource::NamedEarlyBoundRegion(fr_span) | RegionNameSource::NamedFreeRegion(fr_span) | RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _) @@ -415,6 +423,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn report_escaping_data_error( &self, mir: &Mir<'tcx>, + upvars: &[Upvar], infcx: &InferCtxt<'_, '_, 'tcx>, mir_def_id: DefId, fr: RegionVid, @@ -423,9 +432,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { span: Span, errors_buffer: &mut Vec, ) { - let fr_name_and_span = self.get_var_name_and_span_for_region(infcx.tcx, mir, fr); + let fr_name_and_span = + self.get_var_name_and_span_for_region(infcx.tcx, mir, upvars, fr); let outlived_fr_name_and_span = - self.get_var_name_and_span_for_region(infcx.tcx, mir, outlived_fr); + self.get_var_name_and_span_for_region(infcx.tcx, mir, upvars, outlived_fr); let escapes_from = match self.universal_regions.defining_ty { DefiningTy::Closure(..) => "closure", @@ -442,6 +452,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { { return self.report_general_error( mir, + upvars, infcx, mir_def_id, fr, @@ -504,6 +515,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn report_general_error( &self, mir: &Mir<'tcx>, + upvars: &[Upvar], infcx: &InferCtxt<'_, '_, 'tcx>, mir_def_id: DefId, fr: RegionVid, @@ -520,10 +532,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); let counter = &mut 1; - let fr_name = self.give_region_a_name(infcx, mir, mir_def_id, fr, counter).unwrap(); + let fr_name = self.give_region_a_name(infcx, mir, upvars, mir_def_id, fr, counter).unwrap(); fr_name.highlight_region_name(&mut diag); let outlived_fr_name = - self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, counter).unwrap(); + self.give_region_a_name(infcx, mir, upvars, mir_def_id, outlived_fr, counter).unwrap(); outlived_fr_name.highlight_region_name(&mut diag); let mir_def_name = if infcx.tcx.is_closure(mir_def_id) { @@ -656,6 +668,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { crate fn free_region_constraint_info( &self, mir: &Mir<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, infcx: &InferCtxt<'_, '_, 'tcx>, borrow_region: RegionVid, @@ -664,7 +677,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let (category, from_closure, span) = self.best_blame_constraint(mir, borrow_region, |r| r == outlived_region); let outlived_fr_name = - self.give_region_a_name(infcx, mir, mir_def_id, outlived_region, &mut 1); + self.give_region_a_name(infcx, mir, upvars, mir_def_id, outlived_region, &mut 1); (category, from_closure, span, outlived_fr_name) } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index 362214d3257..680e7ce576a 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -2,6 +2,7 @@ use std::fmt::{self, Display}; use crate::borrow_check::nll::region_infer::RegionInferenceContext; use crate::borrow_check::nll::universal_regions::DefiningTy; use crate::borrow_check::nll::ToRegionVid; +use crate::borrow_check::Upvar; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; @@ -144,6 +145,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, fr: RegionVid, counter: &mut usize, @@ -160,7 +162,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) .or_else(|| { self.give_name_if_anonymous_region_appears_in_upvars( - infcx.tcx, mir, fr, counter, + infcx.tcx, upvars, fr, counter, ) }) .or_else(|| { @@ -639,13 +641,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn give_name_if_anonymous_region_appears_in_upvars( &self, tcx: TyCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + upvars: &[Upvar], fr: RegionVid, counter: &mut usize, ) -> Option { 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); + self.get_upvar_name_and_span_for_region(tcx, upvars, upvar_index); let region_name = self.synthesize_region_name(counter); Some(RegionName { diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs index f6bbaf2db03..d8f34233839 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs @@ -1,5 +1,6 @@ use crate::borrow_check::nll::region_infer::RegionInferenceContext; use crate::borrow_check::nll::ToRegionVid; +use crate::borrow_check::Upvar; use rustc::mir::{Local, Mir}; use rustc::ty::{RegionVid, TyCtxt}; use rustc_data_structures::indexed_vec::Idx; @@ -11,6 +12,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], fr: RegionVid, ) -> Option<(Option, Span)> { debug!("get_var_name_and_span_for_region(fr={:?})", fr); @@ -19,7 +21,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { 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); + let (name, span) = + self.get_upvar_name_and_span_for_region(tcx, upvars, index); (Some(name), span) }) .or_else(|| { @@ -67,10 +70,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { crate fn get_upvar_name_and_span_for_region( &self, tcx: TyCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + upvars: &[Upvar], upvar_index: usize, ) -> (Symbol, Span) { - let upvar_hir_id = mir.upvar_decls[upvar_index].var_hir_id.assert_crate_local(); + let upvar_hir_id = upvars[upvar_index].var_hir_id; debug!("get_upvar_name_and_span_for_region: upvar_hir_id={:?}", upvar_hir_id); let upvar_name = tcx.hir().name_by_hir_id(upvar_hir_id); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index ac10683598a..9dd18ab76a5 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -4,6 +4,7 @@ use crate::borrow_check::nll::constraints::{ConstraintSccIndex, ConstraintSet, O use crate::borrow_check::nll::region_infer::values::{ PlaceholderIndices, RegionElement, ToElementIndex }; +use crate::borrow_check::Upvar; use crate::borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; use crate::borrow_check::nll::type_check::Locations; use rustc::hir::def_id::DefId; @@ -400,6 +401,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &mut self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, errors_buffer: &mut Vec, ) -> Option> { @@ -407,7 +409,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { infcx.tcx.sess.time_extended(), Some(infcx.tcx.sess), &format!("solve_nll_region_constraints({:?})", mir_def_id), - || self.solve_inner(infcx, mir, mir_def_id, errors_buffer), + || self.solve_inner(infcx, mir, upvars, mir_def_id, errors_buffer), ) } @@ -415,6 +417,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &mut self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, errors_buffer: &mut Vec, ) -> Option> { @@ -442,6 +445,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_universal_regions( infcx, mir, + upvars, mir_def_id, outlives_requirements.as_mut(), errors_buffer, @@ -1102,6 +1106,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, mut propagated_outlives_requirements: Option<&mut Vec>>, errors_buffer: &mut Vec, @@ -1115,6 +1120,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_universal_region( infcx, mir, + upvars, mir_def_id, fr, &mut propagated_outlives_requirements, @@ -1145,6 +1151,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, longer_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec>>, @@ -1177,6 +1184,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { representative, infcx, mir, + upvars, mir_def_id, propagated_outlives_requirements, errors_buffer, @@ -1192,6 +1200,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { shorter_fr, infcx, mir, + upvars, mir_def_id, propagated_outlives_requirements, errors_buffer, @@ -1208,6 +1217,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { shorter_fr: RegionVid, infcx: &InferCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, propagated_outlives_requirements: &mut Option<&mut Vec>>, errors_buffer: &mut Vec, @@ -1265,7 +1275,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // // Note: in this case, we use the unapproximated regions to report the // error. This gives better error messages in some cases. - self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer); + self.report_error(mir, upvars, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer); Some(ErrorReported) } diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index ae8dfa8144f..d3cef46b402 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -105,7 +105,7 @@ impl<'tcx> DefiningTy<'tcx> { /// Returns a list of all the upvar types for this MIR. If this is /// not a closure or generator, there are no upvars, and hence it /// will be an empty list. The order of types in this list will - /// match up with the `upvar_decls` field of `Mir`. + /// match up with the upvar order in the HIR, typesystem, and MIR. pub fn upvar_tys(self, tcx: TyCtxt<'_, '_, 'tcx>) -> impl Iterator> + 'tcx { match self { DefiningTy::Closure(def_id, substs) => Either::Left(substs.upvar_tys(def_id, tcx)),