Skip to content

Commit 607243b

Browse files
committed
Auto merge of #54798 - matthewjasper:free-region-closure-errors, r=nikomatsakis
[NLL] Improve closure region bound errors Previously, we would report free region errors that originate from closure with the span of the closure and a "closure body requires ..." message. This is now updated to use a reason and span from inside the closure.
2 parents b1a137d + 8258107 commit 607243b

26 files changed

+300
-210
lines changed

src/librustc/ich/impls_mir.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,23 @@ impl_stable_hash_for!(struct mir::ClosureRegionRequirements<'tcx> {
551551
impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement<'tcx> {
552552
subject,
553553
outlived_free_region,
554-
blame_span
554+
blame_span,
555+
category
556+
});
557+
558+
impl_stable_hash_for!(enum mir::ConstraintCategory {
559+
Return,
560+
TypeAnnotation,
561+
Cast,
562+
ClosureBounds,
563+
CallArgument,
564+
CopyBound,
565+
SizedBound,
566+
Assignment,
567+
OpaqueType,
568+
Boring,
569+
BoringNoLocation,
570+
Internal,
555571
});
556572

557573
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::ClosureOutlivesSubject<'gcx> {

src/librustc/mir/mod.rs

+42-2
Original file line numberDiff line numberDiff line change
@@ -2676,11 +2676,51 @@ pub struct ClosureOutlivesRequirement<'tcx> {
26762676
// This region or type ...
26772677
pub subject: ClosureOutlivesSubject<'tcx>,
26782678

2679-
// .. must outlive this one.
2679+
// ... must outlive this one.
26802680
pub outlived_free_region: ty::RegionVid,
26812681

2682-
// If not, report an error here.
2682+
// If not, report an error here ...
26832683
pub blame_span: Span,
2684+
2685+
// ... due to this reason.
2686+
pub category: ConstraintCategory,
2687+
}
2688+
2689+
/// Outlives constraints can be categorized to determine whether and why they
2690+
/// are interesting (for error reporting). Order of variants indicates sort
2691+
/// order of the category, thereby influencing diagnostic output.
2692+
///
2693+
/// See also [rustc_mir::borrow_check::nll::constraints]
2694+
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
2695+
pub enum ConstraintCategory {
2696+
Return,
2697+
TypeAnnotation,
2698+
Cast,
2699+
2700+
/// A constraint that came from checking the body of a closure.
2701+
///
2702+
/// We try to get the category that the closure used when reporting this.
2703+
ClosureBounds,
2704+
CallArgument,
2705+
CopyBound,
2706+
SizedBound,
2707+
Assignment,
2708+
OpaqueType,
2709+
2710+
/// A "boring" constraint (caused by the given location) is one that
2711+
/// the user probably doesn't want to see described in diagnostics,
2712+
/// because it is kind of an artifact of the type system setup.
2713+
/// Example: `x = Foo { field: y }` technically creates
2714+
/// intermediate regions representing the "type of `Foo { field: y
2715+
/// }`", and data flows from `y` into those variables, but they
2716+
/// are not very interesting. The assignment into `x` on the other
2717+
/// hand might be.
2718+
Boring,
2719+
// Boring and applicable everywhere.
2720+
BoringNoLocation,
2721+
2722+
/// A constraint that doesn't correspond to anything the user sees.
2723+
Internal,
26842724
}
26852725

26862726
/// The subject of a ClosureOutlivesRequirement -- that is, the thing

src/librustc_mir/borrow_check/nll/constraints/graph.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
// except according to those terms.
1010

1111
use borrow_check::nll::type_check::Locations;
12-
use borrow_check::nll::constraints::{ConstraintCategory, ConstraintIndex};
12+
use borrow_check::nll::constraints::ConstraintIndex;
1313
use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
14+
use rustc::mir::ConstraintCategory;
1415
use rustc::ty::RegionVid;
1516
use rustc_data_structures::graph;
1617
use rustc_data_structures::indexed_vec::IndexVec;

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

+1-36
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use rustc::mir::ConstraintCategory;
1112
use rustc::ty::RegionVid;
1213
use rustc_data_structures::graph::scc::Sccs;
1314
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
@@ -23,42 +24,6 @@ crate struct ConstraintSet {
2324
constraints: IndexVec<ConstraintIndex, OutlivesConstraint>,
2425
}
2526

