Skip to content

Commit 8258107

Browse files
committed
Improve closure region bound errors
Now use the category and span that are associated to the most interesting bound that led to the closure bound.
1 parent 1160e60 commit 8258107

18 files changed

+214
-148
lines changed

src/librustc/mir/mod.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -2639,11 +2639,14 @@ pub struct ClosureOutlivesRequirement<'tcx> {
26392639
// This region or type ...
26402640
pub subject: ClosureOutlivesSubject<'tcx>,
26412641

2642-
// .. must outlive this one.
2642+
// ... must outlive this one.
26432643
pub outlived_free_region: ty::RegionVid,
26442644

2645-
// If not, report an error here.
2645+
// If not, report an error here ...
26462646
pub blame_span: Span,
2647+
2648+
// ... due to this reason.
2649+
pub category: ConstraintCategory,
26472650
}
26482651

26492652
/// Outlives constraints can be categorized to determine whether and why they

src/librustc_mir/borrow_check/nll/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
138138
let MirTypeckRegionConstraints {
139139
mut liveness_constraints,
140140
outlives_constraints,
141+
closure_bounds_mapping,
141142
type_tests,
142143
} = constraints;
143144

@@ -157,6 +158,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
157158
universal_region_relations,
158159
mir,
159160
outlives_constraints,
161+
closure_bounds_mapping,
160162
type_tests,
161163
liveness_constraints,
162164
elements,

src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs

+27-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use borrow_check::nll::constraints::{OutlivesConstraint};
1212
use borrow_check::nll::region_infer::RegionInferenceContext;
13+
use borrow_check::nll::type_check::Locations;
1314
use rustc::hir::def_id::DefId;
1415
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
1516
use rustc::infer::InferCtxt;
@@ -18,7 +19,6 @@ use rustc::ty::{self, RegionVid};
1819
use rustc_data_structures::indexed_vec::IndexVec;
1920
use rustc_errors::{Diagnostic, DiagnosticBuilder};
2021
use std::collections::VecDeque;
21-
use std::fmt;
2222
use syntax::symbol::keywords;
2323
use syntax_pos::Span;
2424
use syntax::errors::Applicability;
@@ -93,7 +93,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
9393
// Classify each of the constraints along the path.
9494
let mut categorized_path: Vec<(ConstraintCategory, Span)> = path
9595
.iter()
96-
.map(|constraint| (constraint.category, constraint.locations.span(mir)))
96+
.map(|constraint| {
97+
if constraint.category == ConstraintCategory::ClosureBounds {
98+
self.retrieve_closure_constraint_info(mir, &constraint)
99+
} else {
100+
(constraint.category, constraint.locations.span(mir))
101+
}
102+
})
97103
.collect();
98104
debug!(
99105
"best_blame_constraint: categorized_path={:#?}",
@@ -474,8 +480,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
474480
mir: &Mir<'tcx>,
475481
fr1: RegionVid,
476482
fr2: RegionVid,
477-
) -> Span {
478-
let (_, span, _) = self.best_blame_constraint(mir, fr1, |r| r == fr2);
479-
span
483+
) -> (ConstraintCategory, Span) {
484+
let (category, span, _) = self.best_blame_constraint(mir, fr1, |r| r == fr2);
485+
(category, span)
486+
}
487+
488+
fn retrieve_closure_constraint_info(
489+
&self,
490+
mir: &Mir<'tcx>,
491+
constraint: &OutlivesConstraint
492+
) -> (ConstraintCategory, Span) {
493+
let loc = match constraint.locations {
494+
Locations::All(span) => return (constraint.category, span),
495+
Locations::Single(loc) => loc,
496+
};
497+
498+
let opt_span_category = self
499+
.closure_bounds_mapping[&loc]
500+
.get(&(constraint.sup, constraint.sub));
501+
*opt_span_category.unwrap_or(&(constraint.category, mir.source_info(loc).span))
480502
}
481503
}

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

