diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 72db9f8da9872..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,12 +311,10 @@ 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(), - 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..3bdf78ff3db54 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_set.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs @@ -8,12 +8,11 @@ // 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}; +use borrow_check::nll::type_check::Locations; use std::fmt; -use syntax_pos::Span; use std::ops::Deref; #[derive(Clone, Default)] @@ -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, constraint.locations ); 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: /// @@ -100,15 +96,15 @@ pub struct OutlivesConstraint { pub next: Option, /// Where did this constraint arise? - pub span: Span, + pub locations: Locations, } 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.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 6c796ea4c73ab..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,16 +82,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { let OutlivesConstraint { sup, sub, - point, - span, + locations, next: _, } = constraint; with_msg(&format!( - "{:?}: {:?} @ {:?} due to {:?}", + "{:?}: {:?} due to {:?}", sup, sub, - point, - span + locations, ))?; } 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..970652d8872cd --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs @@ -0,0 +1,340 @@ +// 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 or the MIT license +// , at your +// 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::{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. Order of variants indicates +/// sort order of the category, thereby influencing diagnostic output. +#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)] +enum ConstraintCategory { + 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> { + /// 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> { + 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 = 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={:?} 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(); + 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.insert(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); + } + + } + + // Now we've visited each point, compute the final paths. + let mut paths: Vec> = 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 = 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, 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]; + let category = 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 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 + /// `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 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: shortest_path={:?}", path); + + let mut categorized_path = path.iter().filter_map(|index| { + self.classify_constraint(index, mir) + }).collect::>(); + 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 let Some((category, span)) = &categorized_path.first() { + let mut diag = infcx.tcx.sess.struct_span_err( + *span, &format!("{} requires that data must outlive {}", + category, outlived_fr_string), + ); + + diag.emit(); + } else { + 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 { + // 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> { + 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/graphviz.rs b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs index 106dd003ceab9..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.point).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 a576dc5f7f47b..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,28 +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, 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, + 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::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}; @@ -154,11 +154,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,17 +353,15 @@ 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, - point: Location, ) { assert!(self.inferred_values.is_none(), "values already inferred"); self.constraints.push(OutlivesConstraint { - span, + locations, sup, sub, - point, next: None, }) } @@ -410,7 +405,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![]); @@ -503,12 +498,13 @@ 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; } 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; } } @@ -517,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, @@ -534,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,), ); } @@ -568,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>, ) -> bool { @@ -576,8 +575,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let TypeTest { generic_kind, lower_bound, - point: _, - span, + locations, test: _, } = type_test; @@ -601,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 } @@ -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 @@ -869,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>>, ) { @@ -885,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, @@ -903,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>>, @@ -925,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). @@ -960,134 +959,9 @@ 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); } } - - /// 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, - 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 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 { - // 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> { - 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> { 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..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.at_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,21 +181,11 @@ 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(); - let point = self.locations.at_location().unwrap_or(Location::START); - self.outlives_constraints.push(OutlivesConstraint { - span, + locations: self.locations, sub, sup, - point, next: None, }); } 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 611050a406020..e3d20d9a8dbcb 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); @@ -288,7 +287,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 +312,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 +342,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 +386,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 +485,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, @@ -600,7 +596,6 @@ struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { reported_errors: FxHashSet<(Ty<'tcx>, Span)>, constraints: MirTypeckRegionConstraints<'tcx>, borrowck_context: Option>, - mir: &'a Mir<'tcx>, } struct BorrowCheckContext<'a, 'tcx: 'a> { @@ -631,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 @@ -666,32 +661,41 @@ 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, - - /// 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, - }, + /// 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 { match self { Locations::All => None, - Locations::Pair { from_location, .. } => Some(*from_location), + Locations::Boring(from_location) | Locations::Interesting(from_location) => { + Some(*from_location) + } } } - pub fn at_location(&self) -> Option { - match self { - Locations::All => None, - Locations::Pair { at_location, .. } => Some(*at_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 } } @@ -703,7 +707,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)], implicit_region_bound: Option>, borrowck_context: Option>, - mir: &'a Mir<'tcx>, ) -> Self { TypeChecker { infcx, @@ -713,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(), } @@ -756,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, @@ -797,11 +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.at_successor_within_block()) - { + if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) { span_mirbug!( self, stmt, @@ -816,7 +827,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, @@ -897,16 +908,13 @@ 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(), - }; + let locations = term_location.interesting(); if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) { span_mirbug!( self, @@ -917,26 +925,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, @@ -944,7 +932,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, @@ -984,7 +972,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 @@ -1026,7 +1014,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.at_self()) { + if let Err(terr) = self.sub_types(value_ty, ty, term_location.interesting()) + { span_mirbug!( self, term, @@ -1052,12 +1041,9 @@ 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(), - }; + let locations = term_location.interesting(); if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations) { span_mirbug!( self, @@ -1092,7 +1078,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, @@ -1320,7 +1306,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) => { @@ -1329,7 +1315,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 { @@ -1345,7 +1331,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, @@ -1366,7 +1352,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, @@ -1390,7 +1376,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, @@ -1409,7 +1395,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 => {} @@ -1458,7 +1444,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, @@ -1519,8 +1506,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, ); } @@ -1535,53 +1523,56 @@ 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>, - 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); @@ -1614,7 +1605,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn normalize(&mut self, value: T, location: impl ToLocations) -> T + fn normalize(&mut self, value: T, location: impl NormalizeLocation) -> T where T: type_op::normalize::Normalizable<'gcx, 'tcx> + Copy, { @@ -1667,52 +1658,38 @@ 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; - - /// 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; +pub trait AtLocation { + /// 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 { - Locations::Pair { - from_location: self, - at_location: self, - } + fn boring(self) -> Locations { + Locations::Boring(self) } - fn at_successor_within_block(self) -> Locations { - Locations::Pair { - from_location: self, - at_location: self.successor_within_block(), - } + fn interesting(self) -> Locations { + Locations::Interesting(self) } } -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() + self.boring() } } 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..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 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..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,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..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 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..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 @@ -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,24 +23,23 @@ 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 LL | | }); - | |_____^ + | |______^ note: No external requirements --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:44:1 | 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..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 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..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 @@ -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,24 +23,23 @@ 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 LL | | }); - | |_____^ + | |______^ note: No external requirements --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:47:1 | 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..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 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..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,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/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 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..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 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..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,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..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 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..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,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..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 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..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,11 +239,11 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: number of external vids: 3 = note: where >::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..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,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(items: &[T]) -> Box> { - | ____________________________________________________^ -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