26-
/// Constraints can be categorized to determine whether and why they are
27-
/// interesting. Order of variants indicates sort order of the category,
28-
/// thereby influencing diagnostic output.
29-
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
30-
pub enum ConstraintCategory {
31-
Return,
32-
TypeAnnotation,
33-
Cast,
34-
CallArgument,
35-
36-
/// A constraint that came from checking the body of a closure.
37-
///
38-
/// Ideally we would give an explanation that points to the relevant part
39-
/// of the closure's body.
40-
ClosureBounds,
41-
CopyBound,
42-
SizedBound,
43-
Assignment,
44-
OpaqueType,
45-
46-
/// A "boring" constraint (caused by the given location) is one that
47-
/// the user probably doesn't want to see described in diagnostics,
48-
/// because it is kind of an artifact of the type system setup.
49-
/// Example: `x = Foo { field: y }` technically creates
50-
/// intermediate regions representing the "type of `Foo { field: y
51-
/// }`", and data flows from `y` into those variables, but they
52-
/// are not very interesting. The assignment into `x` on the other
53-
/// hand might be.
54-
Boring,
55-
// Boring and applicable everywhere.
56-
BoringNoLocation,
57-
58-
/// A constraint that doesn't correspond to anything the user sees.
59-
Internal,
60-
}
61-
6227
impl ConstraintSet {
6328
crate fn push(&mut self, constraint: OutlivesConstraint) {
6429
debug!(

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

+46-20
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use borrow_check::nll::constraints::{OutlivesConstraint, ConstraintCategory};
11+
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;
16-
use rustc::mir::{Location, Mir};
17+
use rustc::mir::{ConstraintCategory, Location, Mir};
1718
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;
@@ -28,22 +28,26 @@ mod var_name;
2828

2929
use self::region_name::RegionName;
3030

31-
impl fmt::Display for ConstraintCategory {
32-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31+
trait ConstraintDescription {
32+
fn description(&self) -> &'static str;
33+
}
34+
35+
impl ConstraintDescription for ConstraintCategory {
36+
fn description(&self) -> &'static str {
3337
// Must end with a space. Allows for empty names to be provided.
3438
match self {
35-
ConstraintCategory::Assignment => write!(f, "assignment "),
36-
ConstraintCategory::Return => write!(f, "returning this value "),
37-
ConstraintCategory::Cast => write!(f, "cast "),
38-
ConstraintCategory::CallArgument => write!(f, "argument "),
39-
ConstraintCategory::TypeAnnotation => write!(f, "type annotation "),
40-
ConstraintCategory::ClosureBounds => write!(f, "closure body "),
41-
ConstraintCategory::SizedBound => write!(f, "proving this value is `Sized` "),
42-
ConstraintCategory::CopyBound => write!(f, "copying this value "),
43-
ConstraintCategory::OpaqueType => write!(f, "opaque type "),
39+
ConstraintCategory::Assignment => "assignment ",
40+
ConstraintCategory::Return => "returning this value ",
41+
ConstraintCategory::Cast => "cast ",
42+
ConstraintCategory::CallArgument => "argument ",
43+
ConstraintCategory::TypeAnnotation => "type annotation ",
44+
ConstraintCategory::ClosureBounds => "closure body ",
45+
ConstraintCategory::SizedBound => "proving this value is `Sized` ",
46+
ConstraintCategory::CopyBound => "copying this value ",
47+
ConstraintCategory::OpaqueType => "opaque type ",
4448
ConstraintCategory::Boring
4549
| ConstraintCategory::BoringNoLocation
46-
| ConstraintCategory::Internal => write!(f, ""),
50+
| ConstraintCategory::Internal => "",
4751
}
4852
}
4953
}
@@ -89,7 +93,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
8993
// Classify each of the constraints along the path.
9094
let mut categorized_path: Vec<(ConstraintCategory, Span)> = path
9195
.iter()
92-
.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+
})
93103
.collect();
94104
debug!(
95105
"best_blame_constraint: categorized_path={:#?}",
@@ -358,7 +368,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
358368
_ => {
359369
diag.span_label(span, format!(
360370
"{}requires that `{}` must outlive `{}`",
361-
category, fr_name, outlived_fr_name,
371+
category.description(), fr_name, outlived_fr_name,
362372
));
363373
},
364374
}
@@ -470,8 +480,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
470480
mir: &Mir<'tcx>,
471481
fr1: RegionVid,
472482
fr2: RegionVid,
473-
) -> Span {
474-
let (_, span, _) = self.best_blame_constraint(mir, fr1, |r| r == fr2);
475-
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))
476502
}
477503
}

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

+22-7
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,17 @@ use rustc::infer::canonical::QueryRegionConstraint;
1919
use rustc::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
2020
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin};
2121
use rustc::mir::{
22-
ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location,
23-
Mir,
22+
ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
23+
ConstraintCategory, Local, Location, Mir,
2424
};
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/constraint_conversion.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use borrow_check::nll::constraints::{ConstraintCategory, ConstraintSet, OutlivesConstraint};
11+
use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
1212
use borrow_check::nll::region_infer::TypeTest;
1313
use borrow_check::nll::type_check::Locations;
1414
use borrow_check::nll::universal_regions::UniversalRegions;
@@ -17,6 +17,7 @@ use rustc::infer::outlives::env::RegionBoundPairs;
1717
use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
1818
use rustc::infer::region_constraints::{GenericKind, VerifyBound};
1919
use rustc::infer::{self, SubregionOrigin};
20+
use rustc::mir::ConstraintCategory;
2021
use rustc::ty::subst::UnpackedKind;
2122
use rustc::ty::{self, TyCtxt};
2223
use syntax_pos::DUMMY_SP;

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ use borrow_check::nll::type_check::constraint_conversion;
1212
use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
1313
use borrow_check::nll::universal_regions::UniversalRegions;
1414
use borrow_check::nll::ToRegionVid;
15-
use borrow_check::nll::constraints::ConstraintCategory;
1615
use rustc::infer::canonical::QueryRegionConstraint;
1716
use rustc::infer::outlives::free_region_map::FreeRegionRelations;
1817
use rustc::infer::region_constraints::GenericKind;
1918
use rustc::infer::InferCtxt;
19+
use rustc::mir::ConstraintCategory;
2020
use rustc::traits::query::outlives_bounds::{self, OutlivesBound};
2121
use rustc::traits::query::type_op::{self, TypeOp};
2222
use rustc::ty::{self, RegionVid, Ty};

0 commit comments

Comments
 (0)