From 5ddda3f19551ce299af426756661f8dcdf3ccde6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis <niko@alum.mit.edu> Date: Mon, 4 Jun 2018 08:53:34 -0400 Subject: [PATCH 01/15] rename `ToLocations` to `NormalizeLocation` --- src/librustc_mir/borrow_check/nll/type_check/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 611050a406020..b1ccee340bc6b 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1614,7 +1614,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn normalize<T>(&mut self, value: T, location: impl ToLocations) -> T + fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T where T: type_op::normalize::Normalizable<'gcx, 'tcx> + Copy, { @@ -1701,17 +1701,17 @@ impl AtLocation for Location { } } -trait ToLocations: fmt::Debug + Copy { +trait NormalizeLocation: fmt::Debug + Copy { fn to_locations(self) -> Locations; } -impl ToLocations for Locations { +impl NormalizeLocation for Locations { fn to_locations(self) -> Locations { self } } -impl ToLocations for Location { +impl NormalizeLocation for Location { fn to_locations(self) -> Locations { self.at_self() } From dbeda5ee29ddfd9195f540860020afd1a628bde2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis <niko@alum.mit.edu> Date: Mon, 4 Jun 2018 09:29:36 -0400 Subject: [PATCH 02/15] remove the `at_location` from Locations We are not currently using it for anything; even polonius just uses the `from_location`. --- .../borrow_check/nll/constraint_generation.rs | 1 - .../borrow_check/nll/constraint_set.rs | 12 ++-- .../borrow_check/nll/region_infer/dump_mir.rs | 4 +- .../borrow_check/nll/region_infer/graphviz.rs | 2 +- .../borrow_check/nll/region_infer/mod.rs | 22 +++---- .../nll/type_check/constraint_conversion.rs | 4 +- .../borrow_check/nll/type_check/mod.rs | 61 ++----------------- 7 files changed, 20 insertions(+), 86 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 72db9f8da9872..6e9574e2d5b73 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -315,7 +315,6 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { span, ref_region.to_region_vid(), borrow_region.to_region_vid(), - location.successor_within_block(), ); if let Some(all_facts) = self.all_facts { diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs index 4c6e445293d54..ac3ab961d0a15 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_set.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::mir::Location; use rustc::ty::RegionVid; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; @@ -24,8 +23,8 @@ crate struct ConstraintSet { impl ConstraintSet { pub fn push(&mut self, constraint: OutlivesConstraint) { debug!( - "add_outlives({:?}: {:?} @ {:?}", - constraint.sup, constraint.sub, constraint.point + "add_outlives({:?}: {:?})", + constraint.sup, constraint.sub ); if constraint.sup == constraint.sub { // 'a: 'a is pretty uninteresting @@ -86,9 +85,6 @@ pub struct OutlivesConstraint { /// Region that must be outlived. pub sub: RegionVid, - /// At this location. - pub point: Location, - /// Later on, we thread the constraints onto a linked list /// grouped by their `sub` field. So if you had: /// @@ -107,8 +103,8 @@ impl fmt::Debug for OutlivesConstraint { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!( formatter, - "({:?}: {:?} @ {:?}) due to {:?}", - self.sup, self.sub, self.point, self.span + "({:?}: {:?}) due to {:?}", + self.sup, self.sub, self.span ) } } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs index 6c796ea4c73ab..c68bb15552fc7 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs @@ -82,15 +82,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { let OutlivesConstraint { sup, sub, - point, span, next: _, } = constraint; with_msg(&format!( - "{:?}: {:?} @ {:?} due to {:?}", + "{:?}: {:?} due to {:?}", sup, sub, - point, span ))?; } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs index 106dd003ceab9..15896413af991 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs @@ -44,7 +44,7 @@ impl<'this, 'tcx> dot::Labeller<'this> for RegionInferenceContext<'tcx> { dot::LabelText::LabelStr(format!("{:?}", n).into_cow()) } fn edge_label(&'this self, e: &OutlivesConstraint) -> dot::LabelText<'this> { - dot::LabelText::LabelStr(format!("{:?}", e.point).into_cow()) + dot::LabelText::LabelStr(format!("{:?}", e.span).into_cow()) } } 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 a576dc5f7f47b..fd8a62b4deb33 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -359,14 +359,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { span: Span, sup: RegionVid, sub: RegionVid, - point: Location, ) { assert!(self.inferred_values.is_none(), "values already inferred"); self.constraints.push(OutlivesConstraint { span, sup, sub, - point, next: None, }) } @@ -503,7 +501,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { for type_test in &self.type_tests { debug!("check_type_test: {:?}", type_test); - if self.eval_region_test(mir, type_test.point, type_test.lower_bound, &type_test.test) { + if self.eval_region_test(mir, type_test.lower_bound, &type_test.test) { continue; } @@ -765,31 +763,30 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn eval_region_test( &self, mir: &Mir<'tcx>, - point: Location, lower_bound: RegionVid, test: &RegionTest, ) -> bool { debug!( - "eval_region_test(point={:?}, lower_bound={:?}, test={:?})", - point, lower_bound, test + "eval_region_test(lower_bound={:?}, test={:?})", + lower_bound, test ); match test { RegionTest::IsOutlivedByAllRegionsIn(regions) => regions .iter() - .all(|&r| self.eval_outlives(mir, r, lower_bound, point)), + .all(|&r| self.eval_outlives(mir, r, lower_bound)), RegionTest::IsOutlivedByAnyRegionIn(regions) => regions .iter() - .any(|&r| self.eval_outlives(mir, r, lower_bound, point)), + .any(|&r| self.eval_outlives(mir, r, lower_bound)), RegionTest::Any(tests) => tests .iter() - .any(|test| self.eval_region_test(mir, point, lower_bound, test)), + .any(|test| self.eval_region_test(mir, lower_bound, test)), RegionTest::All(tests) => tests .iter() - .all(|test| self.eval_region_test(mir, point, lower_bound, test)), + .all(|test| self.eval_region_test(mir, lower_bound, test)), } } @@ -799,11 +796,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { _mir: &Mir<'tcx>, sup_region: RegionVid, sub_region: RegionVid, - point: Location, ) -> bool { debug!( - "eval_outlives({:?}: {:?} @ {:?})", - sup_region, sub_region, point + "eval_outlives({:?}: {:?})", + sup_region, sub_region ); let inferred_values = self diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs index 3100df3e8f629..2ee74dc6095fa 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs @@ -146,7 +146,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { ) -> TypeTest<'tcx> { let lower_bound = self.to_region_vid(region); - let point = self.locations.at_location().unwrap_or(Location::START); + let point = self.locations.from_location().unwrap_or(Location::START); let test = self.verify_bound_to_region_test(&bound); @@ -197,13 +197,11 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) { let span = self.span(); - let point = self.locations.at_location().unwrap_or(Location::START); self.outlives_constraints.push(OutlivesConstraint { span, sub, sup, - point, next: None, }); } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index b1ccee340bc6b..da12ce89f9d68 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -671,11 +671,6 @@ pub enum Locations { /// This is intended for error reporting and diagnosis; the /// constraints may *take effect* at a distinct spot. from_location: Location, - - /// The constraints must be met at this location. In terms of the - /// NLL RFC, when you have a constraint `R1: R2 @ P`, this field - /// is the `P` value. - at_location: Location, }, } @@ -686,13 +681,6 @@ impl Locations { Locations::Pair { from_location, .. } => Some(*from_location), } } - - pub fn at_location(&self) -> Option<Location> { - match self { - Locations::All => None, - Locations::Pair { at_location, .. } => Some(*at_location), - } - } } impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { @@ -799,9 +787,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { StatementKind::Assign(ref place, ref rv) => { let place_ty = place.ty(mir, tcx).to_ty(tcx); let rv_ty = rv.ty(mir, tcx); - if let Err(terr) = - self.sub_types(rv_ty, place_ty, location.at_successor_within_block()) - { + if let Err(terr) = self.sub_types(rv_ty, place_ty, location.at_self()) { span_mirbug!( self, stmt, @@ -897,15 +883,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { TerminatorKind::DropAndReplace { ref location, ref value, - target, - unwind, + target: _, + unwind: _, } => { let place_ty = location.ty(mir, tcx).to_ty(tcx); let rv_ty = value.ty(mir, tcx); let locations = Locations::Pair { from_location: term_location, - at_location: target.start_location(), }; if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) { span_mirbug!( @@ -917,26 +902,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { terr ); } - - // Subtle: this assignment occurs at the start of - // *both* blocks, so we need to ensure that it holds - // at both locations. - if let Some(unwind) = unwind { - let locations = Locations::Pair { - from_location: term_location, - at_location: unwind.start_location(), - }; - if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) { - span_mirbug!( - self, - term, - "bad DropAndReplace ({:?} = {:?}): {:?}", - place_ty, - rv_ty, - terr - ); - } - } } TerminatorKind::SwitchInt { ref discr, @@ -1052,11 +1017,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ) { let tcx = self.tcx(); match *destination { - Some((ref dest, target_block)) => { + Some((ref dest, _target_block)) => { let dest_ty = dest.ty(mir, tcx).to_ty(tcx); let locations = Locations::Pair { from_location: term_location, - at_location: target_block.start_location(), }; if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations) { span_mirbug!( @@ -1674,29 +1638,12 @@ trait AtLocation { /// indicated by `self`. This is typically used when processing /// "inputs" to the given location. fn at_self(self) -> Locations; - - /// Creates a `Locations` where `self` is the from-location and - /// its successor within the block is the at-location. This means - /// that any required region relationships must hold only upon - /// **exiting** the statement/terminator indicated by `self`. This - /// is for example used when you have a `place = rv` statement: it - /// indicates that the `typeof(rv) <: typeof(place)` as of the - /// **next** statement. - fn at_successor_within_block(self) -> Locations; } impl AtLocation for Location { fn at_self(self) -> Locations { Locations::Pair { from_location: self, - at_location: self, - } - } - - fn at_successor_within_block(self) -> Locations { - Locations::Pair { - from_location: self, - at_location: self.successor_within_block(), } } } From 609bb27514fe71f08040aef1eb8a7acd098e9185 Mon Sep 17 00:00:00 2001 From: Niko Matsakis <niko@alum.mit.edu> Date: Mon, 4 Jun 2018 11:19:43 -0400 Subject: [PATCH 03/15] categorize `Locations` as interesting or boring --- .../borrow_check/nll/type_check/liveness.rs | 2 +- .../borrow_check/nll/type_check/mod.rs | 90 ++++++++++--------- 2 files changed, 48 insertions(+), 44 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs index f27de92c6215a..d84dcc5678279 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs @@ -199,7 +199,7 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo }); if let Some(data) = &drop_data.region_constraint_data { - self.cx.push_region_constraints(location.at_self(), data); + self.cx.push_region_constraints(location.boring(), data); } drop_data.dropck_result.report_overflows( diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index da12ce89f9d68..404e04ef4ccef 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -288,7 +288,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { tcx.predicates_of(def_id).instantiate(tcx, substs); type_checker.normalize_and_prove_instantiated_predicates( instantiated_predicates, - location, + location.boring(), ); } @@ -313,10 +313,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { debug!("sanitize_constant: expected_ty={:?}", expected_ty); - if let Err(terr) = self - .cx - .eq_types(expected_ty, constant.ty, location.at_self()) - { + if let Err(terr) = self.cx.eq_types(expected_ty, constant.ty, location.boring()) { span_mirbug!( self, constant, @@ -346,7 +343,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { let sty = self.sanitize_type(place, sty); let ty = self.tcx().type_of(def_id); let ty = self.cx.normalize(ty, location); - if let Err(terr) = self.cx.eq_types(ty, sty, location.at_self()) { + if let Err(terr) = self.cx.eq_types(ty, sty, location.boring()) { span_mirbug!( self, place, @@ -390,7 +387,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { // (e.g., #29149). Note that we decide to use Copy before knowing whether the bounds // fully apply: in effect, the rule is that if a value of some type could implement // Copy, then it must. - self.cx.prove_trait_ref(trait_ref, location); + self.cx.prove_trait_ref(trait_ref, location.interesting()); } place_ty } @@ -489,7 +486,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ProjectionElem::Field(field, fty) => { let fty = self.sanitize_type(place, fty); match self.field_ty(place, base, field, location) { - Ok(ty) => if let Err(terr) = self.cx.eq_types(ty, fty, location.at_self()) { + Ok(ty) => if let Err(terr) = self.cx.eq_types(ty, fty, location.boring()) { span_mirbug!( self, place, @@ -787,7 +784,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { StatementKind::Assign(ref place, ref rv) => { let place_ty = place.ty(mir, tcx).to_ty(tcx); let rv_ty = rv.ty(mir, tcx); - if let Err(terr) = self.sub_types(rv_ty, place_ty, location.at_self()) { + if let Err(terr) = self.sub_types(rv_ty, place_ty, location.interesting()) { span_mirbug!( self, stmt, @@ -802,7 +799,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { def_id: tcx.lang_items().sized_trait().unwrap(), substs: tcx.mk_substs_trait(place_ty, &[]), }; - self.prove_trait_ref(trait_ref, location); + self.prove_trait_ref(trait_ref, location.interesting()); } StatementKind::SetDiscriminant { ref place, @@ -909,7 +906,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { .. } => { let discr_ty = discr.ty(mir, tcx); - if let Err(terr) = self.sub_types(discr_ty, switch_ty, term_location.at_self()) { + if let Err(terr) = self.sub_types(discr_ty, switch_ty, term_location.boring()) { span_mirbug!( self, term, @@ -949,7 +946,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.prove_predicates( sig.inputs().iter().map(|ty| ty::Predicate::WellFormed(ty)), - term_location, + term_location.boring(), ); // The ordinary liveness rules will ensure that all @@ -991,7 +988,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match mir.yield_ty { None => span_mirbug!(self, term, "yield in non-generator"), Some(ty) => { - if let Err(terr) = self.sub_types(value_ty, ty, term_location.at_self()) { + if let Err(terr) = self.sub_types(value_ty, ty, term_location.interesting()) { span_mirbug!( self, term, @@ -1056,7 +1053,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() { let op_arg_ty = op_arg.ty(mir, self.tcx()); - if let Err(terr) = self.sub_types(op_arg_ty, fn_arg, term_location.at_self()) { + if let Err(terr) = self.sub_types(op_arg_ty, fn_arg, term_location.interesting()) { span_mirbug!( self, term, @@ -1284,7 +1281,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { substs: tcx.mk_substs_trait(operand_ty, &[]), }; - self.prove_trait_ref(trait_ref, location); + self.prove_trait_ref(trait_ref, location.interesting()); }, Rvalue::NullaryOp(_, ty) => { @@ -1293,7 +1290,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { substs: tcx.mk_substs_trait(ty, &[]), }; - self.prove_trait_ref(trait_ref, location); + self.prove_trait_ref(trait_ref, location.interesting()); } Rvalue::Cast(cast_kind, op, ty) => match cast_kind { @@ -1309,7 +1306,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig); - if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) { + if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.interesting()) { span_mirbug!( self, rvalue, @@ -1330,7 +1327,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }; let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig); - if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) { + if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.interesting()) { span_mirbug!( self, rvalue, @@ -1354,7 +1351,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig); - if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) { + if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.interesting()) { span_mirbug!( self, rvalue, @@ -1373,7 +1370,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { substs: tcx.mk_substs_trait(op.ty(mir, tcx), &[ty.into()]), }; - self.prove_trait_ref(trait_ref, location); + self.prove_trait_ref(trait_ref, location.interesting()); } CastKind::Misc => {} @@ -1422,7 +1419,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } }; let operand_ty = operand.ty(mir, tcx); - if let Err(terr) = self.sub_types(operand_ty, field_ty, location.at_self()) { + + if let Err(terr) = self.sub_types(operand_ty, field_ty, location.boring()) { span_mirbug!( self, rvalue, @@ -1483,8 +1481,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { *substs, ); + // Hmm, are these constraints *really* boring? self.push_region_constraints( - location.at_self(), + location.boring(), &closure_constraints, ); } @@ -1499,53 +1498,53 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(), }; - self.normalize_and_prove_instantiated_predicates(instantiated_predicates, location); + self.normalize_and_prove_instantiated_predicates(instantiated_predicates, location.boring()); } - fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, location: Location) { + fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, locations: Locations) { self.prove_predicates( Some(ty::Predicate::Trait( trait_ref.to_poly_trait_ref().to_poly_trait_predicate(), )), - location, + locations, ); } fn normalize_and_prove_instantiated_predicates( &mut self, instantiated_predicates: ty::InstantiatedPredicates<'tcx>, - location: Location, + locations: Locations, ) { for predicate in instantiated_predicates.predicates { - let predicate = self.normalize(predicate, location); - self.prove_predicate(predicate, location); + let predicate = self.normalize(predicate, locations); + self.prove_predicate(predicate, locations); } } fn prove_predicates( &mut self, predicates: impl IntoIterator<Item = ty::Predicate<'tcx>>, - location: Location, + locations: Locations, ) { for predicate in predicates { debug!( - "prove_predicates(predicate={:?}, location={:?})", - predicate, location, + "prove_predicates(predicate={:?}, locations={:?})", + predicate, locations, ); - self.prove_predicate(predicate, location); + self.prove_predicate(predicate, locations); } } - fn prove_predicate(&mut self, predicate: ty::Predicate<'tcx>, location: Location) { + fn prove_predicate(&mut self, predicate: ty::Predicate<'tcx>, locations: Locations) { debug!( "prove_predicate(predicate={:?}, location={:?})", - predicate, location, + predicate, locations, ); let param_env = self.param_env; self.fully_perform_op( - location.at_self(), + locations, param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)), ).unwrap_or_else(|NoSolution| { span_mirbug!(self, NoSolution, "could not prove {:?}", predicate); @@ -1632,20 +1631,25 @@ impl MirPass for TypeckMir { } trait AtLocation { - /// Creates a `Locations` where `self` is both the from-location - /// and the at-location. This means that any required region - /// relationships must hold upon entering the statement/terminator - /// indicated by `self`. This is typically used when processing - /// "inputs" to the given location. - fn at_self(self) -> Locations; + /// Indicates a "boring" constraint that the user probably + /// woudln't want to see highlights. + fn boring(self) -> Locations; + + /// Indicates an "interesting" edge, which is of significance only + /// for diagnostics. + fn interesting(self) -> Locations; } impl AtLocation for Location { - fn at_self(self) -> Locations { + fn boring(self) -> Locations { Locations::Pair { from_location: self, } } + + fn interesting(self) -> Locations { + self.boring() + } } trait NormalizeLocation: fmt::Debug + Copy { @@ -1660,6 +1664,6 @@ impl NormalizeLocation for Locations { impl NormalizeLocation for Location { fn to_locations(self) -> Locations { - self.at_self() + self.boring() } } From 0b620186fdac2a8a671d445ac25ef33d1df44153 Mon Sep 17 00:00:00 2001 From: Niko Matsakis <niko@alum.mit.edu> Date: Mon, 4 Jun 2018 12:25:12 -0400 Subject: [PATCH 04/15] propagate boring vs interesting causal info for constraints/tests --- .../borrow_check/nll/constraint_generation.rs | 6 +- .../borrow_check/nll/constraint_set.rs | 10 +-- .../borrow_check/nll/region_infer/dump_mir.rs | 4 +- .../borrow_check/nll/region_infer/graphviz.rs | 2 +- .../borrow_check/nll/region_infer/mod.rs | 33 +++++----- .../nll/type_check/constraint_conversion.rs | 26 ++------ .../borrow_check/nll/type_check/mod.rs | 61 +++++++++++-------- 7 files changed, 70 insertions(+), 72 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 6e9574e2d5b73..68aa9aeabf811 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -10,9 +10,10 @@ use borrow_check::borrow_set::BorrowSet; use borrow_check::location::LocationTable; +use borrow_check::nll::ToRegionVid; use borrow_check::nll::facts::AllFacts; use borrow_check::nll::region_infer::{Cause, RegionInferenceContext}; -use borrow_check::nll::ToRegionVid; +use borrow_check::nll::type_check::AtLocation; use rustc::hir; use rustc::infer::InferCtxt; use rustc::mir::visit::TyContext; @@ -310,9 +311,8 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.sty { ty::TyRef(ref_region, _, mutbl) => { - let span = self.mir.source_info(location).span; self.regioncx.add_outlives( - span, + location.boring(), ref_region.to_region_vid(), borrow_region.to_region_vid(), ); diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs index ac3ab961d0a15..3bdf78ff3db54 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_set.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs @@ -10,9 +10,9 @@ use rustc::ty::RegionVid; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use borrow_check::nll::type_check::Locations; use std::fmt; -use syntax_pos::Span; use std::ops::Deref; #[derive(Clone, Default)] @@ -23,8 +23,8 @@ crate struct ConstraintSet { impl ConstraintSet { pub fn push(&mut self, constraint: OutlivesConstraint) { debug!( - "add_outlives({:?}: {:?})", - constraint.sup, constraint.sub + "add_outlives({:?}: {:?} @ {:?})", + constraint.sup, constraint.sub, constraint.locations ); if constraint.sup == constraint.sub { // 'a: 'a is pretty uninteresting @@ -96,7 +96,7 @@ pub struct OutlivesConstraint { pub next: Option<ConstraintIndex>, /// Where did this constraint arise? - pub span: Span, + pub locations: Locations, } impl fmt::Debug for OutlivesConstraint { @@ -104,7 +104,7 @@ impl fmt::Debug for OutlivesConstraint { write!( formatter, "({:?}: {:?}) due to {:?}", - self.sup, self.sub, self.span + self.sup, self.sub, self.locations ) } } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs index c68bb15552fc7..88d9f46e340d3 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs @@ -82,14 +82,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { let OutlivesConstraint { sup, sub, - span, + locations, next: _, } = constraint; with_msg(&format!( "{:?}: {:?} due to {:?}", sup, sub, - span + locations, ))?; } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs index 15896413af991..0116fbcfc8860 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs @@ -44,7 +44,7 @@ impl<'this, 'tcx> dot::Labeller<'this> for RegionInferenceContext<'tcx> { dot::LabelText::LabelStr(format!("{:?}", n).into_cow()) } fn edge_label(&'this self, e: &OutlivesConstraint) -> dot::LabelText<'this> { - dot::LabelText::LabelStr(format!("{:?}", e.span).into_cow()) + dot::LabelText::LabelStr(format!("{:?}", e.locations).into_cow()) } } 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 fd8a62b4deb33..ace701eeb789c 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -11,6 +11,7 @@ use super::universal_regions::UniversalRegions; use borrow_check::nll::region_infer::values::ToElementIndex; use borrow_check::nll::constraint_set::{ConstraintIndex, ConstraintSet, OutlivesConstraint}; +use borrow_check::nll::type_check::Locations; use rustc::hir::def_id::DefId; use rustc::infer::canonical::QueryRegionConstraint; use rustc::infer::error_reporting::nice_region_error::NiceRegionError; @@ -154,11 +155,8 @@ pub struct TypeTest<'tcx> { /// The region `'x` that the type must outlive. pub lower_bound: RegionVid, - /// The point where the outlives relation must hold. - pub point: Location, - - /// Where did this constraint arise? - pub span: Span, + /// Where did this constraint arise and why? + pub locations: Locations, /// A test which, if met by the region `'x`, proves that this type /// constraint is satisfied. @@ -356,13 +354,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`. pub(super) fn add_outlives( &mut self, - span: Span, + locations: Locations, sup: RegionVid, sub: RegionVid, ) { assert!(self.inferred_values.is_none(), "values already inferred"); self.constraints.push(OutlivesConstraint { - span, + locations, sup, sub, next: None, @@ -408,7 +406,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_type_tests(infcx, mir, mir_def_id, outlives_requirements.as_mut()); - self.check_universal_regions(infcx, mir_def_id, outlives_requirements.as_mut()); + self.check_universal_regions(infcx, mir, mir_def_id, outlives_requirements.as_mut()); let outlives_requirements = outlives_requirements.unwrap_or(vec![]); @@ -506,7 +504,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements { - if self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements) { + if self.try_promote_type_test(infcx, mir, type_test, propagated_outlives_requirements) { continue; } } @@ -515,9 +513,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { let lower_bound_region = self.to_error_region(type_test.lower_bound); if let Some(lower_bound_region) = lower_bound_region { let region_scope_tree = &tcx.region_scope_tree(mir_def_id); + let type_test_span = type_test.locations.span(mir); infcx.report_generic_bound_failure( region_scope_tree, - type_test.span, + type_test_span, None, type_test.generic_kind, lower_bound_region, @@ -532,8 +531,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { // to report it; we could probably handle it by // iterating over the universal regions and reporting // an error that multiple bounds are required. + let type_test_span = type_test.locations.span(mir); tcx.sess.span_err( - type_test.span, + type_test_span, &format!("`{}` does not live long enough", type_test.generic_kind,), ); } @@ -566,6 +566,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn try_promote_type_test<'gcx>( &self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, + mir: &Mir<'tcx>, type_test: &TypeTest<'tcx>, propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'gcx>>, ) -> bool { @@ -574,8 +575,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let TypeTest { generic_kind, lower_bound, - point: _, - span, + locations, test: _, } = type_test; @@ -599,7 +599,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { propagated_outlives_requirements.push(ClosureOutlivesRequirement { subject, outlived_free_region: lower_bound_plus, - blame_span: *span, + blame_span: locations.span(mir), }); true } @@ -865,6 +865,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn check_universal_regions<'gcx>( &self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, + mir: &Mir<'tcx>, mir_def_id: DefId, mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>, ) { @@ -881,6 +882,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { for (fr, _) in universal_definitions { self.check_universal_region( infcx, + mir, mir_def_id, fr, &mut propagated_outlives_requirements, @@ -899,6 +901,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn check_universal_region<'gcx>( &self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, + mir: &Mir<'tcx>, mir_def_id: DefId, longer_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>, @@ -921,7 +924,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); let blame_index = self.blame_constraint(longer_fr, shorter_fr); - let blame_span = self.constraints[blame_index].span; + let blame_span = self.constraints[blame_index].locations.span(mir); if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { // Shrink `fr` until we find a non-local region (if we do). diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs index 2ee74dc6095fa..27bd50427772d 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs @@ -19,14 +19,12 @@ use rustc::infer::canonical::QueryRegionConstraint; use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; use rustc::infer::region_constraints::{GenericKind, VerifyBound}; use rustc::infer::{self, SubregionOrigin}; -use rustc::mir::{Location, Mir}; use rustc::ty::subst::UnpackedKind; use rustc::ty::{self, TyCtxt}; -use syntax::codemap::Span; +use syntax_pos::DUMMY_SP; crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, location_table: &'a LocationTable, region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)], @@ -41,7 +39,6 @@ crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> { impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { crate fn new( tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, location_table: &'a LocationTable, region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)], @@ -54,7 +51,6 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { ) -> Self { Self { tcx, - mir, universal_regions, location_table, region_bound_pairs, @@ -91,8 +87,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { // will start to fail. let ty::OutlivesPredicate(k1, r2) = query_constraint.no_late_bound_regions().unwrap_or_else(|| { - span_bug!( - self.span(), + bug!( "query_constraint {:?} contained bound regions", query_constraint, ); @@ -125,7 +120,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { UnpackedKind::Type(t1) => { // we don't actually use this for anything, but // the `TypeOutlives` code needs an origin. - let origin = infer::RelateParamBound(self.span(), t1); + let origin = infer::RelateParamBound(DUMMY_SP, t1); TypeOutlives::new( &mut *self, @@ -146,15 +141,12 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { ) -> TypeTest<'tcx> { let lower_bound = self.to_region_vid(region); - let point = self.locations.from_location().unwrap_or(Location::START); - let test = self.verify_bound_to_region_test(&bound); TypeTest { generic_kind, lower_bound, - point, - span: self.span(), + locations: self.locations, test, } } @@ -189,17 +181,9 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { self.universal_regions.to_region_vid(r) } - fn span(&self) -> Span { - self.mir - .source_info(self.locations.from_location().unwrap_or(Location::START)) - .span - } - fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) { - let span = self.span(); - self.outlives_constraints.push(OutlivesConstraint { - span, + locations: self.locations, sub, sup, next: None, diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 404e04ef4ccef..782b07d02f438 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -147,7 +147,6 @@ fn type_check_internal<'gcx, 'tcx>( region_bound_pairs, implicit_region_bound, borrowck_context, - mir, ); let errors_reported = { let mut verifier = TypeVerifier::new(&mut checker, mir); @@ -597,7 +596,6 @@ struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { reported_errors: FxHashSet<(Ty<'tcx>, Span)>, constraints: MirTypeckRegionConstraints<'tcx>, borrowck_context: Option<BorrowCheckContext<'a, 'tcx>>, - mir: &'a Mir<'tcx>, } struct BorrowCheckContext<'a, 'tcx: 'a> { @@ -628,7 +626,7 @@ crate struct MirTypeckRegionConstraints<'tcx> { /// required to hold. Normally, this is at a particular point which /// created the obligation, but for constraints that the user gave, we /// want the constraint to hold at all points. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum Locations { /// Indicates that a type constraint should always be true. This /// is particularly important in the new borrowck analysis for @@ -663,21 +661,42 @@ pub enum Locations { /// assigned to `x` are of `'static` lifetime. All, - Pair { - /// The location in the MIR that generated these constraints. - /// This is intended for error reporting and diagnosis; the - /// constraints may *take effect* at a distinct spot. - from_location: Location, - }, + /// A "boring" constraint (caused by the given location) is one that + /// the user probably doesn't want to see described in diagnostics, + /// because it is kind of an artifact of the type system setup. + /// + /// Example: `x = Foo { field: y }` technically creates + /// intermediate regions representing the "type of `Foo { field: y + /// }`", and data flows from `y` into those variables, but they + /// are not very interesting. The assignment into `x` on the other + /// hand might be. + Boring(Location), + + /// An *important* outlives constraint (caused by the given + /// location) is one that would be useful to highlight in + /// diagnostics, because it represents a point where references + /// flow from one spot to another (e.g., `x = y`) + Interesting(Location), } impl Locations { pub fn from_location(&self) -> Option<Location> { match self { Locations::All => None, - Locations::Pair { from_location, .. } => Some(*from_location), + Locations::Boring(from_location) | Locations::Interesting(from_location) => { + Some(*from_location) + } } } + + /// Gets a span representing the location. + pub fn span(&self, mir: &Mir<'_>) -> Span { + let span_location = match self { + Locations::All => Location::START, + Locations::Boring(l) | Locations::Interesting(l) => *l, + }; + mir.source_info(span_location).span + } } impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { @@ -688,7 +707,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)], implicit_region_bound: Option<ty::Region<'tcx>>, borrowck_context: Option<BorrowCheckContext<'a, 'tcx>>, - mir: &'a Mir<'tcx>, ) -> Self { TypeChecker { infcx, @@ -698,7 +716,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { region_bound_pairs, implicit_region_bound, borrowck_context, - mir, reported_errors: FxHashSet(), constraints: MirTypeckRegionConstraints::default(), } @@ -741,7 +758,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { if let Some(borrowck_context) = &mut self.borrowck_context { constraint_conversion::ConstraintConversion::new( self.infcx.tcx, - self.mir, borrowck_context.universal_regions, borrowck_context.location_table, self.region_bound_pairs, @@ -886,9 +902,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let place_ty = location.ty(mir, tcx).to_ty(tcx); let rv_ty = value.ty(mir, tcx); - let locations = Locations::Pair { - from_location: term_location, - }; + let locations = term_location.interesting(); if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) { span_mirbug!( self, @@ -988,7 +1002,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match mir.yield_ty { None => span_mirbug!(self, term, "yield in non-generator"), Some(ty) => { - if let Err(terr) = self.sub_types(value_ty, ty, term_location.interesting()) { + if let Err(terr) = self.sub_types(value_ty, ty, term_location.interesting()) + { span_mirbug!( self, term, @@ -1016,9 +1031,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match *destination { Some((ref dest, _target_block)) => { let dest_ty = dest.ty(mir, tcx).to_ty(tcx); - let locations = Locations::Pair { - from_location: term_location, - }; + let locations = term_location.interesting(); if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations) { span_mirbug!( self, @@ -1630,7 +1643,7 @@ impl MirPass for TypeckMir { } } -trait AtLocation { +pub trait AtLocation { /// Indicates a "boring" constraint that the user probably /// woudln't want to see highlights. fn boring(self) -> Locations; @@ -1642,13 +1655,11 @@ trait AtLocation { impl AtLocation for Location { fn boring(self) -> Locations { - Locations::Pair { - from_location: self, - } + Locations::Boring(self) } fn interesting(self) -> Locations { - self.boring() + Locations::Interesting(self) } } From 9e2157fdcac358646d2ff2ca888d2a63df565239 Mon Sep 17 00:00:00 2001 From: Niko Matsakis <niko@alum.mit.edu> Date: Tue, 5 Jun 2018 06:13:28 -0400 Subject: [PATCH 05/15] don't consider assignments to temporaries "interesting" --- .../borrow_check/nll/type_check/mod.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 782b07d02f438..911e543425916 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -798,9 +798,21 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let tcx = self.tcx(); match stmt.kind { StatementKind::Assign(ref place, ref rv) => { + // Assignments to temporaries are not "interesting"; + // they are not caused by the user, but rather artifacts + // of lowering. Assignments to other sorts of places *are* interesting + // though. + let is_temp = if let Place::Local(l) = place { + !mir.local_decls[*l].is_user_variable.is_some() + } else { + false + }; + + let locations = if is_temp { location.boring() } else { location.interesting() }; + let place_ty = place.ty(mir, tcx).to_ty(tcx); let rv_ty = rv.ty(mir, tcx); - if let Err(terr) = self.sub_types(rv_ty, place_ty, location.interesting()) { + if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) { span_mirbug!( self, stmt, From 56274be4b541599b0a1a02c710cc293659715345 Mon Sep 17 00:00:00 2001 From: David Wood <david@davidtw.co> Date: Mon, 11 Jun 2018 23:07:54 +0100 Subject: [PATCH 06/15] Added bfs for constraint paths from regions. --- .../borrow_check/nll/region_infer/mod.rs | 110 +++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) 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 ace701eeb789c..1fa530f5492ab 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -26,6 +26,7 @@ use rustc::mir::{ use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc::util::common::{self, ErrorReported}; use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use std::rc::Rc; use syntax_pos::Span; @@ -504,7 +505,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { } if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements { - if self.try_promote_type_test(infcx, mir, type_test, propagated_outlives_requirements) { + if self.try_promote_type_test(infcx, mir, type_test, + propagated_outlives_requirements) { continue; } } @@ -963,6 +965,104 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } + fn find_constraint_paths_from_region( + &self, + r0: RegionVid + ) -> Vec<Vec<ConstraintIndex>> { + let constraints = self.constraints.clone(); + + // Mapping of regions to the previous region and constraint index that led to it. + let mut previous = FxHashMap(); + // Current region in traversal. + let mut current = r0; + // Regions yet to be visited. + let mut next = vec! [ current ]; + // Regions that have been visited. + let mut visited = FxHashSet(); + // Ends of paths. + let mut end_regions: Vec<RegionVid> = Vec::new(); + + // When we've still got points to visit... + while !next.is_empty() { + // ...take the next point... + debug!("find_constraint_paths_from_region: next={:?}", next); + current = next.pop().unwrap(); // Can unwrap here as we know the vector is not empty. + + // ...find the edges containing it... + let mut upcoming = Vec::new(); + for (index, constraint) in constraints.iter_enumerated() { + if constraint.sub == current { + // ...add the regions that join us with to the path we've taken... + debug!("find_constraint_paths_from_region: index={:?} constraint={:?}", + index, constraint); + let next_region = constraint.sup.clone(); + + // ...unless we've visited it since this was added... + if visited.contains(&next_region) { + debug!("find_constraint_paths_from_region: skipping as visited"); + continue; + } + + previous.insert(next_region, (index, Some(current))); + upcoming.push(next_region); + } + } + + if upcoming.is_empty() { + // If we didn't find any edges then this is the end of a path... + debug!("find_constraint_paths_from_region: new end region current={:?}", current); + end_regions.push(current); + } else { + // ...but, if we did find edges, then add these to the regions yet to visit... + debug!("find_constraint_paths_from_region: extend next upcoming={:?}", upcoming); + next.extend(upcoming); + } + + // ...and don't visit it again. + visited.insert(current.clone()); + debug!("find_constraint_paths_from_region: next={:?} visited={:?}", next, visited); + } + + // Now we've visited each point, compute the final paths. + let mut paths: Vec<Vec<ConstraintIndex>> = Vec::new(); + debug!("find_constraint_paths_from_region: end_regions={:?}", end_regions); + for end_region in end_regions { + debug!("find_constraint_paths_from_region: end_region={:?}", end_region); + + // Get the constraint and region that led to this end point. + // We can unwrap as we know if end_point was in the vector that it + // must also be in our previous map. + let (mut index, mut region) = previous.get(&end_region).unwrap(); + debug!("find_constraint_paths_from_region: index={:?} region={:?}", index, region); + + // Keep track of the indices. + let mut path: Vec<ConstraintIndex> = vec![index]; + + while region.is_some() && region != Some(r0) { + let p = previous.get(®ion.unwrap()).unwrap(); + index = p.0; + region = p.1; + + debug!("find_constraint_paths_from_region: index={:?} region={:?}", index, region); + path.push(index); + } + + // Add to our paths. + paths.push(path); + } + + debug!("find_constraint_paths_from_region: paths={:?}", paths); + paths + } + + fn constraint_is_interesting(&self, index: &ConstraintIndex) -> bool { + self.constraints.get(*index).filter(|constraint| { + debug!("constraint_is_interesting: locations={:?} constraint={:?}", + constraint.locations, constraint); + if let Locations::Interesting(_) = constraint.locations { true } else { false } + }).is_some() + } + /// Report an error because the universal region `fr` was required to outlive /// `outlived_fr` but it is not known to do so. For example: /// @@ -992,6 +1092,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } + let constraints = self.find_constraint_paths_from_region(fr.clone()); + let path = constraints.iter().min_by_key(|p| p.len()).unwrap(); + debug!("report_error: path={:?}", path); + let path = path.iter() + .filter(|index| self.constraint_is_interesting(index)) + .collect::<Vec<&ConstraintIndex>>(); + debug!("report_error: path={:?}", path); + let fr_string = match fr_name { Some(r) => format!("free region `{}`", r), None => format!("free region `{:?}`", fr), From fd0806618c259a31da2c7824610d3224e71dad34 Mon Sep 17 00:00:00 2001 From: David Wood <david@davidtw.co> Date: Tue, 12 Jun 2018 20:43:14 +0100 Subject: [PATCH 07/15] Constraints are now being categorized, sorted and the error labelled. Categorization needs a bit of work. --- .../borrow_check/nll/constraint_set.rs | 36 +++++++ .../borrow_check/nll/region_infer/mod.rs | 96 +++++++++++++++---- 2 files changed, 116 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs index 3bdf78ff3db54..232242b552f7f 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_set.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs @@ -13,6 +13,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use borrow_check::nll::type_check::Locations; use std::fmt; +use std::cmp::Ordering; use std::ops::Deref; #[derive(Clone, Default)] @@ -109,4 +110,39 @@ impl fmt::Debug for OutlivesConstraint { } } +/// Constraints that are considered interesting can be categorized to +/// determine why they are interesting. +#[derive(Debug, Eq, PartialEq)] +crate enum ConstraintCategory { + Assignment, + CallArgument, + Cast, + Other, +} + +impl Ord for ConstraintCategory { + fn cmp(&self, other: &Self) -> Ordering { + if self == other { + return Ordering::Equal; + } + + match (self, other) { + (ConstraintCategory::Assignment, _) => Ordering::Greater, + (_, ConstraintCategory::Assignment) => Ordering::Less, + (ConstraintCategory::CallArgument, _) => Ordering::Greater, + (_, ConstraintCategory::CallArgument) => Ordering::Less, + (ConstraintCategory::Cast, _) => Ordering::Greater, + (_, ConstraintCategory::Cast) => Ordering::Less, + (ConstraintCategory::Other, _) => Ordering::Greater, + } + } +} + +impl PartialOrd for ConstraintCategory { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + + newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" }); 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 1fa530f5492ab..713ff7002b324 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -10,7 +10,8 @@ use super::universal_regions::UniversalRegions; use borrow_check::nll::region_infer::values::ToElementIndex; -use borrow_check::nll::constraint_set::{ConstraintIndex, ConstraintSet, OutlivesConstraint}; +use borrow_check::nll::constraint_set::{ConstraintIndex, ConstraintCategory, ConstraintSet}; +use borrow_check::nll::constraint_set::{OutlivesConstraint}; use borrow_check::nll::type_check::Locations; use rustc::hir::def_id::DefId; use rustc::infer::canonical::QueryRegionConstraint; @@ -21,13 +22,14 @@ use rustc::infer::NLLRegionVariableOrigin; use rustc::infer::RegionVariableOrigin; use rustc::mir::{ ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location, - Mir, + Mir, StatementKind, TerminatorKind, Rvalue }; use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc::util::common::{self, ErrorReported}; use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; + use std::rc::Rc; use syntax_pos::Span; @@ -961,10 +963,13 @@ 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(infcx, mir_def_id, longer_fr, shorter_fr, blame_span); + self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, blame_span); } } + /// When reporting an error, it is useful to be able to determine which constraints influenced + /// the region being reported as an error. This function finds all of the paths from the + /// constraint. fn find_constraint_paths_from_region( &self, r0: RegionVid @@ -1055,6 +1060,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { paths } + /// This function will return true if a constraint is interesting and false if a constraint + /// is not. It is useful in filtering constraint paths to only interesting points. fn constraint_is_interesting(&self, index: &ConstraintIndex) -> bool { self.constraints.get(*index).filter(|constraint| { debug!("constraint_is_interesting: locations={:?} constraint={:?}", @@ -1063,6 +1070,32 @@ impl<'tcx> RegionInferenceContext<'tcx> { }).is_some() } + /// This function classifies a constraint from a location. + fn classify_constraint(&self, location: Location, mir: &Mir<'tcx>) -> ConstraintCategory { + let data = &mir[location.block]; + if location.statement_index == data.statements.len() { + if let Some(ref terminator) = data.terminator { + match terminator.kind { + TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment, + TerminatorKind::Call { .. } => ConstraintCategory::CallArgument, + _ => ConstraintCategory::Other, + } + } else { + ConstraintCategory::Other + } + } else { + let statement = &data.statements[location.statement_index]; + match statement.kind { + StatementKind::Assign(_, ref rvalue) => match rvalue { + Rvalue::Cast(..) => ConstraintCategory::Cast, + Rvalue::Use(..) => ConstraintCategory::Assignment, + _ => ConstraintCategory::Other, + }, + _ => ConstraintCategory::Other, + } + } + } + /// Report an error because the universal region `fr` was required to outlive /// `outlived_fr` but it is not known to do so. For example: /// @@ -1073,6 +1106,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`. fn report_error( &self, + mir: &Mir<'tcx>, infcx: &InferCtxt<'_, '_, 'tcx>, mir_def_id: DefId, fr: RegionVid, @@ -1095,27 +1129,57 @@ impl<'tcx> RegionInferenceContext<'tcx> { let constraints = self.find_constraint_paths_from_region(fr.clone()); let path = constraints.iter().min_by_key(|p| p.len()).unwrap(); debug!("report_error: path={:?}", path); + let path = path.iter() .filter(|index| self.constraint_is_interesting(index)) .collect::<Vec<&ConstraintIndex>>(); debug!("report_error: path={:?}", path); - let fr_string = match fr_name { - Some(r) => format!("free region `{}`", r), - None => format!("free region `{:?}`", fr), - }; + let mut categorized_path = path.iter().filter_map(|index| { + self.constraints.get(**index).iter().filter_map(|constraint| { + let span = constraint.locations.span(mir); + constraint.locations.from_location().iter().filter_map(|location| { + let classification = self.classify_constraint(*location, mir); + Some((classification, span)) + }).next() + }).next() + }).collect::<Vec<(ConstraintCategory, Span)>>(); + debug!("report_error: categorized_path={:?}", categorized_path); + + categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0)); + debug!("report_error: sorted_path={:?}", categorized_path); + + if categorized_path.len() > 0 { + let blame_constraint = &categorized_path[0]; + + let mut diag = infcx.tcx.sess.struct_span_err( + blame_constraint.1, + &format!("{:?}", blame_constraint.0), + ); - let outlived_fr_string = match outlived_fr_name { - Some(r) => format!("free region `{}`", r), - None => format!("free region `{:?}`", outlived_fr), - }; + for secondary in categorized_path.iter().skip(1) { + diag.span_label(secondary.1, format!("{:?}", secondary.0)); + } - let mut diag = infcx.tcx.sess.struct_span_err( - blame_span, - &format!("{} does not outlive {}", fr_string, outlived_fr_string,), - ); + diag.emit(); + } else { + let fr_string = match fr_name { + Some(r) => format!("free region `{}`", r), + None => format!("free region `{:?}`", fr), + }; + + let outlived_fr_string = match outlived_fr_name { + Some(r) => format!("free region `{}`", r), + None => format!("free region `{:?}`", outlived_fr), + }; + + let mut diag = infcx.tcx.sess.struct_span_err( + blame_span, + &format!("{} does not outlive {}", fr_string, outlived_fr_string,), + ); - diag.emit(); + diag.emit(); + } } crate fn why_region_contains_point(&self, fr1: RegionVid, elem: Location) -> Option<Cause> { From 58a723209d170634ecc4f9be02e9bc3659541125 Mon Sep 17 00:00:00 2001 From: David Wood <david@davidtw.co> Date: Wed, 20 Jun 2018 21:11:27 +0100 Subject: [PATCH 08/15] Switched to while let in DFS and deriving Ord on ConstraintCategory. --- .../borrow_check/nll/constraint_set.rs | 28 +------------------ .../borrow_check/nll/region_infer/mod.rs | 9 ++---- 2 files changed, 4 insertions(+), 33 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs index 232242b552f7f..d8c26960a7219 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_set.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs @@ -13,7 +13,6 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use borrow_check::nll::type_check::Locations; use std::fmt; -use std::cmp::Ordering; use std::ops::Deref; #[derive(Clone, Default)] @@ -112,7 +111,7 @@ impl fmt::Debug for OutlivesConstraint { /// Constraints that are considered interesting can be categorized to /// determine why they are interesting. -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] crate enum ConstraintCategory { Assignment, CallArgument, @@ -120,29 +119,4 @@ crate enum ConstraintCategory { Other, } -impl Ord for ConstraintCategory { - fn cmp(&self, other: &Self) -> Ordering { - if self == other { - return Ordering::Equal; - } - - match (self, other) { - (ConstraintCategory::Assignment, _) => Ordering::Greater, - (_, ConstraintCategory::Assignment) => Ordering::Less, - (ConstraintCategory::CallArgument, _) => Ordering::Greater, - (_, ConstraintCategory::CallArgument) => Ordering::Less, - (ConstraintCategory::Cast, _) => Ordering::Greater, - (_, ConstraintCategory::Cast) => Ordering::Less, - (ConstraintCategory::Other, _) => Ordering::Greater, - } - } -} - -impl PartialOrd for ConstraintCategory { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - - newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" }); 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 713ff7002b324..d7e818c50437d 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -978,20 +978,17 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Mapping of regions to the previous region and constraint index that led to it. let mut previous = FxHashMap(); - // Current region in traversal. - let mut current = r0; // Regions yet to be visited. - let mut next = vec! [ current ]; + let mut next = vec! [ r0 ]; // Regions that have been visited. let mut visited = FxHashSet(); // Ends of paths. let mut end_regions: Vec<RegionVid> = Vec::new(); // When we've still got points to visit... - while !next.is_empty() { + while let Some(current) = next.pop() { // ...take the next point... - debug!("find_constraint_paths_from_region: next={:?}", next); - current = next.pop().unwrap(); // Can unwrap here as we know the vector is not empty. + debug!("find_constraint_paths_from_region: current={:?} next={:?}", current, next); // ...find the edges containing it... let mut upcoming = Vec::new(); From 27ce0cca8e93885d16890e712a7bc4ac27475176 Mon Sep 17 00:00:00 2001 From: David Wood <david@davidtw.co> Date: Wed, 20 Jun 2018 21:34:34 +0100 Subject: [PATCH 09/15] Moved region inference error reporting into own module. --- .../borrow_check/nll/constraint_set.rs | 10 - .../nll/region_infer/error_reporting.rs | 324 ++++++++++++++++++ .../borrow_check/nll/region_infer/mod.rs | 302 +--------------- 3 files changed, 328 insertions(+), 308 deletions(-) create mode 100644 src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs index d8c26960a7219..3bdf78ff3db54 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_set.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs @@ -109,14 +109,4 @@ impl fmt::Debug for OutlivesConstraint { } } -/// Constraints that are considered interesting can be categorized to -/// determine why they are interesting. -#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] -crate enum ConstraintCategory { - Assignment, - CallArgument, - Cast, - Other, -} - newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" }); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs new file mode 100644 index 0000000000000..261bc31b6f606 --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs @@ -0,0 +1,324 @@ +// 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::{Cause, ConstraintIndex, RegionInferenceContext}; +use borrow_check::nll::region_infer::values::ToElementIndex; +use borrow_check::nll::type_check::Locations; +use rustc::hir::def_id::DefId; +use rustc::infer::InferCtxt; +use rustc::infer::error_reporting::nice_region_error::NiceRegionError; +use rustc::mir::{Location, Mir, StatementKind, TerminatorKind, Rvalue}; +use rustc::ty::RegionVid; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::indexed_vec::IndexVec; +use syntax_pos::Span; + +/// Constraints that are considered interesting can be categorized to +/// determine why they are interesting. +#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)] +enum ConstraintCategory { + Assignment, + Cast, + CallArgument, + Other, +} + +impl<'tcx> RegionInferenceContext<'tcx> { + /// When reporting an error, it is useful to be able to determine which constraints influenced + /// the region being reported as an error. This function finds all of the paths from the + /// constraint. + fn find_constraint_paths_from_region( + &self, + r0: RegionVid + ) -> Vec<Vec<ConstraintIndex>> { + let constraints = self.constraints.clone(); + + // Mapping of regions to the previous region and constraint index that led to it. + let mut previous = FxHashMap(); + // Regions yet to be visited. + let mut next = vec! [ r0 ]; + // Regions that have been visited. + let mut visited = FxHashSet(); + // Ends of paths. + let mut end_regions: Vec<RegionVid> = Vec::new(); + + // When we've still got points to visit... + while let Some(current) = next.pop() { + // ...take the next point... + debug!("find_constraint_paths_from_region: current={:?} next={:?}", current, next); + + // ...find the edges containing it... + let mut upcoming = Vec::new(); + for (index, constraint) in constraints.iter_enumerated() { + if constraint.sub == current { + // ...add the regions that join us with to the path we've taken... + debug!("find_constraint_paths_from_region: index={:?} constraint={:?}", + index, constraint); + let next_region = constraint.sup.clone(); + + // ...unless we've visited it since this was added... + if visited.contains(&next_region) { + debug!("find_constraint_paths_from_region: skipping as visited"); + continue; + } + + previous.insert(next_region, (index, Some(current))); + upcoming.push(next_region); + } + } + + if upcoming.is_empty() { + // If we didn't find any edges then this is the end of a path... + debug!("find_constraint_paths_from_region: new end region current={:?}", current); + end_regions.push(current); + } else { + // ...but, if we did find edges, then add these to the regions yet to visit... + debug!("find_constraint_paths_from_region: extend next upcoming={:?}", upcoming); + next.extend(upcoming); + } + + // ...and don't visit it again. + visited.insert(current.clone()); + debug!("find_constraint_paths_from_region: next={:?} visited={:?}", next, visited); + } + + // Now we've visited each point, compute the final paths. + let mut paths: Vec<Vec<ConstraintIndex>> = Vec::new(); + debug!("find_constraint_paths_from_region: end_regions={:?}", end_regions); + for end_region in end_regions { + debug!("find_constraint_paths_from_region: end_region={:?}", end_region); + + // Get the constraint and region that led to this end point. + // We can unwrap as we know if end_point was in the vector that it + // must also be in our previous map. + let (mut index, mut region) = previous.get(&end_region).unwrap(); + debug!("find_constraint_paths_from_region: index={:?} region={:?}", index, region); + + // Keep track of the indices. + let mut path: Vec<ConstraintIndex> = vec![index]; + + while region.is_some() && region != Some(r0) { + let p = previous.get(®ion.unwrap()).unwrap(); + index = p.0; + region = p.1; + + debug!("find_constraint_paths_from_region: index={:?} region={:?}", index, region); + path.push(index); + } + + // Add to our paths. + paths.push(path); + } + + debug!("find_constraint_paths_from_region: paths={:?}", paths); + paths + } + + /// This function will return true if a constraint is interesting and false if a constraint + /// is not. It is useful in filtering constraint paths to only interesting points. + fn constraint_is_interesting(&self, index: &ConstraintIndex) -> bool { + self.constraints.get(*index).filter(|constraint| { + debug!("constraint_is_interesting: locations={:?} constraint={:?}", + constraint.locations, constraint); + if let Locations::Interesting(_) = constraint.locations { true } else { false } + }).is_some() + } + + /// This function classifies a constraint from a location. + fn classify_constraint(&self, location: Location, mir: &Mir<'tcx>) -> ConstraintCategory { + let data = &mir[location.block]; + if location.statement_index == data.statements.len() { + if let Some(ref terminator) = data.terminator { + match terminator.kind { + TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment, + TerminatorKind::Call { .. } => ConstraintCategory::CallArgument, + _ => ConstraintCategory::Other, + } + } else { + ConstraintCategory::Other + } + } else { + let statement = &data.statements[location.statement_index]; + match statement.kind { + StatementKind::Assign(_, ref rvalue) => match rvalue { + Rvalue::Cast(..) => ConstraintCategory::Cast, + Rvalue::Use(..) => ConstraintCategory::Assignment, + _ => ConstraintCategory::Other, + }, + _ => ConstraintCategory::Other, + } + } + } + + /// Report an error because the universal region `fr` was required to outlive + /// `outlived_fr` but it is not known to do so. For example: + /// + /// ``` + /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } + /// ``` + /// + /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`. + pub(super) fn report_error( + &self, + mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, '_, 'tcx>, + mir_def_id: DefId, + fr: RegionVid, + outlived_fr: RegionVid, + blame_span: Span, + ) { + // Obviously uncool error reporting. + + let fr_name = self.to_error_region(fr); + let outlived_fr_name = self.to_error_region(outlived_fr); + + if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) { + let tables = infcx.tcx.typeck_tables_of(mir_def_id); + let nice = NiceRegionError::new_from_span(infcx.tcx, blame_span, o, f, Some(tables)); + if let Some(_error_reported) = nice.try_report() { + return; + } + } + + let constraints = self.find_constraint_paths_from_region(fr.clone()); + let path = constraints.iter().min_by_key(|p| p.len()).unwrap(); + debug!("report_error: path={:?}", path); + + let path = path.iter() + .filter(|index| self.constraint_is_interesting(index)) + .collect::<Vec<&ConstraintIndex>>(); + debug!("report_error: path={:?}", path); + + let mut categorized_path = path.iter().filter_map(|index| { + self.constraints.get(**index).iter().filter_map(|constraint| { + let span = constraint.locations.span(mir); + constraint.locations.from_location().iter().filter_map(|location| { + let classification = self.classify_constraint(*location, mir); + Some((classification, span)) + }).next() + }).next() + }).collect::<Vec<(ConstraintCategory, Span)>>(); + debug!("report_error: categorized_path={:?}", categorized_path); + + categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0)); + debug!("report_error: sorted_path={:?}", categorized_path); + + if categorized_path.len() > 0 { + let blame_constraint = &categorized_path[0]; + + let mut diag = infcx.tcx.sess.struct_span_err( + blame_constraint.1, + &format!("{:?}", blame_constraint.0), + ); + + for secondary in categorized_path.iter().skip(1) { + diag.span_label(secondary.1, format!("{:?}", secondary.0)); + } + + diag.emit(); + } else { + let fr_string = match fr_name { + Some(r) => format!("free region `{}`", r), + None => format!("free region `{:?}`", fr), + }; + + let outlived_fr_string = match outlived_fr_name { + Some(r) => format!("free region `{}`", r), + None => format!("free region `{:?}`", outlived_fr), + }; + + let mut diag = infcx.tcx.sess.struct_span_err( + blame_span, + &format!("{} does not outlive {}", fr_string, outlived_fr_string,), + ); + + diag.emit(); + } + } + + crate fn why_region_contains_point(&self, fr1: RegionVid, elem: Location) -> Option<Cause> { + // Find some constraint `X: Y` where: + // - `fr1: X` transitively + // - and `Y` is live at `elem` + let index = self.blame_constraint(fr1, elem); + let region_sub = self.constraints[index].sub; + + // then return why `Y` was live at `elem` + self.liveness_constraints.cause(region_sub, elem) + } + + /// Tries to finds a good span to blame for the fact that `fr1` + /// contains `fr2`. + pub(super) fn blame_constraint(&self, fr1: RegionVid, + elem: impl ToElementIndex) -> ConstraintIndex { + // Find everything that influenced final value of `fr`. + let influenced_fr1 = self.dependencies(fr1); + + // Try to find some outlives constraint `'X: fr2` where `'X` + // influenced `fr1`. Blame that. + // + // NB, this is a pretty bad choice most of the time. In + // particular, the connection between `'X` and `fr1` may not + // be obvious to the user -- not to mention the naive notion + // of dependencies, which doesn't account for the locations of + // contraints at all. But it will do for now. + let relevant_constraint = self.constraints + .iter_enumerated() + .filter_map(|(i, constraint)| { + if !self.liveness_constraints.contains(constraint.sub, elem) { + None + } else { + influenced_fr1[constraint.sup] + .map(|distance| (distance, i)) + } + }) + .min() // constraining fr1 with fewer hops *ought* to be more obvious + .map(|(_dist, i)| i); + + relevant_constraint.unwrap_or_else(|| { + bug!( + "could not find any constraint to blame for {:?}: {:?}", + fr1, + elem, + ); + }) + } + + /// Finds all regions whose values `'a` may depend on in some way. + /// For each region, returns either `None` (does not influence + /// `'a`) or `Some(d)` which indicates that it influences `'a` + /// with distinct `d` (minimum number of edges that must be + /// traversed). + /// + /// Used during error reporting, extremely naive and inefficient. + fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> { + let mut result_set = IndexVec::from_elem(None, &self.definitions); + let mut changed = true; + result_set[r0] = Some(0); // distance 0 from `r0` + + while changed { + changed = false; + for constraint in &*self.constraints { + if let Some(n) = result_set[constraint.sup] { + let m = n + 1; + if result_set[constraint.sub] + .map(|distance| m < distance) + .unwrap_or(true) + { + result_set[constraint.sub] = Some(m); + changed = true; + } + } + } + } + + result_set + } +} 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 d7e818c50437d..09e425ff55508 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -9,32 +9,28 @@ // except according to those terms. use super::universal_regions::UniversalRegions; -use borrow_check::nll::region_infer::values::ToElementIndex; -use borrow_check::nll::constraint_set::{ConstraintIndex, ConstraintCategory, ConstraintSet}; -use borrow_check::nll::constraint_set::{OutlivesConstraint}; +use borrow_check::nll::constraint_set::{ConstraintIndex, ConstraintSet, OutlivesConstraint}; use borrow_check::nll::type_check::Locations; use rustc::hir::def_id::DefId; use rustc::infer::canonical::QueryRegionConstraint; -use rustc::infer::error_reporting::nice_region_error::NiceRegionError; use rustc::infer::region_constraints::{GenericKind, VarInfos}; use rustc::infer::InferCtxt; use rustc::infer::NLLRegionVariableOrigin; use rustc::infer::RegionVariableOrigin; use rustc::mir::{ ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location, - Mir, StatementKind, TerminatorKind, Rvalue + Mir }; use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable}; -use rustc::util::common::{self, ErrorReported}; +use rustc::util::common; use rustc_data_structures::bitvec::BitVector; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use std::rc::Rc; -use syntax_pos::Span; mod annotation; mod dump_mir; +mod error_reporting; mod graphviz; mod values; use self::values::{RegionValueElements, RegionValues}; @@ -966,296 +962,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, blame_span); } } - - /// When reporting an error, it is useful to be able to determine which constraints influenced - /// the region being reported as an error. This function finds all of the paths from the - /// constraint. - fn find_constraint_paths_from_region( - &self, - r0: RegionVid - ) -> Vec<Vec<ConstraintIndex>> { - let constraints = self.constraints.clone(); - - // Mapping of regions to the previous region and constraint index that led to it. - let mut previous = FxHashMap(); - // Regions yet to be visited. - let mut next = vec! [ r0 ]; - // Regions that have been visited. - let mut visited = FxHashSet(); - // Ends of paths. - let mut end_regions: Vec<RegionVid> = Vec::new(); - - // When we've still got points to visit... - while let Some(current) = next.pop() { - // ...take the next point... - debug!("find_constraint_paths_from_region: current={:?} next={:?}", current, next); - - // ...find the edges containing it... - let mut upcoming = Vec::new(); - for (index, constraint) in constraints.iter_enumerated() { - if constraint.sub == current { - // ...add the regions that join us with to the path we've taken... - debug!("find_constraint_paths_from_region: index={:?} constraint={:?}", - index, constraint); - let next_region = constraint.sup.clone(); - - // ...unless we've visited it since this was added... - if visited.contains(&next_region) { - debug!("find_constraint_paths_from_region: skipping as visited"); - continue; - } - - previous.insert(next_region, (index, Some(current))); - upcoming.push(next_region); - } - } - - if upcoming.is_empty() { - // If we didn't find any edges then this is the end of a path... - debug!("find_constraint_paths_from_region: new end region current={:?}", current); - end_regions.push(current); - } else { - // ...but, if we did find edges, then add these to the regions yet to visit... - debug!("find_constraint_paths_from_region: extend next upcoming={:?}", upcoming); - next.extend(upcoming); - } - - // ...and don't visit it again. - visited.insert(current.clone()); - debug!("find_constraint_paths_from_region: next={:?} visited={:?}", next, visited); - } - - // Now we've visited each point, compute the final paths. - let mut paths: Vec<Vec<ConstraintIndex>> = Vec::new(); - debug!("find_constraint_paths_from_region: end_regions={:?}", end_regions); - for end_region in end_regions { - debug!("find_constraint_paths_from_region: end_region={:?}", end_region); - - // Get the constraint and region that led to this end point. - // We can unwrap as we know if end_point was in the vector that it - // must also be in our previous map. - let (mut index, mut region) = previous.get(&end_region).unwrap(); - debug!("find_constraint_paths_from_region: index={:?} region={:?}", index, region); - - // Keep track of the indices. - let mut path: Vec<ConstraintIndex> = vec![index]; - - while region.is_some() && region != Some(r0) { - let p = previous.get(®ion.unwrap()).unwrap(); - index = p.0; - region = p.1; - - debug!("find_constraint_paths_from_region: index={:?} region={:?}", index, region); - path.push(index); - } - - // Add to our paths. - paths.push(path); - } - - debug!("find_constraint_paths_from_region: paths={:?}", paths); - paths - } - - /// This function will return true if a constraint is interesting and false if a constraint - /// is not. It is useful in filtering constraint paths to only interesting points. - fn constraint_is_interesting(&self, index: &ConstraintIndex) -> bool { - self.constraints.get(*index).filter(|constraint| { - debug!("constraint_is_interesting: locations={:?} constraint={:?}", - constraint.locations, constraint); - if let Locations::Interesting(_) = constraint.locations { true } else { false } - }).is_some() - } - - /// This function classifies a constraint from a location. - fn classify_constraint(&self, location: Location, mir: &Mir<'tcx>) -> ConstraintCategory { - let data = &mir[location.block]; - if location.statement_index == data.statements.len() { - if let Some(ref terminator) = data.terminator { - match terminator.kind { - TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment, - TerminatorKind::Call { .. } => ConstraintCategory::CallArgument, - _ => ConstraintCategory::Other, - } - } else { - ConstraintCategory::Other - } - } else { - let statement = &data.statements[location.statement_index]; - match statement.kind { - StatementKind::Assign(_, ref rvalue) => match rvalue { - Rvalue::Cast(..) => ConstraintCategory::Cast, - Rvalue::Use(..) => ConstraintCategory::Assignment, - _ => ConstraintCategory::Other, - }, - _ => ConstraintCategory::Other, - } - } - } - - /// Report an error because the universal region `fr` was required to outlive - /// `outlived_fr` but it is not known to do so. For example: - /// - /// ``` - /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } - /// ``` - /// - /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`. - fn report_error( - &self, - mir: &Mir<'tcx>, - infcx: &InferCtxt<'_, '_, 'tcx>, - mir_def_id: DefId, - fr: RegionVid, - outlived_fr: RegionVid, - blame_span: Span, - ) { - // Obviously uncool error reporting. - - let fr_name = self.to_error_region(fr); - let outlived_fr_name = self.to_error_region(outlived_fr); - - if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) { - let tables = infcx.tcx.typeck_tables_of(mir_def_id); - let nice = NiceRegionError::new_from_span(infcx.tcx, blame_span, o, f, Some(tables)); - if let Some(ErrorReported) = nice.try_report() { - return; - } - } - - let constraints = self.find_constraint_paths_from_region(fr.clone()); - let path = constraints.iter().min_by_key(|p| p.len()).unwrap(); - debug!("report_error: path={:?}", path); - - let path = path.iter() - .filter(|index| self.constraint_is_interesting(index)) - .collect::<Vec<&ConstraintIndex>>(); - debug!("report_error: path={:?}", path); - - let mut categorized_path = path.iter().filter_map(|index| { - self.constraints.get(**index).iter().filter_map(|constraint| { - let span = constraint.locations.span(mir); - constraint.locations.from_location().iter().filter_map(|location| { - let classification = self.classify_constraint(*location, mir); - Some((classification, span)) - }).next() - }).next() - }).collect::<Vec<(ConstraintCategory, Span)>>(); - debug!("report_error: categorized_path={:?}", categorized_path); - - categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0)); - debug!("report_error: sorted_path={:?}", categorized_path); - - if categorized_path.len() > 0 { - let blame_constraint = &categorized_path[0]; - - let mut diag = infcx.tcx.sess.struct_span_err( - blame_constraint.1, - &format!("{:?}", blame_constraint.0), - ); - - for secondary in categorized_path.iter().skip(1) { - diag.span_label(secondary.1, format!("{:?}", secondary.0)); - } - - diag.emit(); - } else { - let fr_string = match fr_name { - Some(r) => format!("free region `{}`", r), - None => format!("free region `{:?}`", fr), - }; - - let outlived_fr_string = match outlived_fr_name { - Some(r) => format!("free region `{}`", r), - None => format!("free region `{:?}`", outlived_fr), - }; - - let mut diag = infcx.tcx.sess.struct_span_err( - blame_span, - &format!("{} does not outlive {}", fr_string, outlived_fr_string,), - ); - - diag.emit(); - } - } - - crate fn why_region_contains_point(&self, fr1: RegionVid, elem: Location) -> Option<Cause> { - // Find some constraint `X: Y` where: - // - `fr1: X` transitively - // - and `Y` is live at `elem` - let index = self.blame_constraint(fr1, elem); - let region_sub = self.constraints[index].sub; - - // then return why `Y` was live at `elem` - self.liveness_constraints.cause(region_sub, elem) - } - - /// Tries to finds a good span to blame for the fact that `fr1` - /// contains `fr2`. - fn blame_constraint(&self, fr1: RegionVid, elem: impl ToElementIndex) -> ConstraintIndex { - // Find everything that influenced final value of `fr`. - let influenced_fr1 = self.dependencies(fr1); - - // Try to find some outlives constraint `'X: fr2` where `'X` - // influenced `fr1`. Blame that. - // - // NB, this is a pretty bad choice most of the time. In - // particular, the connection between `'X` and `fr1` may not - // be obvious to the user -- not to mention the naive notion - // of dependencies, which doesn't account for the locations of - // contraints at all. But it will do for now. - let relevant_constraint = self.constraints - .iter_enumerated() - .filter_map(|(i, constraint)| { - if !self.liveness_constraints.contains(constraint.sub, elem) { - None - } else { - influenced_fr1[constraint.sup] - .map(|distance| (distance, i)) - } - }) - .min() // constraining fr1 with fewer hops *ought* to be more obvious - .map(|(_dist, i)| i); - - relevant_constraint.unwrap_or_else(|| { - bug!( - "could not find any constraint to blame for {:?}: {:?}", - fr1, - elem, - ); - }) - } - - /// Finds all regions whose values `'a` may depend on in some way. - /// For each region, returns either `None` (does not influence - /// `'a`) or `Some(d)` which indicates that it influences `'a` - /// with distinct `d` (minimum number of edges that must be - /// traversed). - /// - /// Used during error reporting, extremely naive and inefficient. - fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> { - let mut result_set = IndexVec::from_elem(None, &self.definitions); - let mut changed = true; - result_set[r0] = Some(0); // distance 0 from `r0` - - while changed { - changed = false; - for constraint in self.constraints.iter() { - if let Some(n) = result_set[constraint.sup] { - let m = n + 1; - if result_set[constraint.sub] - .map(|distance| m < distance) - .unwrap_or(true) - { - result_set[constraint.sub] = Some(m); - changed = true; - } - } - } - } - - result_set - } } impl<'tcx> RegionDefinition<'tcx> { From e01e883e4f2e86961f02ce3041e4773a04286cfb Mon Sep 17 00:00:00 2001 From: David Wood <david@davidtw.co> Date: Tue, 26 Jun 2018 23:00:24 +0100 Subject: [PATCH 10/15] Introduce new categories and show a reasonable error message. --- .../nll/region_infer/error_reporting.rs | 100 ++++++++++-------- 1 file changed, 58 insertions(+), 42 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs index 261bc31b6f606..cc78043b83cce 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs @@ -8,26 +8,42 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::fmt; use borrow_check::nll::region_infer::{Cause, ConstraintIndex, RegionInferenceContext}; use borrow_check::nll::region_infer::values::ToElementIndex; use borrow_check::nll::type_check::Locations; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; use rustc::infer::error_reporting::nice_region_error::NiceRegionError; -use rustc::mir::{Location, Mir, StatementKind, TerminatorKind, Rvalue}; +use rustc::mir::{self, Location, Mir, Place, StatementKind, TerminatorKind, Rvalue}; use rustc::ty::RegionVid; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::IndexVec; use syntax_pos::Span; /// Constraints that are considered interesting can be categorized to -/// determine why they are interesting. +/// determine why they are interesting. Order of variants indicates +/// sort order of the category, thereby influencing diagnostic output. #[derive(Debug, Eq, PartialEq, PartialOrd, Ord)] enum ConstraintCategory { - Assignment, Cast, + Assignment, + Return, CallArgument, Other, + Boring, +} + +impl fmt::Display for ConstraintCategory { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ConstraintCategory::Assignment => write!(f, "Assignment"), + ConstraintCategory::Return => write!(f, "Return"), + ConstraintCategory::Cast => write!(f, "Cast"), + ConstraintCategory::CallArgument => write!(f, "Argument"), + _ => write!(f, "Free region"), + } + } } impl<'tcx> RegionInferenceContext<'tcx> { @@ -132,9 +148,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// This function classifies a constraint from a location. - fn classify_constraint(&self, location: Location, mir: &Mir<'tcx>) -> ConstraintCategory { + fn classify_constraint(&self, index: &ConstraintIndex, + mir: &Mir<'tcx>) -> Option<(ConstraintCategory, Span)> { + let constraint = self.constraints.get(*index)?; + let span = constraint.locations.span(mir); + let location = constraint.locations.from_location()?; + + if !self.constraint_is_interesting(index) { + return Some((ConstraintCategory::Boring, span)); + } + let data = &mir[location.block]; - if location.statement_index == data.statements.len() { + let category = if location.statement_index == data.statements.len() { if let Some(ref terminator) = data.terminator { match terminator.kind { TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment, @@ -147,14 +172,22 @@ impl<'tcx> RegionInferenceContext<'tcx> { } else { let statement = &data.statements[location.statement_index]; match statement.kind { - StatementKind::Assign(_, ref rvalue) => match rvalue { - Rvalue::Cast(..) => ConstraintCategory::Cast, - Rvalue::Use(..) => ConstraintCategory::Assignment, - _ => ConstraintCategory::Other, + StatementKind::Assign(ref place, ref rvalue) => { + if *place == Place::Local(mir::RETURN_PLACE) { + ConstraintCategory::Return + } else { + match rvalue { + Rvalue::Cast(..) => ConstraintCategory::Cast, + Rvalue::Use(..) => ConstraintCategory::Assignment, + _ => ConstraintCategory::Other, + } + } }, _ => ConstraintCategory::Other, } - } + }; + + Some((category, span)) } /// Report an error because the universal region `fr` was required to outlive @@ -187,53 +220,36 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } + let fr_string = match fr_name { + Some(r) => format!("free region `{}`", r), + None => format!("free region `{:?}`", fr), + }; + + let outlived_fr_string = match outlived_fr_name { + Some(r) => format!("free region `{}`", r), + None => format!("free region `{:?}`", outlived_fr), + }; + let constraints = self.find_constraint_paths_from_region(fr.clone()); let path = constraints.iter().min_by_key(|p| p.len()).unwrap(); - debug!("report_error: path={:?}", path); - - let path = path.iter() - .filter(|index| self.constraint_is_interesting(index)) - .collect::<Vec<&ConstraintIndex>>(); - debug!("report_error: path={:?}", path); + debug!("report_error: shortest_path={:?}", path); let mut categorized_path = path.iter().filter_map(|index| { - self.constraints.get(**index).iter().filter_map(|constraint| { - let span = constraint.locations.span(mir); - constraint.locations.from_location().iter().filter_map(|location| { - let classification = self.classify_constraint(*location, mir); - Some((classification, span)) - }).next() - }).next() + self.classify_constraint(index, mir) }).collect::<Vec<(ConstraintCategory, Span)>>(); debug!("report_error: categorized_path={:?}", categorized_path); categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0)); debug!("report_error: sorted_path={:?}", categorized_path); - if categorized_path.len() > 0 { - let blame_constraint = &categorized_path[0]; - + if let Some((category, span)) = &categorized_path.first() { let mut diag = infcx.tcx.sess.struct_span_err( - blame_constraint.1, - &format!("{:?}", blame_constraint.0), + *span, &format!("{} requires that data must outlive {}", + category, outlived_fr_string), ); - for secondary in categorized_path.iter().skip(1) { - diag.span_label(secondary.1, format!("{:?}", secondary.0)); - } - diag.emit(); } else { - let fr_string = match fr_name { - Some(r) => format!("free region `{}`", r), - None => format!("free region `{:?}`", fr), - }; - - let outlived_fr_string = match outlived_fr_name { - Some(r) => format!("free region `{}`", r), - None => format!("free region `{:?}`", outlived_fr), - }; - let mut diag = infcx.tcx.sess.struct_span_err( blame_span, &format!("{} does not outlive {}", fr_string, outlived_fr_string,), From 59e64e908504a6ce6cd549acd735e38871f88368 Mon Sep 17 00:00:00 2001 From: David Wood <david@davidtw.co> Date: Tue, 26 Jun 2018 23:30:52 +0100 Subject: [PATCH 11/15] Updated affected tests. --- src/test/ui/borrowck/issue-45983.nll.stderr | 2 +- .../regions-escape-bound-fn-2.nll.stderr | 2 +- ...horter-to-static-comparing-against-free.rs | 2 +- ...er-to-static-comparing-against-free.stderr | 8 +++---- ...approximated-shorter-to-static-no-bound.rs | 2 +- ...oximated-shorter-to-static-no-bound.stderr | 13 +++++----- ...roximated-shorter-to-static-wrong-bound.rs | 2 +- ...mated-shorter-to-static-wrong-bound.stderr | 13 +++++----- ...te-fail-to-approximate-longer-no-bounds.rs | 2 +- ...ail-to-approximate-longer-no-bounds.stderr | 8 +++---- .../projection-one-region-closure.rs | 6 ++--- .../projection-one-region-closure.stderr | 24 +++++++++---------- ...ojection-one-region-trait-bound-closure.rs | 6 ++--- ...tion-one-region-trait-bound-closure.stderr | 24 +++++++++---------- ...ojection-two-region-trait-bound-closure.rs | 2 +- ...tion-two-region-trait-bound-closure.stderr | 8 +++---- .../dyn-trait-underscore.nll.stderr | 12 ++++------ 17 files changed, 65 insertions(+), 71 deletions(-) diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr index a008a408d9711..9b5fcbc56d5cd 100644 --- a/src/test/ui/borrowck/issue-45983.nll.stderr +++ b/src/test/ui/borrowck/issue-45983.nll.stderr @@ -4,7 +4,7 @@ warning: not reporting region error due to nll LL | give_any(|y| x = Some(y)); | ^ -error: free region `` does not outlive free region `'_#2r` +error: Assignment requires that data must outlive free region `'_#2r` --> $DIR/issue-45983.rs:17:27 | LL | give_any(|y| x = Some(y)); diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr index ee3970aa8fd8f..91161d6820c34 100644 --- a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr +++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr @@ -4,7 +4,7 @@ warning: not reporting region error due to nll LL | with_int(|y| x = Some(y)); | ^ -error: free region `` does not outlive free region `'_#2r` +error: Assignment requires that data must outlive free region `'_#2r` --> $DIR/regions-escape-bound-fn-2.rs:18:27 | LL | with_int(|y| x = Some(y)); diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs index 84bfd6ea4f253..248933fc39e14 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs @@ -31,7 +31,7 @@ fn case1() { foo(cell, |cell_a, cell_x| { //~^ WARNING not reporting region error due to nll cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure - //~^ ERROR does not outlive free region + //~^ ERROR Argument requires that data must outlive free region }) } diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index ac4efecc8ac07..7b1cba1d937f6 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -4,11 +4,11 @@ warning: not reporting region error due to nll LL | foo(cell, |cell_a, cell_x| { | ^^^ -error: free region `ReFree(DefId(0/1:12 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]::{{closure}}[0]), BrAnon(1))` does not outlive free region `'_#1r` - --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:9 +error: Argument requires that data must outlive free region `'_#1r` + --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:20 | LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure - | ^^^^^^ + | ^^^^^^^^^^^^ note: No external requirements --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:31:15 @@ -17,7 +17,7 @@ LL | foo(cell, |cell_a, cell_x| { | _______________^ LL | | //~^ WARNING not reporting region error due to nll LL | | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure -LL | | //~^ ERROR does not outlive free region +LL | | //~^ ERROR Argument requires that data must outlive free region LL | | }) | |_____^ | diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs index df715c52921a0..4c8c2b1b95bb0 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs @@ -43,7 +43,7 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3 #[rustc_regions] fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { - //~^ ERROR does not outlive free region + //~^ ERROR Argument requires that data must outlive free region // Only works if 'x: 'y: demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index 122e393f97a53..8a18af90e195c 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -9,7 +9,7 @@ note: External requirements | LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { | _______________________________________________^ -LL | | //~^ ERROR does not outlive free region +LL | | //~^ ERROR Argument requires that data must outlive free region LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll @@ -23,12 +23,11 @@ LL | | }); = note: number of external vids: 2 = note: where '_#1r: '_#0r -error: free region `ReFree(DefId(0/0:6 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]), BrNamed(crate0:DefIndex(1:16), 'a))` does not outlive free region `ReStatic` - --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:47 +error: Argument requires that data must outlive free region `ReStatic` + --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:5 | -LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { - | _______________________________________________^ -LL | | //~^ ERROR does not outlive free region +LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { +LL | | //~^ ERROR Argument requires that data must outlive free region LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll @@ -40,7 +39,7 @@ note: No external requirements | LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { LL | | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { -LL | | //~^ ERROR does not outlive free region +LL | | //~^ ERROR Argument requires that data must outlive free region LL | | ... | LL | | }); diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs index fdbb312572f89..d9cfea4c891c4 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs @@ -46,7 +46,7 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3 #[rustc_regions] fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - //~^ ERROR does not outlive free region + //~^ ERROR Argument requires that data must outlive free region // Only works if 'x: 'y: demand_y(x, y, x.get()) //~^ WARNING not reporting region error due to nll diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index 8cdbc26458150..dda1c44b4d8b4 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -9,7 +9,7 @@ note: External requirements | LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { | _______________________________________________^ -LL | | //~^ ERROR does not outlive free region +LL | | //~^ ERROR Argument requires that data must outlive free region LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | //~^ WARNING not reporting region error due to nll @@ -23,12 +23,11 @@ LL | | }); = note: number of external vids: 3 = note: where '_#1r: '_#0r -error: free region `ReFree(DefId(0/0:6 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]), BrNamed(crate0:DefIndex(1:16), 'a))` does not outlive free region `ReStatic` - --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:47 +error: Argument requires that data must outlive free region `ReStatic` + --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:5 | -LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - | _______________________________________________^ -LL | | //~^ ERROR does not outlive free region +LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { +LL | | //~^ ERROR Argument requires that data must outlive free region LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | //~^ WARNING not reporting region error due to nll @@ -40,7 +39,7 @@ note: No external requirements | LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { LL | | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { -LL | | //~^ ERROR does not outlive free region +LL | | //~^ ERROR Argument requires that data must outlive free region LL | | // Only works if 'x: 'y: ... | LL | | }); diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs index 7699d10173495..480461b6b639c 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs @@ -46,7 +46,7 @@ fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { // Only works if 'x: 'y: demand_y(x, y, x.get()) //~^ WARN not reporting region error due to nll - //~| ERROR does not outlive free region + //~| ERROR Argument requires that data must outlive free region }); } diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 8b6cd2ea432db..00e4c289e7eb5 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -4,11 +4,11 @@ warning: not reporting region error due to nll LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ -error: free region `ReFree(DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]), BrAnon(4))` does not outlive free region `ReFree(DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]), BrAnon(2))` - --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:18 +error: Argument requires that data must outlive free region `ReFree(DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]), BrAnon(2))` + --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:9 | LL | demand_y(x, y, x.get()) - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^ note: No external requirements --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:45:47 @@ -18,7 +18,7 @@ LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | //~^ WARN not reporting region error due to nll -LL | | //~| ERROR does not outlive free region +LL | | //~| ERROR Argument requires that data must outlive free region LL | | }); | |_____^ | diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs index 77024c4119ff9..5e695f3f7c7d7 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs @@ -55,7 +55,7 @@ where with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to nll //~| ERROR the parameter type `T` may not live long enough - //~| ERROR does not outlive free region + //~| ERROR Argument requires that data must outlive free region } #[rustc_regions] @@ -67,7 +67,7 @@ where with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to nll //~| ERROR the parameter type `T` may not live long enough - //~| ERROR does not outlive free region + //~| ERROR Argument requires that data must outlive free region } #[rustc_regions] @@ -89,7 +89,7 @@ where with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to nll //~| ERROR the parameter type `T` may not live long enough - //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` + //~| ERROR Argument requires that data must outlive free region } #[rustc_regions] diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index e1218830dbb64..fac0a0b0064c0 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -40,11 +40,11 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); | = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`... -error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))` - --> $DIR/projection-one-region-closure.rs:55:20 +error: Argument requires that data must outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))` + --> $DIR/projection-one-region-closure.rs:55:5 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: No external requirements --> $DIR/projection-one-region-closure.rs:51:1 @@ -54,7 +54,7 @@ LL | | where LL | | T: Anything<'b>, LL | | { ... | -LL | | //~| ERROR does not outlive free region +LL | | //~| ERROR Argument requires that data must outlive free region LL | | } | |_^ | @@ -88,11 +88,11 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); | = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`... -error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` - --> $DIR/projection-one-region-closure.rs:67:20 +error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)` + --> $DIR/projection-one-region-closure.rs:67:5 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: No external requirements --> $DIR/projection-one-region-closure.rs:62:1 @@ -102,7 +102,7 @@ LL | | where LL | | T: Anything<'b>, LL | | 'a: 'a, ... | -LL | | //~| ERROR does not outlive free region +LL | | //~| ERROR Argument requires that data must outlive free region LL | | } | |_^ | @@ -137,11 +137,11 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); | = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`... -error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` - --> $DIR/projection-one-region-closure.rs:89:20 +error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)` + --> $DIR/projection-one-region-closure.rs:89:5 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: No external requirements --> $DIR/projection-one-region-closure.rs:74:1 @@ -151,7 +151,7 @@ LL | | where LL | | T: Anything<'b>, LL | | T::AssocType: 'a, ... | -LL | | //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` +LL | | //~| ERROR Argument requires that data must outlive free region LL | | } | |_^ | diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs index fb1009c9cc8e8..24d1753eea826 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs @@ -46,7 +46,7 @@ where { with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to nll - //~| ERROR does not outlive free region + //~| ERROR Argument requires that data must outlive free region } #[rustc_regions] @@ -57,7 +57,7 @@ where { with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to nll - //~| ERROR does not outlive free region + //~| ERROR Argument requires that data must outlive free region } #[rustc_regions] @@ -78,7 +78,7 @@ where with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to nll - //~| ERROR does not outlive free region + //~| ERROR Argument requires that data must outlive free region } #[rustc_regions] diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 76554e29f62ea..07e65fb405158 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -31,11 +31,11 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: number of external vids: 3 = note: where '_#1r: '_#2r -error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))` - --> $DIR/projection-one-region-trait-bound-closure.rs:47:20 +error: Argument requires that data must outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))` + --> $DIR/projection-one-region-trait-bound-closure.rs:47:5 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: No external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:43:1 @@ -45,7 +45,7 @@ LL | | where LL | | T: Anything<'b>, LL | | { ... | -LL | | //~| ERROR does not outlive free region +LL | | //~| ERROR Argument requires that data must outlive free region LL | | } | |_^ | @@ -70,11 +70,11 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: number of external vids: 4 = note: where '_#2r: '_#3r -error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` - --> $DIR/projection-one-region-trait-bound-closure.rs:58:20 +error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)` + --> $DIR/projection-one-region-trait-bound-closure.rs:58:5 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: No external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:53:1 @@ -84,7 +84,7 @@ LL | | where LL | | T: Anything<'b>, LL | | 'a: 'a, ... | -LL | | //~| ERROR does not outlive free region +LL | | //~| ERROR Argument requires that data must outlive free region LL | | } | |_^ | @@ -110,11 +110,11 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: number of external vids: 4 = note: where '_#2r: '_#3r -error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` - --> $DIR/projection-one-region-trait-bound-closure.rs:79:20 +error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)` + --> $DIR/projection-one-region-trait-bound-closure.rs:79:5 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: No external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:64:1 @@ -124,7 +124,7 @@ LL | | where LL | | T: Anything<'b>, LL | | T::AssocType: 'a, ... | -LL | | //~| ERROR does not outlive free region +LL | | //~| ERROR Argument requires that data must outlive free region LL | | } | |_^ | diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs index 5307d0880d4da..8129f93736b64 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs @@ -107,7 +107,7 @@ where { with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to nll - //~| ERROR does not outlive free region + //~| ERROR Argument requires that data must outlive free region } #[rustc_regions] diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index c7f456929609e..c778f23a2c450 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -239,11 +239,11 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: number of external vids: 3 = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r -error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))` - --> $DIR/projection-two-region-trait-bound-closure.rs:108:20 +error: Argument requires that data must outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))` + --> $DIR/projection-two-region-trait-bound-closure.rs:108:5 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: No external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:104:1 @@ -253,7 +253,7 @@ LL | | where LL | | T: Anything<'b, 'b>, LL | | { ... | -LL | | //~| ERROR does not outlive free region +LL | | //~| ERROR Argument requires that data must outlive free region LL | | } | |_^ | diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr index cdc0c78e69414..681c0dce7d172 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr @@ -22,15 +22,11 @@ warning: not reporting region error due to nll LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^^^^^^^^^^^^^^^^^^^ -error: free region `` does not outlive free region `'static` - --> $DIR/dyn-trait-underscore.rs:16:52 +error: Cast requires that data must outlive free region `'static` + --> $DIR/dyn-trait-underscore.rs:18:5 | -LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> { - | ____________________________________________________^ -LL | | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` -LL | | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime -LL | | } - | |_^ +LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error From a11245f80e56e8281f7bbc237140926fe428d8bc Mon Sep 17 00:00:00 2001 From: David Wood <david@davidtw.co> Date: Wed, 27 Jun 2018 21:18:07 +0100 Subject: [PATCH 12/15] Ensure that changed errors are lower case. --- .../borrow_check/nll/region_infer/error_reporting.rs | 10 +++++----- src/test/ui/borrowck/issue-45983.nll.stderr | 2 +- .../ui/borrowck/regions-escape-bound-fn-2.nll.stderr | 2 +- ...mated-shorter-to-static-comparing-against-free.rs | 2 +- ...d-shorter-to-static-comparing-against-free.stderr | 4 ++-- ...pagate-approximated-shorter-to-static-no-bound.rs | 2 +- ...te-approximated-shorter-to-static-no-bound.stderr | 8 ++++---- ...ate-approximated-shorter-to-static-wrong-bound.rs | 2 +- ...approximated-shorter-to-static-wrong-bound.stderr | 8 ++++---- ...propagate-fail-to-approximate-longer-no-bounds.rs | 2 +- ...agate-fail-to-approximate-longer-no-bounds.stderr | 4 ++-- .../nll/ty-outlives/projection-one-region-closure.rs | 6 +++--- .../ty-outlives/projection-one-region-closure.stderr | 12 ++++++------ .../projection-one-region-trait-bound-closure.rs | 6 +++--- .../projection-one-region-trait-bound-closure.stderr | 12 ++++++------ .../projection-two-region-trait-bound-closure.rs | 2 +- .../projection-two-region-trait-bound-closure.stderr | 4 ++-- .../dyn-trait-underscore.nll.stderr | 2 +- 18 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs index cc78043b83cce..f3372f6be703b 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs @@ -37,11 +37,11 @@ enum ConstraintCategory { impl fmt::Display for ConstraintCategory { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - ConstraintCategory::Assignment => write!(f, "Assignment"), - ConstraintCategory::Return => write!(f, "Return"), - ConstraintCategory::Cast => write!(f, "Cast"), - ConstraintCategory::CallArgument => write!(f, "Argument"), - _ => write!(f, "Free region"), + ConstraintCategory::Assignment => write!(f, "assignment"), + ConstraintCategory::Return => write!(f, "return"), + ConstraintCategory::Cast => write!(f, "cast"), + ConstraintCategory::CallArgument => write!(f, "argument"), + _ => write!(f, "free region"), } } } diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr index 9b5fcbc56d5cd..a62d81c033333 100644 --- a/src/test/ui/borrowck/issue-45983.nll.stderr +++ b/src/test/ui/borrowck/issue-45983.nll.stderr @@ -4,7 +4,7 @@ warning: not reporting region error due to nll LL | give_any(|y| x = Some(y)); | ^ -error: Assignment requires that data must outlive free region `'_#2r` +error: assignment requires that data must outlive free region `'_#2r` --> $DIR/issue-45983.rs:17:27 | LL | give_any(|y| x = Some(y)); diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr index 91161d6820c34..7a4db0802a846 100644 --- a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr +++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr @@ -4,7 +4,7 @@ warning: not reporting region error due to nll LL | with_int(|y| x = Some(y)); | ^ -error: Assignment requires that data must outlive free region `'_#2r` +error: assignment requires that data must outlive free region `'_#2r` --> $DIR/regions-escape-bound-fn-2.rs:18:27 | LL | with_int(|y| x = Some(y)); diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs index 248933fc39e14..5a71e75d4b2cd 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs @@ -31,7 +31,7 @@ fn case1() { foo(cell, |cell_a, cell_x| { //~^ WARNING not reporting region error due to nll cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure - //~^ ERROR Argument requires that data must outlive free region + //~^ ERROR argument requires that data must outlive free region }) } diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 7b1cba1d937f6..656c1b46a3ce5 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -4,7 +4,7 @@ warning: not reporting region error due to nll LL | foo(cell, |cell_a, cell_x| { | ^^^ -error: Argument requires that data must outlive free region `'_#1r` +error: argument requires that data must outlive free region `'_#1r` --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:20 | LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure @@ -17,7 +17,7 @@ LL | foo(cell, |cell_a, cell_x| { | _______________^ LL | | //~^ WARNING not reporting region error due to nll LL | | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure -LL | | //~^ ERROR Argument requires that data must outlive free region +LL | | //~^ ERROR argument requires that data must outlive free region LL | | }) | |_____^ | diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs index 4c8c2b1b95bb0..b25b0e25df211 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs @@ -43,7 +43,7 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3 #[rustc_regions] fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { - //~^ ERROR Argument requires that data must outlive free region + //~^ ERROR argument requires that data must outlive free region // Only works if 'x: 'y: demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index 8a18af90e195c..582417b0da934 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -9,7 +9,7 @@ note: External requirements | LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { | _______________________________________________^ -LL | | //~^ ERROR Argument requires that data must outlive free region +LL | | //~^ ERROR argument requires that data must outlive free region LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll @@ -23,11 +23,11 @@ LL | | }); = note: number of external vids: 2 = note: where '_#1r: '_#0r -error: Argument requires that data must outlive free region `ReStatic` +error: argument requires that data must outlive free region `ReStatic` --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:5 | LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { -LL | | //~^ ERROR Argument requires that data must outlive free region +LL | | //~^ ERROR argument requires that data must outlive free region LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll @@ -39,7 +39,7 @@ note: No external requirements | LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { LL | | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { -LL | | //~^ ERROR Argument requires that data must outlive free region +LL | | //~^ ERROR argument requires that data must outlive free region LL | | ... | LL | | }); diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs index d9cfea4c891c4..db9951bcc0f21 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs @@ -46,7 +46,7 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3 #[rustc_regions] fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - //~^ ERROR Argument requires that data must outlive free region + //~^ ERROR argument requires that data must outlive free region // Only works if 'x: 'y: demand_y(x, y, x.get()) //~^ WARNING not reporting region error due to nll diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index dda1c44b4d8b4..481ba512972fa 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -9,7 +9,7 @@ note: External requirements | LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { | _______________________________________________^ -LL | | //~^ ERROR Argument requires that data must outlive free region +LL | | //~^ ERROR argument requires that data must outlive free region LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | //~^ WARNING not reporting region error due to nll @@ -23,11 +23,11 @@ LL | | }); = note: number of external vids: 3 = note: where '_#1r: '_#0r -error: Argument requires that data must outlive free region `ReStatic` +error: argument requires that data must outlive free region `ReStatic` --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:5 | LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { -LL | | //~^ ERROR Argument requires that data must outlive free region +LL | | //~^ ERROR argument requires that data must outlive free region LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | //~^ WARNING not reporting region error due to nll @@ -39,7 +39,7 @@ note: No external requirements | LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { LL | | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { -LL | | //~^ ERROR Argument requires that data must outlive free region +LL | | //~^ ERROR argument requires that data must outlive free region LL | | // Only works if 'x: 'y: ... | LL | | }); diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs index 480461b6b639c..316268e7e726d 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs @@ -46,7 +46,7 @@ fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { // Only works if 'x: 'y: demand_y(x, y, x.get()) //~^ WARN not reporting region error due to nll - //~| ERROR Argument requires that data must outlive free region + //~| ERROR argument requires that data must outlive free region }); } diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 00e4c289e7eb5..74c0576e03b62 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -4,7 +4,7 @@ warning: not reporting region error due to nll LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ -error: Argument requires that data must outlive free region `ReFree(DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]), BrAnon(2))` +error: argument requires that data must outlive free region `ReFree(DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]), BrAnon(2))` --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:9 | LL | demand_y(x, y, x.get()) @@ -18,7 +18,7 @@ LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | //~^ WARN not reporting region error due to nll -LL | | //~| ERROR Argument requires that data must outlive free region +LL | | //~| ERROR argument requires that data must outlive free region LL | | }); | |_____^ | diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs index 5e695f3f7c7d7..3832be6288aef 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs @@ -55,7 +55,7 @@ where with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to nll //~| ERROR the parameter type `T` may not live long enough - //~| ERROR Argument requires that data must outlive free region + //~| ERROR argument requires that data must outlive free region } #[rustc_regions] @@ -67,7 +67,7 @@ where with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to nll //~| ERROR the parameter type `T` may not live long enough - //~| ERROR Argument requires that data must outlive free region + //~| ERROR argument requires that data must outlive free region } #[rustc_regions] @@ -89,7 +89,7 @@ where with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to nll //~| ERROR the parameter type `T` may not live long enough - //~| ERROR Argument requires that data must outlive free region + //~| ERROR argument requires that data must outlive free region } #[rustc_regions] diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index fac0a0b0064c0..898c995e09b9d 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -40,7 +40,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); | = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`... -error: Argument requires that data must outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))` +error: argument requires that data must outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))` --> $DIR/projection-one-region-closure.rs:55:5 | LL | with_signature(cell, t, |cell, t| require(cell, t)); @@ -54,7 +54,7 @@ LL | | where LL | | T: Anything<'b>, LL | | { ... | -LL | | //~| ERROR Argument requires that data must outlive free region +LL | | //~| ERROR argument requires that data must outlive free region LL | | } | |_^ | @@ -88,7 +88,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); | = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`... -error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)` +error: argument requires that data must outlive free region `ReEarlyBound(0, 'a)` --> $DIR/projection-one-region-closure.rs:67:5 | LL | with_signature(cell, t, |cell, t| require(cell, t)); @@ -102,7 +102,7 @@ LL | | where LL | | T: Anything<'b>, LL | | 'a: 'a, ... | -LL | | //~| ERROR Argument requires that data must outlive free region +LL | | //~| ERROR argument requires that data must outlive free region LL | | } | |_^ | @@ -137,7 +137,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); | = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`... -error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)` +error: argument requires that data must outlive free region `ReEarlyBound(0, 'a)` --> $DIR/projection-one-region-closure.rs:89:5 | LL | with_signature(cell, t, |cell, t| require(cell, t)); @@ -151,7 +151,7 @@ LL | | where LL | | T: Anything<'b>, LL | | T::AssocType: 'a, ... | -LL | | //~| ERROR Argument requires that data must outlive free region +LL | | //~| ERROR argument requires that data must outlive free region LL | | } | |_^ | diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs index 24d1753eea826..da76193459b30 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs @@ -46,7 +46,7 @@ where { with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to nll - //~| ERROR Argument requires that data must outlive free region + //~| ERROR argument requires that data must outlive free region } #[rustc_regions] @@ -57,7 +57,7 @@ where { with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to nll - //~| ERROR Argument requires that data must outlive free region + //~| ERROR argument requires that data must outlive free region } #[rustc_regions] @@ -78,7 +78,7 @@ where with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to nll - //~| ERROR Argument requires that data must outlive free region + //~| ERROR argument requires that data must outlive free region } #[rustc_regions] diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 07e65fb405158..be11c6249f0ba 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -31,7 +31,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: number of external vids: 3 = note: where '_#1r: '_#2r -error: Argument requires that data must outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))` +error: argument requires that data must outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))` --> $DIR/projection-one-region-trait-bound-closure.rs:47:5 | LL | with_signature(cell, t, |cell, t| require(cell, t)); @@ -45,7 +45,7 @@ LL | | where LL | | T: Anything<'b>, LL | | { ... | -LL | | //~| ERROR Argument requires that data must outlive free region +LL | | //~| ERROR argument requires that data must outlive free region LL | | } | |_^ | @@ -70,7 +70,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: number of external vids: 4 = note: where '_#2r: '_#3r -error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)` +error: argument requires that data must outlive free region `ReEarlyBound(0, 'a)` --> $DIR/projection-one-region-trait-bound-closure.rs:58:5 | LL | with_signature(cell, t, |cell, t| require(cell, t)); @@ -84,7 +84,7 @@ LL | | where LL | | T: Anything<'b>, LL | | 'a: 'a, ... | -LL | | //~| ERROR Argument requires that data must outlive free region +LL | | //~| ERROR argument requires that data must outlive free region LL | | } | |_^ | @@ -110,7 +110,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: number of external vids: 4 = note: where '_#2r: '_#3r -error: Argument requires that data must outlive free region `ReEarlyBound(0, 'a)` +error: argument requires that data must outlive free region `ReEarlyBound(0, 'a)` --> $DIR/projection-one-region-trait-bound-closure.rs:79:5 | LL | with_signature(cell, t, |cell, t| require(cell, t)); @@ -124,7 +124,7 @@ LL | | where LL | | T: Anything<'b>, LL | | T::AssocType: 'a, ... | -LL | | //~| ERROR Argument requires that data must outlive free region +LL | | //~| ERROR argument requires that data must outlive free region LL | | } | |_^ | diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs index 8129f93736b64..5e481a9626f08 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs @@ -107,7 +107,7 @@ where { with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to nll - //~| ERROR Argument requires that data must outlive free region + //~| ERROR argument requires that data must outlive free region } #[rustc_regions] diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index c778f23a2c450..546384e8545e3 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -239,7 +239,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: number of external vids: 3 = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r -error: Argument requires that data must outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))` +error: argument requires that data must outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))` --> $DIR/projection-two-region-trait-bound-closure.rs:108:5 | LL | with_signature(cell, t, |cell, t| require(cell, t)); @@ -253,7 +253,7 @@ LL | | where LL | | T: Anything<'b, 'b>, LL | | { ... | -LL | | //~| ERROR Argument requires that data must outlive free region +LL | | //~| ERROR argument requires that data must outlive free region LL | | } | |_^ | diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr index 681c0dce7d172..49f9044b19b24 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr @@ -22,7 +22,7 @@ warning: not reporting region error due to nll LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^^^^^^^^^^^^^^^^^^^ -error: Cast requires that data must outlive free region `'static` +error: cast requires that data must outlive free region `'static` --> $DIR/dyn-trait-underscore.rs:18:5 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime From f334a9e8dd3438fb2f827b8f3932b18ae50e76ce Mon Sep 17 00:00:00 2001 From: Niko Matsakis <niko@alum.mit.edu> Date: Thu, 28 Jun 2018 15:00:00 -0400 Subject: [PATCH 13/15] WIP boring() long line --- src/librustc_mir/borrow_check/nll/type_check/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 911e543425916..e3d20d9a8dbcb 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1523,7 +1523,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(), }; - self.normalize_and_prove_instantiated_predicates(instantiated_predicates, location.boring()); + self.normalize_and_prove_instantiated_predicates( + instantiated_predicates, + location.boring(), + ); } fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, locations: Locations) { From 15aad8356083e6098f7e8aefa1293b68201ec43c Mon Sep 17 00:00:00 2001 From: David Wood <david@davidtw.co> Date: Fri, 29 Jun 2018 22:17:35 +0100 Subject: [PATCH 14/15] Fix infinite loops when regions are self-referential. --- .../nll/region_infer/error_reporting.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs index f3372f6be703b..970652d8872cd 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs @@ -63,12 +63,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Regions that have been visited. let mut visited = FxHashSet(); // Ends of paths. - let mut end_regions: Vec<RegionVid> = Vec::new(); + let mut end_regions = FxHashSet(); // When we've still got points to visit... while let Some(current) = next.pop() { // ...take the next point... - debug!("find_constraint_paths_from_region: current={:?} next={:?}", current, next); + debug!("find_constraint_paths_from_region: current={:?} visited={:?} next={:?}", + current, visited, next); + // ...but make sure not to visit this point again... + visited.insert(current); // ...find the edges containing it... let mut upcoming = Vec::new(); @@ -93,16 +96,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { if upcoming.is_empty() { // If we didn't find any edges then this is the end of a path... debug!("find_constraint_paths_from_region: new end region current={:?}", current); - end_regions.push(current); + end_regions.insert(current); } else { - // ...but, if we did find edges, then add these to the regions yet to visit... + // ...but, if we did find edges, then add these to the regions yet to visit. debug!("find_constraint_paths_from_region: extend next upcoming={:?}", upcoming); next.extend(upcoming); } - // ...and don't visit it again. - visited.insert(current.clone()); - debug!("find_constraint_paths_from_region: next={:?} visited={:?}", next, visited); } // Now we've visited each point, compute the final paths. From c0c4741ef794d707a4378ace1547e8a41961016a Mon Sep 17 00:00:00 2001 From: David Wood <david@davidtw.co> Date: Sat, 30 Jun 2018 00:10:00 +0100 Subject: [PATCH 15/15] Updated affected tests after rebase. --- src/test/ui/borrowck/issue-45983.nll.stderr | 2 +- src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr | 2 +- .../propagate-approximated-shorter-to-static-no-bound.stderr | 2 +- ...ropagate-approximated-shorter-to-static-wrong-bound.stderr | 2 +- src/test/ui/nll/issue-50716.rs | 2 +- src/test/ui/nll/issue-50716.stderr | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr index a62d81c033333..a008a408d9711 100644 --- a/src/test/ui/borrowck/issue-45983.nll.stderr +++ b/src/test/ui/borrowck/issue-45983.nll.stderr @@ -4,7 +4,7 @@ warning: not reporting region error due to nll LL | give_any(|y| x = Some(y)); | ^ -error: assignment requires that data must outlive free region `'_#2r` +error: free region `` does not outlive free region `'_#2r` --> $DIR/issue-45983.rs:17:27 | LL | give_any(|y| x = Some(y)); diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr index 7a4db0802a846..ee3970aa8fd8f 100644 --- a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr +++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr @@ -4,7 +4,7 @@ warning: not reporting region error due to nll LL | with_int(|y| x = Some(y)); | ^ -error: assignment requires that data must outlive free region `'_#2r` +error: free region `` does not outlive free region `'_#2r` --> $DIR/regions-escape-bound-fn-2.rs:18:27 | LL | with_int(|y| x = Some(y)); diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index 582417b0da934..40f215619c689 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -32,7 +32,7 @@ LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll LL | | }); - | |_____^ + | |______^ note: No external requirements --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:44:1 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index 481ba512972fa..d89ff028a5042 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -32,7 +32,7 @@ LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | //~^ WARNING not reporting region error due to nll LL | | }); - | |_____^ + | |______^ note: No external requirements --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:47:1 diff --git a/src/test/ui/nll/issue-50716.rs b/src/test/ui/nll/issue-50716.rs index 310600aaf9ac8..a41af168c3e4e 100644 --- a/src/test/ui/nll/issue-50716.rs +++ b/src/test/ui/nll/issue-50716.rs @@ -22,7 +22,7 @@ where for<'b> &'b T: A, <&'static T as A>::X: Sized { - let _x = *s; //~ ERROR free region `'a` does not outlive free region `'static` + let _x = *s; //~ ERROR assignment requires that data must outlive free region `'static` } fn main() {} diff --git a/src/test/ui/nll/issue-50716.stderr b/src/test/ui/nll/issue-50716.stderr index 20b03d648d9b6..de69f8cfbcb6e 100644 --- a/src/test/ui/nll/issue-50716.stderr +++ b/src/test/ui/nll/issue-50716.stderr @@ -1,7 +1,7 @@ -error: free region `'a` does not outlive free region `'static` +error: assignment requires that data must outlive free region `'static` --> $DIR/issue-50716.rs:25:14 | -LL | let _x = *s; //~ ERROR free region `'a` does not outlive free region `'static` +LL | let _x = *s; //~ ERROR assignment requires that data must outlive free region `'static` | ^^ error: aborting due to previous error