Skip to content

Commit 4c7f5af

Browse files
committed
Separate region inference logic from error handling better
1 parent 19bd934 commit 4c7f5af

File tree

2 files changed

+96
-88
lines changed

2 files changed

+96
-88
lines changed

src/librustc_mir/borrow_check/diagnostics/region_errors.rs

+33-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
//! Error reporting machinery for lifetime errors.
22
33
use rustc::hir::def_id::DefId;
4-
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
5-
use rustc::infer::InferCtxt;
6-
use rustc::infer::NLLRegionVariableOrigin;
7-
use rustc::mir::{ConstraintCategory, Local, Location, Body};
4+
use rustc::infer::{
5+
error_reporting::nice_region_error::NiceRegionError,
6+
InferCtxt, NLLRegionVariableOrigin,
7+
};
8+
use rustc::mir::{
9+
ConstraintCategory, Local, Location, Body,
10+
};
811
use rustc::ty::{self, RegionVid};
912
use rustc_index::vec::IndexVec;
1013
use rustc_errors::DiagnosticBuilder;
@@ -93,6 +96,32 @@ pub struct ErrorConstraintInfo {
9396
}
9497

9598
impl<'tcx> RegionInferenceContext<'tcx> {
99+
/// Converts a region inference variable into a `ty::Region` that
100+
/// we can use for error reporting. If `r` is universally bound,
101+
/// then we use the name that we have on record for it. If `r` is
102+
/// existentially bound, then we check its inferred value and try
103+
/// to find a good name from that. Returns `None` if we can't find
104+
/// one (e.g., this is just some random part of the CFG).
105+
pub fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> {
106+
self.to_error_region_vid(r).and_then(|r| self.definitions[r].external_name)
107+
}
108+
109+
/// Returns the [RegionVid] corresponding to the region returned by
110+
/// `to_error_region`.
111+
pub fn to_error_region_vid(&self, r: RegionVid) -> Option<RegionVid> {
112+
if self.universal_regions.is_universal_region(r) {
113+
Some(r)
114+
} else {
115+
let r_scc = self.constraint_sccs.scc(r);
116+
let upper_bound = self.universal_upper_bound(r);
117+
if self.scc_values.contains(r_scc, upper_bound) {
118+
self.to_error_region_vid(upper_bound)
119+
} else {
120+
None
121+
}
122+
}
123+
}
124+
96125
/// Tries to find the best constraint to blame for the fact that
97126
/// `R: from_region`, where `R` is some region that meets
98127
/// `target_test`. This works by following the constraint graph,

src/librustc_mir/borrow_check/region_infer/mod.rs

+63-84
Original file line numberDiff line numberDiff line change
@@ -928,32 +928,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
928928
}
929929
}
930930

931-
/// Converts a region inference variable into a `ty::Region` that
932-
/// we can use for error reporting. If `r` is universally bound,
933-
/// then we use the name that we have on record for it. If `r` is
934-
/// existentially bound, then we check its inferred value and try
935-
/// to find a good name from that. Returns `None` if we can't find
936-
/// one (e.g., this is just some random part of the CFG).
937-
pub fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> {
938-
self.to_error_region_vid(r).and_then(|r| self.definitions[r].external_name)
939-
}
940-
941-
/// Returns the [RegionVid] corresponding to the region returned by
942-
/// `to_error_region`.
943-
pub fn to_error_region_vid(&self, r: RegionVid) -> Option<RegionVid> {
944-
if self.universal_regions.is_universal_region(r) {
945-
Some(r)
946-
} else {
947-
let r_scc = self.constraint_sccs.scc(r);
948-
let upper_bound = self.universal_upper_bound(r);
949-
if self.scc_values.contains(r_scc, upper_bound) {
950-
self.to_error_region_vid(upper_bound)
951-
} else {
952-
None
953-
}
954-
}
955-
}
956-
957931
/// Invoked when we have some type-test (e.g., `T: 'X`) that we cannot
958932
/// prove to be satisfied. If this is a closure, we will attempt to
959933
/// "promote" this type-test into our `ClosureRegionRequirements` and
@@ -1164,7 +1138,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11641138
/// include the CFG anyhow.
11651139
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
11661140
/// a result `'y`.
1167-
fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
1141+
pub (in crate::borrow_check) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
11681142
debug!("universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
11691143

11701144
// Find the smallest universal region that contains all other
@@ -1458,19 +1432,34 @@ impl<'tcx> RegionInferenceContext<'tcx> {
14581432
debug!("check_polonius_subset_errors: subset_error longer_fr={:?},\
14591433
shorter_fr={:?}", longer_fr, shorter_fr);
14601434

1461-
self.report_or_propagate_universal_region_error(
1435+
let propagated = self.try_propagate_universal_region_error(
14621436
*longer_fr,
14631437
*shorter_fr,
1464-
infcx,
14651438
body,
1466-
local_names,
1467-
upvars,
1468-
mir_def_id,
14691439
&mut propagated_outlives_requirements,
1470-
&mut outlives_suggestion,
1471-
errors_buffer,
1472-
region_naming,
14731440
);
1441+
if !propagated {
1442+
// If we are not in a context where we can't propagate errors, or we
1443+
// could not shrink `fr` to something smaller, then just report an
1444+
// error.
1445+
//
1446+
// Note: in this case, we use the unapproximated regions to report the
1447+
// error. This gives better error messages in some cases.
1448+
let db = self.report_error(
1449+
body,
1450+
local_names,
1451+
upvars,
1452+
infcx,
1453+
mir_def_id,
1454+
*longer_fr,
1455+
NLLRegionVariableOrigin::FreeRegion,
1456+
*shorter_fr,
1457+
&mut outlives_suggestion,
1458+
region_naming,
1459+
);
1460+
1461+
db.buffer(errors_buffer);
1462+
}
14741463
}
14751464

14761465
// Handle the placeholder errors as usual, until the chalk-rustc-polonius triumvirate has
@@ -1594,48 +1583,59 @@ impl<'tcx> RegionInferenceContext<'tcx> {
15941583
return None;
15951584
}
15961585

1597-
self.report_or_propagate_universal_region_error(
1586+
let propagated = self.try_propagate_universal_region_error(
15981587
longer_fr,
15991588
shorter_fr,
1600-
infcx,
16011589
body,
1602-
local_names,
1603-
upvars,
1604-
mir_def_id,
16051590
propagated_outlives_requirements,
1606-
outlives_suggestion,
1607-
errors_buffer,
1608-
region_naming,
1609-
)
1591+
);
1592+
1593+
if propagated {
1594+
None
1595+
} else {
1596+
// If we are not in a context where we can't propagate errors, or we
1597+
// could not shrink `fr` to something smaller, then just report an
1598+
// error.
1599+
//
1600+
// Note: in this case, we use the unapproximated regions to report the
1601+
// error. This gives better error messages in some cases.
1602+
let db = self.report_error(
1603+
body,
1604+
local_names,
1605+
upvars,
1606+
infcx,
1607+
mir_def_id,
1608+
longer_fr,
1609+
NLLRegionVariableOrigin::FreeRegion,
1610+
shorter_fr,
1611+
outlives_suggestion,
1612+
region_naming,
1613+
);
1614+
1615+
db.buffer(errors_buffer);
1616+
1617+
Some(ErrorReported)
1618+
}
16101619
}
16111620

1612-
fn report_or_propagate_universal_region_error(
1621+
/// Attempt to propagate a region error (e.g. `'a: 'b`) that is not met to a closure's
1622+
/// creator. If we cannot, then we report an error to the user.
1623+
///
1624+
/// Returns `true` if the error was propagated, and `false` otherwise.
1625+
fn try_propagate_universal_region_error(
16131626
&self,
16141627
longer_fr: RegionVid,
16151628
shorter_fr: RegionVid,
1616-
infcx: &InferCtxt<'_, 'tcx>,
16171629
body: &Body<'tcx>,
1618-
local_names: &IndexVec<Local, Option<Symbol>>,
1619-
upvars: &[Upvar],
1620-
mir_def_id: DefId,
16211630
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
1622-
outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>,
1623-
errors_buffer: &mut Vec<Diagnostic>,
1624-
region_naming: &mut RegionErrorNamingCtx,
1625-
) -> Option<ErrorReported> {
1626-
debug!(
1627-
"report_or_propagate_universal_region_error: fr={:?} does not outlive shorter_fr={:?}",
1628-
longer_fr, shorter_fr,
1629-
);
1630-
1631+
) -> bool {
16311632
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
16321633
// Shrink `longer_fr` until we find a non-local region (if we do).
16331634
// We'll call it `fr-` -- it's ever so slightly smaller than
16341635
// `longer_fr`.
1635-
16361636
if let Some(fr_minus) =
16371637
self.universal_region_relations.non_local_lower_bound(longer_fr) {
1638-
debug!("report_or_propagate_universal_region_error: fr_minus={:?}", fr_minus);
1638+
debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus);
16391639

16401640
let blame_span_category =
16411641
self.find_outlives_blame_span(body, longer_fr,
@@ -1648,7 +1648,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
16481648
.universal_region_relations
16491649
.non_local_upper_bounds(&shorter_fr);
16501650
debug!(
1651-
"report_or_propagate_universal_region_error: shorter_fr_plus={:?}",
1651+
"try_propagate_universal_region_error: shorter_fr_plus={:?}",
16521652
shorter_fr_plus
16531653
);
16541654
for &&fr in &shorter_fr_plus {
@@ -1660,32 +1660,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
16601660
category: blame_span_category.0,
16611661
});
16621662
}
1663-
return None;
1663+
return true;
16641664
}
16651665
}
16661666

1667-
// If we are not in a context where we can't propagate errors, or we
1668-
// could not shrink `fr` to something smaller, then just report an
1669-
// error.
1670-
//
1671-
// Note: in this case, we use the unapproximated regions to report the
1672-
// error. This gives better error messages in some cases.
1673-
let db = self.report_error(
1674-
body,
1675-
local_names,
1676-
upvars,
1677-
infcx,
1678-
mir_def_id,
1679-
longer_fr,
1680-
NLLRegionVariableOrigin::FreeRegion,
1681-
shorter_fr,
1682-
outlives_suggestion,
1683-
region_naming,
1684-
);
1685-
1686-
db.buffer(errors_buffer);
1687-
1688-
Some(ErrorReported)
1667+
false
16891668
}
16901669

16911670
fn check_bound_universal_region(

0 commit comments

Comments
 (0)