Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

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

Lines changed: 5 additions & 2 deletions
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

Lines changed: 2 additions & 0 deletions
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

Lines changed: 27 additions & 5 deletions
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

Lines changed: 20 additions & 5 deletions
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

Lines changed: 89 additions & 34 deletions
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)