+20-5
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ use rustc::mir::{
2525
use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
2626
use rustc::util::common;
2727
use rustc_data_structures::bit_set::BitSet;
28+
use rustc_data_structures::fx::FxHashMap;
2829
use rustc_data_structures::graph::scc::Sccs;
2930
use rustc_data_structures::indexed_vec::IndexVec;
3031
use rustc_errors::{Diagnostic, DiagnosticBuilder};
32+
use syntax_pos::Span;
3133

3234
use std::rc::Rc;
3335

@@ -60,10 +62,16 @@ pub struct RegionInferenceContext<'tcx> {
6062
/// the SCC (see `constraint_sccs`) and for error reporting.
6163
constraint_graph: Rc<NormalConstraintGraph>,
6264

63-
/// The SCC computed from `constraints` and the constraint graph. Used to compute the values
64-
/// of each region.
65+
/// The SCC computed from `constraints` and the constraint graph. Used to
66+
/// compute the values of each region.
6567
constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
6668

69+
/// Map closure bounds to a `Span` that should be used for error reporting.
70+
closure_bounds_mapping: FxHashMap<
71+
Location,
72+
FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
73+
>,
74+
6775
/// Contains the minimum universe of any variable within the same
6876
/// SCC. We will ensure that no SCC contains values that are not
6977
/// visible from this index.
@@ -187,6 +195,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
187195
universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
188196
_mir: &Mir<'tcx>,
189197
outlives_constraints: ConstraintSet,
198+
closure_bounds_mapping: FxHashMap<
199+
Location,
200+
FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
201+
>,
190202
type_tests: Vec<TypeTest<'tcx>>,
191203
liveness_constraints: LivenessValues<RegionVid>,
192204
elements: &Rc<RegionValueElements>,
@@ -220,6 +232,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
220232
constraints,
221233
constraint_graph,
222234
constraint_sccs,
235+
closure_bounds_mapping,
223236
scc_universes,
224237
scc_representatives,
225238
scc_values,
@@ -727,6 +740,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
727740
subject,
728741
outlived_free_region: non_local_ub,
729742
blame_span: locations.span(mir),
743+
category: ConstraintCategory::Boring,
730744
};
731745
debug!("try_promote_type_test: pushing {:#?}", requirement);
732746
propagated_outlives_requirements.push(requirement);
@@ -1125,7 +1139,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11251139
longer_fr, shorter_fr,
11261140
);
11271141

1128-
let blame_span = self.find_outlives_blame_span(mir, longer_fr, shorter_fr);
1142+
let blame_span_category = self.find_outlives_blame_span(mir, longer_fr, shorter_fr);
11291143

11301144
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
11311145
// Shrink `fr` until we find a non-local region (if we do).
@@ -1150,7 +1164,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11501164
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
11511165
subject: ClosureOutlivesSubject::Region(fr_minus),
11521166
outlived_free_region: shorter_fr_plus,
1153-
blame_span: blame_span,
1167+
blame_span: blame_span_category.1,
1168+
category: blame_span_category.0,
11541169
});
11551170
return;
11561171
}
@@ -1213,7 +1228,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
12131228
};
12141229

12151230
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
1216-
let span = self.find_outlives_blame_span(mir, longer_fr, error_region);
1231+
let (_, span) = self.find_outlives_blame_span(mir, longer_fr, error_region);
12171232

12181233
// Obviously, this error message is far from satisfactory.
12191234
// At present, though, it only appears in unit tests --

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+89-34
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,15 @@ use rustc::traits::query::type_op::custom::CustomTypeOp;
4242
use rustc::traits::query::{Fallible, NoSolution};
4343
use rustc::traits::{ObligationCause, PredicateObligations};
4444
use rustc::ty::fold::TypeFoldable;
45-
use rustc::ty::subst::Subst;
45+
use rustc::ty::subst::{Subst, UnpackedKind};
4646
use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
4747
use std::rc::Rc;
4848
use std::{fmt, iter};
4949
use syntax_pos::{Span, DUMMY_SP};
5050
use transform::{MirPass, MirSource};
5151

