propagate boring vs interesting causal info for constraints/tests
This commit is contained in:
parent
609bb27514
commit
0b620186fd
7 changed files with 70 additions and 72 deletions
|
|
@ -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(),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
))?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue