propagate boring vs interesting causal info for constraints/tests

This commit is contained in:
Niko Matsakis 2018-06-04 12:25:12 -04:00 committed by David Wood
parent 609bb27514
commit 0b620186fd
No known key found for this signature in database
GPG key ID: 01760B4F9F53F154
7 changed files with 70 additions and 72 deletions

View file

@ -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(),
);

View file

@ -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
)
}
}

View file

@ -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,
))?;
}

View file

@ -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())
}
}

View file

@ -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).

View file

@ -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,

View file

@ -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)
}
}