5252
use either::Either;
53-
use rustc_data_structures::fx::FxHashSet;
53+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
5454

5555
macro_rules! span_mirbug {
5656
($context:expr, $elem:expr, $($message:tt)*) => ({
@@ -128,6 +128,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
128128
let mut constraints = MirTypeckRegionConstraints {
129129
liveness_constraints: LivenessValues::new(elements),
130130
outlives_constraints: ConstraintSet::default(),
131+
closure_bounds_mapping: FxHashMap(),
131132
type_tests: Vec::default(),
132133
};
133134
let mut placeholder_indices = PlaceholderIndices::default();
@@ -752,6 +753,11 @@ crate struct MirTypeckRegionConstraints<'tcx> {
752753

753754
crate outlives_constraints: ConstraintSet,
754755

756+
crate closure_bounds_mapping: FxHashMap<
757+
Location,
758+
FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
759+
>,
760+
755761
crate type_tests: Vec<TypeTest<'tcx>>,
756762
}
757763

@@ -860,7 +866,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
860866
&mut self,
861867
locations: Locations,
862868
category: ConstraintCategory,
863-
op: impl type_op::TypeOp<'gcx, 'tcx, Output = R>,
869+
op: impl type_op::TypeOp<'gcx, 'tcx, Output=R>,
864870
) -> Fallible<R> {
865871
let (r, opt_data) = op.fully_perform(self.infcx)?;
866872

@@ -1103,17 +1109,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
11031109
let place_ty = place.ty(mir, tcx).to_ty(tcx);
11041110
let rv_ty = rv.ty(mir, tcx);
11051111
if let Err(terr) =
1106-
self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category)
1107-
{
1108-
span_mirbug!(
1112+
self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category)
1113+
{
1114+
span_mirbug!(
11091115
self,
11101116
stmt,
11111117
"bad assignment ({:?} = {:?}): {:?}",
11121118
place_ty,
11131119
rv_ty,
11141120
terr
11151121
);
1116-
}
1122+
}
11171123

11181124
if let Some(user_ty) = self.rvalue_user_ty(rv) {
11191125
if let Err(terr) = self.relate_type_and_user_type(
@@ -1233,17 +1239,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
12331239

12341240
let locations = term_location.to_locations();
12351241
if let Err(terr) =
1236-
self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
1237-
{
1238-
span_mirbug!(
1242+
self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
1243+
{
1244+
span_mirbug!(
12391245
self,
12401246
term,
12411247
"bad DropAndReplace ({:?} = {:?}): {:?}",
12421248
place_ty,
12431249
rv_ty,
12441250
terr
12451251
);
1246-
}
1252+
}
12471253
}
12481254
TerminatorKind::SwitchInt {
12491255
ref discr,
@@ -1387,17 +1393,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
13871393
let locations = term_location.to_locations();
13881394

13891395
if let Err(terr) =
1390-
self.sub_types_or_anon(sig.output(), dest_ty, locations, category)
1391-
{
1392-
span_mirbug!(
1396+
self.sub_types_or_anon(sig.output(), dest_ty, locations, category)
1397+
{
1398+
span_mirbug!(
13931399
self,
13941400
term,
13951401
"call dest mismatch ({:?} <- {:?}): {:?}",
13961402
dest_ty,
13971403
sig.output(),
13981404
terr
13991405
);
1400-
}
1406+
}
14011407

14021408
// When `#![feature(unsized_locals)]` is not enabled,
14031409
// this check is done at `check_local`.
@@ -2038,7 +2044,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
20382044
aggregate_kind, location
20392045
);
20402046

2041-
let instantiated_predicates = match aggregate_kind {
2047+
let instantiated_predicates = match aggregate_kind {
20422048
AggregateKind::Adt(def, _, substs, _, _) => {
20432049
tcx.predicates_of(def.did).instantiate(tcx, substs)
20442050
}
@@ -2064,24 +2070,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
20642070
// these extra requirements are basically like where
20652071
// clauses on the struct.
20662072
AggregateKind::Closure(def_id, substs) => {
2067-
if let Some(closure_region_requirements) =
2068-
tcx.mir_borrowck(*def_id).closure_requirements
2069-
{
2070-
let closure_constraints = closure_region_requirements.apply_requirements(
2071-
self.infcx.tcx,
2072-
location,
2073-
*def_id,
2074-
*substs,
2075-
);
2076-
2077-
self.push_region_constraints(
2078-
location.to_locations(),
2079-
ConstraintCategory::ClosureBounds,
2080-
&closure_constraints,
2081-
);
2082-
}
2083-
2084-
tcx.predicates_of(*def_id).instantiate(tcx, substs.substs)
2073+
self.prove_closure_bounds(tcx, *def_id, *substs, location)
20852074
}
20862075

20872076
AggregateKind::Generator(def_id, substs, _) => {
@@ -2097,6 +2086,72 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
20972086
);
20982087
}
20992088

2089+
fn prove_closure_bounds(
2090+
&mut self,
2091+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
2092+
def_id: DefId,
2093+
substs: ty::ClosureSubsts<'tcx>,
2094+
location: Location,
2095+
) -> ty::InstantiatedPredicates<'tcx> {
2096+
if let Some(closure_region_requirements) =
2097+
tcx.mir_borrowck(def_id).closure_requirements
2098+
{
2099+
let closure_constraints = closure_region_requirements.apply_requirements(
2100+
tcx,
2101+
location,
2102+
def_id,
2103+
substs,
2104+
);
2105+
2106+
if let Some(ref mut borrowck_context) = self.borrowck_context {
2107+
let bounds_mapping = closure_constraints
2108+
.iter()
2109+
.enumerate()
2110+
.filter_map(|(idx, constraint)| {
2111+
let ty::OutlivesPredicate(k1, r2) =
2112+
constraint.no_late_bound_regions().unwrap_or_else(|| {
2113+
bug!(
2114+
"query_constraint {:?} contained bound regions",
2115+
constraint,
2116+
);
2117+
});
2118+
2119+
match k1.unpack() {
2120+
UnpackedKind::Lifetime(r1) => {
2121+
// constraint is r1: r2
2122+
let r1_vid = borrowck_context.universal_regions.to_region_vid(r1);
2123+
let r2_vid = borrowck_context.universal_regions.to_region_vid(r2);
2124+
let outlives_requirements = &closure_region_requirements
2125+
.outlives_requirements[idx];
2126+
Some((
2127+
(r1_vid, r2_vid),
2128+
(
2129+
outlives_requirements.category,
2130+
outlives_requirements.blame_span,
2131+
),
2132+
))
2133+
}
2134+
UnpackedKind::Type(_) => None,
2135+
}
2136+
})
2137+
.collect();
2138+
2139+
let existing = borrowck_context.constraints
2140+
.closure_bounds_mapping
2141+
.insert(location, bounds_mapping);
2142+
assert!(existing.is_none(), "Multiple closures at the same location.");
2143+
}
2144+
2145+
self.push_region_constraints(
2146+
location.to_locations(),
2147+
ConstraintCategory::ClosureBounds,
2148+
&closure_constraints,
2149+
);
2150+
}
2151+
2152+
tcx.predicates_of(def_id).instantiate(tcx, substs.substs)
2153+
}
2154+
21002155
fn prove_trait_ref(
21012156
&mut self,
21022157
trait_ref: ty::TraitRef<'tcx>,

0 commit comments

Comments
 (0)