Skip to content

Commit 109c30f

Browse files
committed
More separation of error reporting from region inference
1 parent 3ebcfa1 commit 109c30f

File tree

4 files changed

+77
-99
lines changed

4 files changed

+77
-99
lines changed

src/librustc_mir/borrow_check/diagnostics/region_errors.rs

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
//! Error reporting machinery for lifetime errors.
22
33
use rustc::infer::{
4-
error_reporting::nice_region_error::NiceRegionError, region_constraints::GenericKind,
5-
InferCtxt, NLLRegionVariableOrigin,
4+
error_reporting::nice_region_error::NiceRegionError, InferCtxt, NLLRegionVariableOrigin,
65
};
76
use rustc::mir::{Body, ConstraintCategory, Location};
87
use rustc::ty::{self, RegionVid, Ty};
@@ -16,8 +15,11 @@ use std::collections::VecDeque;
1615
use crate::util::borrowck_errors;
1716

1817
use crate::borrow_check::{
19-
constraints::OutlivesConstraint, nll::ConstraintDescription,
20-
region_infer::RegionInferenceContext, type_check::Locations, universal_regions::DefiningTy,
18+
constraints::OutlivesConstraint,
19+
nll::ConstraintDescription,
20+
region_infer::{values::RegionElement, RegionInferenceContext, TypeTest},
21+
type_check::Locations,
22+
universal_regions::DefiningTy,
2123
MirBorrowckCtxt,
2224
};
2325

@@ -62,23 +64,8 @@ crate type RegionErrors<'tcx> = Vec<RegionErrorKind<'tcx>>;
6264

6365
#[derive(Clone, Debug)]
6466
crate enum RegionErrorKind<'tcx> {
65-
/// An error for a type test: `T: 'a` does not live long enough.
66-
TypeTestDoesNotLiveLongEnough {
67-
/// The span of the type test.
68-
span: Span,
69-
/// The generic type of the type test.
70-
generic: GenericKind<'tcx>,
71-
},
72-
73-
/// A generic bound failure for a type test.
74-
TypeTestGenericBoundError {
75-
/// The span of the type test.
76-
span: Span,
77-
/// The generic type of the type test.
78-
generic: GenericKind<'tcx>,
79-
/// The lower bound region.
80-
lower_bound_region: ty::Region<'tcx>,
81-
},
67+
/// A generic bound failure for a type test (`T: 'a`).
68+
TypeTestError { type_test: TypeTest<'tcx> },
8269

8370
/// An unexpected hidden region for an opaque type.
8471
UnexpectedHiddenRegion {
@@ -94,8 +81,8 @@ crate enum RegionErrorKind<'tcx> {
9481
BoundUniversalRegionError {
9582
/// The placeholder free region.
9683
longer_fr: RegionVid,
97-
/// The region that erroneously must be outlived by `longer_fr`.
98-
error_region: RegionVid,
84+
/// The region element that erroneously must be outlived by `longer_fr`.
85+
error_element: RegionElement,
9986
/// The origin of the placeholder region.
10087
fr_origin: NLLRegionVariableOrigin,
10188
},

src/librustc_mir/borrow_check/mod.rs

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
631631

632632
debug!(
633633
"visit_terminator_drop \
634-
loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}",
634+
loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}",
635635
loc, term, drop_place, drop_place_ty, span
636636
);
637637

@@ -1477,38 +1477,42 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
14771477

