More separation of error reporting from region inference

This commit is contained in:
Mark Mansi 2019-12-28 19:09:42 -06:00 committed by mark
parent 3ebcfa1451
commit 109c30f3d4
4 changed files with 76 additions and 98 deletions

View File

@ -1,8 +1,7 @@
//! Error reporting machinery for lifetime errors.
use rustc::infer::{
error_reporting::nice_region_error::NiceRegionError, region_constraints::GenericKind,
InferCtxt, NLLRegionVariableOrigin,
error_reporting::nice_region_error::NiceRegionError, InferCtxt, NLLRegionVariableOrigin,
};
use rustc::mir::{Body, ConstraintCategory, Location};
use rustc::ty::{self, RegionVid, Ty};
@ -16,8 +15,11 @@
use crate::util::borrowck_errors;
use crate::borrow_check::{
constraints::OutlivesConstraint, nll::ConstraintDescription,
region_infer::RegionInferenceContext, type_check::Locations, universal_regions::DefiningTy,
constraints::OutlivesConstraint,
nll::ConstraintDescription,
region_infer::{values::RegionElement, RegionInferenceContext, TypeTest},
type_check::Locations,
universal_regions::DefiningTy,
MirBorrowckCtxt,
};
@ -62,23 +64,8 @@ enum Trace {
#[derive(Clone, Debug)]
crate enum RegionErrorKind<'tcx> {
/// An error for a type test: `T: 'a` does not live long enough.
TypeTestDoesNotLiveLongEnough {
/// The span of the type test.
span: Span,
/// The generic type of the type test.
generic: GenericKind<'tcx>,
},
/// A generic bound failure for a type test.
TypeTestGenericBoundError {
/// The span of the type test.
span: Span,
/// The generic type of the type test.
generic: GenericKind<'tcx>,
/// The lower bound region.
lower_bound_region: ty::Region<'tcx>,
},
/// A generic bound failure for a type test (`T: 'a`).
TypeTestError { type_test: TypeTest<'tcx> },
/// An unexpected hidden region for an opaque type.
UnexpectedHiddenRegion {
@ -94,8 +81,8 @@ enum Trace {
BoundUniversalRegionError {
/// The placeholder free region.
longer_fr: RegionVid,
/// The region that erroneously must be outlived by `longer_fr`.
error_region: RegionVid,
/// The region element that erroneously must be outlived by `longer_fr`.
error_element: RegionElement,
/// The origin of the placeholder region.
fr_origin: NLLRegionVariableOrigin,
},

View File

@ -631,7 +631,7 @@ fn visit_terminator_entry(
debug!(
"visit_terminator_drop \
loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}",
loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}",
loc, term, drop_place, drop_place_ty, span
);
@ -1477,38 +1477,42 @@ fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
for nll_error in nll_errors.into_iter() {
match nll_error {
RegionErrorKind::TypeTestDoesNotLiveLongEnough { span, generic } => {
// FIXME. We should handle this case better. It
// indicates that we have e.g., some region variable
// whose value is like `'a+'b` where `'a` and `'b` are
// distinct unrelated univesal regions that are not
// known to outlive one another. It'd be nice to have
// some examples where this arises to decide how best
// to report it; we could probably handle it by
// iterating over the universal regions and reporting
// an error that multiple bounds are required.
self.infcx
.tcx
.sess
.struct_span_err(span, &format!("`{}` does not live long enough", generic))
.buffer(&mut self.errors_buffer);
}
RegionErrorKind::TypeTestError { type_test } => {
// Try to convert the lower-bound region into something named we can print for the user.
let lower_bound_region =
self.nonlexical_regioncx.to_error_region(type_test.lower_bound);
RegionErrorKind::TypeTestGenericBoundError {
span,
generic,
lower_bound_region,
} => {
let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id);
self.infcx
.construct_generic_bound_failure(
region_scope_tree,
span,
None,
generic,
lower_bound_region,
)
.buffer(&mut self.errors_buffer);
// Skip duplicate-ish errors.
let type_test_span = type_test.locations.span(&self.body);
if let Some(lower_bound_region) = lower_bound_region {
let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id);
self.infcx
.construct_generic_bound_failure(
region_scope_tree,
type_test_span,
None,
type_test.generic_kind,
lower_bound_region,
)
.buffer(&mut self.errors_buffer);
} else {
// FIXME. We should handle this case better. It indicates that we have
// e.g., some region variable whose value is like `'a+'b` where `'a` and
// `'b` are distinct unrelated univesal regions that are not known to
// outlive one another. It'd be nice to have some examples where this
// arises to decide how best to report it; we could probably handle it by
// iterating over the universal regions and reporting an error that
// multiple bounds are required.
self.infcx
.tcx
.sess
.struct_span_err(
type_test_span,
&format!("`{}` does not live long enough", type_test.generic_kind),
)
.buffer(&mut self.errors_buffer);
}
}
RegionErrorKind::UnexpectedHiddenRegion {
@ -1530,8 +1534,11 @@ fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
RegionErrorKind::BoundUniversalRegionError {
longer_fr,
fr_origin,
error_region,
error_element,
} => {
let error_region =
self.nonlexical_regioncx.region_from_element(longer_fr, error_element);
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
let (_, span) = self.nonlexical_regioncx.find_outlives_blame_span(
&self.body,
@ -2225,7 +2232,7 @@ fn is_mutable<'d>(
let upvar = &self.upvars[field.index()];
debug!(
"upvar.mutability={:?} local_mutation_is_allowed={:?} \
place={:?}",
place={:?}",
upvar, is_local_mutation_allowed, place
);
match (upvar.mutability, is_local_mutation_allowed) {

View File

@ -838,39 +838,20 @@ fn check_type_tests(
}
// Type-test failed. Report the error.
// Try to convert the lower-bound region into something named we can print for the user.
let lower_bound_region = self.to_error_region(type_test.lower_bound);
// Skip duplicate-ish errors.
let type_test_span = type_test.locations.span(body);
let erased_generic_kind = tcx.erase_regions(&type_test.generic_kind);
if !deduplicate_errors.insert((
let erased_generic_kind = infcx.tcx.erase_regions(&type_test.generic_kind);
if deduplicate_errors.insert((
erased_generic_kind,
lower_bound_region,
type_test.lower_bound,
type_test.locations,
)) {
continue;
} else {
debug!(
"check_type_test: reporting error for erased_generic_kind={:?}, \
lower_bound_region={:?}, \
type_test.locations={:?}",
erased_generic_kind, lower_bound_region, type_test.locations,
erased_generic_kind, type_test.lower_bound, type_test.locations,
);
}
if let Some(lower_bound_region) = lower_bound_region {
errors_buffer.push(RegionErrorKind::TypeTestGenericBoundError {
span: type_test_span,
generic: type_test.generic_kind,
lower_bound_region,
});
} else {
errors_buffer.push(RegionErrorKind::TypeTestDoesNotLiveLongEnough {
span: type_test_span,
generic: type_test.generic_kind,
});
errors_buffer.push(RegionErrorKind::TypeTestError { type_test: type_test.clone() });
}
}
}
@ -1355,7 +1336,7 @@ fn check_polonius_subset_errors(
for (longer_fr, shorter_fr) in subset_errors.into_iter() {
debug!(
"check_polonius_subset_errors: subset_error longer_fr={:?},\
shorter_fr={:?}",
shorter_fr={:?}",
longer_fr, shorter_fr
);
@ -1572,23 +1553,9 @@ fn check_bound_universal_region(
debug!("check_bound_universal_region: error_element = {:?}", error_element);
// Find the region that introduced this `error_element`.
let error_region = match error_element {
RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l),
RegionElement::RootUniversalRegion(r) => r,
RegionElement::PlaceholderRegion(error_placeholder) => self
.definitions
.iter_enumerated()
.filter_map(|(r, definition)| match definition.origin {
NLLRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r),
_ => None,
})
.next()
.unwrap(),
};
errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
longer_fr,
error_region,
error_element,
fr_origin: NLLRegionVariableOrigin::Placeholder(placeholder),
});
}
@ -1628,6 +1595,23 @@ fn check_member_constraints(
});
}
}
/// Get the region outlived by `longer_fr` and live at `element`.
crate fn region_from_element(&self, longer_fr: RegionVid, element: RegionElement) -> RegionVid {
match element {
RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l),
RegionElement::RootUniversalRegion(r) => r,
RegionElement::PlaceholderRegion(error_placeholder) => self
.definitions
.iter_enumerated()
.filter_map(|(r, definition)| match definition.origin {
NLLRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r),
_ => None,
})
.next()
.unwrap(),
}
}
}
impl<'tcx> RegionDefinition<'tcx> {

View File

@ -114,7 +114,7 @@ pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" }
/// An individual element in a region value -- the value of a
/// particular region variable consists of a set of these elements.
#[derive(Debug)]
#[derive(Debug, Clone)]
crate enum RegionElement {
/// A point in the control-flow graph.
Location(Location),