14781478
for nll_error in nll_errors.into_iter() {
14791479
match nll_error {
1480-
RegionErrorKind::TypeTestDoesNotLiveLongEnough { span, generic } => {
1481-
// FIXME. We should handle this case better. It
1482-
// indicates that we have e.g., some region variable
1483-
// whose value is like `'a+'b` where `'a` and `'b` are
1484-
// distinct unrelated univesal regions that are not
1485-
// known to outlive one another. It'd be nice to have
1486-
// some examples where this arises to decide how best
1487-
// to report it; we could probably handle it by
1488-
// iterating over the universal regions and reporting
1489-
// an error that multiple bounds are required.
1490-
self.infcx
1491-
.tcx
1492-
.sess
1493-
.struct_span_err(span, &format!("`{}` does not live long enough", generic))
1494-
.buffer(&mut self.errors_buffer);
1495-
}
1496-
1497-
RegionErrorKind::TypeTestGenericBoundError {
1498-
span,
1499-
generic,
1500-
lower_bound_region,
1501-
} => {
1502-
let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id);
1503-
self.infcx
1504-
.construct_generic_bound_failure(
1505-
region_scope_tree,
1506-
span,
1507-
None,
1508-
generic,
1509-
lower_bound_region,
1510-
)
1511-
.buffer(&mut self.errors_buffer);
1480+
RegionErrorKind::TypeTestError { type_test } => {
1481+
// Try to convert the lower-bound region into something named we can print for the user.
1482+
let lower_bound_region =
1483+
self.nonlexical_regioncx.to_error_region(type_test.lower_bound);
1484+
1485+
// Skip duplicate-ish errors.
1486+
let type_test_span = type_test.locations.span(&self.body);
1487+
1488+
if let Some(lower_bound_region) = lower_bound_region {
1489+
let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id);
1490+
self.infcx
1491+
.construct_generic_bound_failure(
1492+
region_scope_tree,
1493+
type_test_span,
1494+
None,
1495+
type_test.generic_kind,
1496+
lower_bound_region,
1497+
)
1498+
.buffer(&mut self.errors_buffer);
1499+
} else {
1500+
// FIXME. We should handle this case better. It indicates that we have
1501+
// e.g., some region variable whose value is like `'a+'b` where `'a` and
1502+
// `'b` are distinct unrelated univesal regions that are not known to
1503+
// outlive one another. It'd be nice to have some examples where this
1504+
// arises to decide how best to report it; we could probably handle it by
1505+
// iterating over the universal regions and reporting an error that
1506+
// multiple bounds are required.
1507+
self.infcx
1508+
.tcx
1509+
.sess
1510+
.struct_span_err(
1511+
type_test_span,
1512+
&format!("`{}` does not live long enough", type_test.generic_kind),
1513+
)
1514+
.buffer(&mut self.errors_buffer);
1515+
}
15121516
}
15131517

15141518
RegionErrorKind::UnexpectedHiddenRegion {
@@ -1530,8 +1534,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15301534
RegionErrorKind::BoundUniversalRegionError {
15311535
longer_fr,
15321536
fr_origin,
1533-
error_region,
1537+
error_element,
15341538
} => {
1539+
let error_region =
1540+
self.nonlexical_regioncx.region_from_element(longer_fr, error_element);
1541+
15351542
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
15361543
let (_, span) = self.nonlexical_regioncx.find_outlives_blame_span(
15371544
&self.body,
@@ -2225,7 +2232,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
22252232
let upvar = &self.upvars[field.index()];
22262233
debug!(
22272234
"upvar.mutability={:?} local_mutation_is_allowed={:?} \
2228-
place={:?}",
2235+
place={:?}",
22292236
upvar, is_local_mutation_allowed, place
22302237
);
22312238
match (upvar.mutability, is_local_mutation_allowed) {

src/librustc_mir/borrow_check/region_infer/mod.rs

Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -838,39 +838,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
838838
}
839839

840840
// Type-test failed. Report the error.
841-
842-
// Try to convert the lower-bound region into something named we can print for the user.
843-
let lower_bound_region = self.to_error_region(type_test.lower_bound);
844-
845-
// Skip duplicate-ish errors.
846-
let type_test_span = type_test.locations.span(body);
847-
let erased_generic_kind = tcx.erase_regions(&type_test.generic_kind);
848-
if !deduplicate_errors.insert((
841+
let erased_generic_kind = infcx.tcx.erase_regions(&type_test.generic_kind);
842+
if deduplicate_errors.insert((
849843
erased_generic_kind,
850-
lower_bound_region,
844+
type_test.lower_bound,
851845
type_test.locations,
852846
)) {
853-
continue;
854-
} else {
855847
debug!(
856848
"check_type_test: reporting error for erased_generic_kind={:?}, \
857849
lower_bound_region={:?}, \
858850
type_test.locations={:?}",
859-
erased_generic_kind, lower_bound_region, type_test.locations,
851+
erased_generic_kind, type_test.lower_bound, type_test.locations,
860852
);
861-
}
862853

863-
if let Some(lower_bound_region) = lower_bound_region {
864-
errors_buffer.push(RegionErrorKind::TypeTestGenericBoundError {
865-
span: type_test_span,
866-
generic: type_test.generic_kind,
867-
lower_bound_region,
868-
});
869-
} else {
870-
errors_buffer.push(RegionErrorKind::TypeTestDoesNotLiveLongEnough {
871-
span: type_test_span,
872-
generic: type_test.generic_kind,
873-
});
854+
errors_buffer.push(RegionErrorKind::TypeTestError { type_test: type_test.clone() });
874855
}
875856
}
876857
}
@@ -1355,7 +1336,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
13551336
for (longer_fr, shorter_fr) in subset_errors.into_iter() {
13561337
debug!(
13571338
"check_polonius_subset_errors: subset_error longer_fr={:?},\
1358-
shorter_fr={:?}",
1339+
shorter_fr={:?}",
13591340
longer_fr, shorter_fr
13601341
);
13611342

@@ -1572,23 +1553,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
15721553
debug!("check_bound_universal_region: error_element = {:?}", error_element);
15731554

15741555
// Find the region that introduced this `error_element`.
1575-
let error_region = match error_element {
1576-
RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l),
1577-
RegionElement::RootUniversalRegion(r) => r,
1578-
RegionElement::PlaceholderRegion(error_placeholder) => self
1579-
.definitions
1580-
.iter_enumerated()
1581-
.filter_map(|(r, definition)| match definition.origin {
1582-
NLLRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r),
1583-
_ => None,
1584-
})
1585-
.next()
1586-
.unwrap(),
1587-
};
1588-
15891556
errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
15901557
longer_fr,
1591-
error_region,
1558+
error_element,
15921559
fr_origin: NLLRegionVariableOrigin::Placeholder(placeholder),
15931560
});
15941561
}
@@ -1628,6 +1595,23 @@ impl<'tcx> RegionInferenceContext<'tcx> {
16281595
});
16291596
}
16301597
}
1598+
1599+
/// Get the region outlived by `longer_fr` and live at `element`.
1600+
crate fn region_from_element(&self, longer_fr: RegionVid, element: RegionElement) -> RegionVid {
1601+
match element {
1602+
RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l),
1603+
RegionElement::RootUniversalRegion(r) => r,
1604+
RegionElement::PlaceholderRegion(error_placeholder) => self
1605+
.definitions
1606+
.iter_enumerated()
1607+
.filter_map(|(r, definition)| match definition.origin {
1608+
NLLRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r),
1609+
_ => None,
1610+
})
1611+
.next()
1612+
.unwrap(),
1613+
}
1614+
}
16311615
}
16321616

16331617
impl<'tcx> RegionDefinition<'tcx> {

src/librustc_mir/borrow_check/region_infer/values.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ rustc_index::newtype_index! {
114114

115115
/// An individual element in a region value -- the value of a
116116
/// particular region variable consists of a set of these elements.
117-
#[derive(Debug)]
117+
#[derive(Debug, Clone)]
118118
crate enum RegionElement {
119119
/// A point in the control-flow graph.
120120
Location(Location),

0 commit comments

Comments
 (0)