Skip to content

Commit 43888e8

Browse files
committed
Refactor region error handling to be done by mirborrowckctx
1 parent 9ff30a7 commit 43888e8

File tree

5 files changed

+253
-201
lines changed

5 files changed

+253
-201
lines changed

src/librustc_mir/borrow_check/diagnostics/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ mod explain_borrow;
3232

3333
crate use mutability_errors::AccessKind;
3434
crate use region_name::{RegionName, RegionNameSource, RegionErrorNamingCtx};
35-
crate use region_errors::{ErrorReportingCtx, ErrorConstraintInfo};
35+
crate use region_errors::{ErrorReportingCtx, ErrorConstraintInfo, RegionErrors, RegionErrorKind};
3636
crate use outlives_suggestion::OutlivesSuggestionBuilder;
3737

3838
pub(super) struct IncludingDowncast(pub(super) bool);

src/librustc_mir/borrow_check/diagnostics/region_errors.rs

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
use rustc::hir::def_id::DefId;
44
use rustc::infer::{
55
error_reporting::nice_region_error::NiceRegionError,
6+
region_constraints::GenericKind,
67
InferCtxt, NLLRegionVariableOrigin,
78
};
89
use rustc::mir::{
910
ConstraintCategory, Local, Location, Body,
1011
};
11-
use rustc::ty::{self, RegionVid};
12+
use rustc::ty::{self, RegionVid, Ty};
1213
use rustc_index::vec::IndexVec;
1314
use rustc_errors::DiagnosticBuilder;
1415
use std::collections::VecDeque;
@@ -53,13 +54,61 @@ impl ConstraintDescription for ConstraintCategory {
5354
}
5455
}
5556

56-
#[derive(Copy, Clone, PartialEq, Eq)]
57+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
5758
enum Trace {
5859
StartRegion,
5960
FromOutlivesConstraint(OutlivesConstraint),
6061
NotVisited,
6162
}
6263

64+
/// A collection of errors encountered during region inference. This is needed to efficiently
65+
/// report errors after borrow checking.
66+
#[derive(Clone, Debug)]
67+
crate struct RegionErrors<'tcx> {
68+
errors: smallvec::SmallVec<[RegionErrorKind<'tcx>; 4]>,
69+
}
70+
71+
#[derive(Clone, Debug)]
72+
crate enum RegionErrorKind<'tcx> {
73+
/// An error for a type test: `T: 'a` does not live long enough
74+
TypeTestDoesNotLiveLongEnough {
75+
/// The span of the type test
76+
span: Span,
77+
/// The generic type of the type test
78+
generic: GenericKind<'tcx>,
79+
},
80+
81+
/// A generic bound failure for a type test
82+
TypeTestGenericBoundError {
83+
/// The span of the type test
84+
span: Span,
85+
/// The generic type of the type test
86+
generic: GenericKind<'tcx>,
87+
/// The lower bound region
88+
lower_bound_region: ty::Region<'tcx>,
89+
},
90+
91+
/// An unexpected hidden region for an opaque type
92+
UnexpectedHiddenRegion {
93+
/// The def id of the opaque type
94+
opaque_type_def_id: DefId,
95+
/// The hidden type
96+
hidden_ty: Ty<'tcx>,
97+
/// The unexpected region
98+
member_region: ty::Region<'tcx>,
99+
},
100+
101+
/// Any other lifetime error
102+
RegionError {
103+
/// The origin of the region
104+
fr_origin: NLLRegionVariableOrigin,
105+
/// The region that should outlive `shorter_fr`
106+
longer_fr: RegionVid,
107+
/// The region that should be shorter, but we can't prove it
108+
shorter_fr: RegionVid,
109+
},
110+
}
111+
63112
/// Various pieces of state used when reporting borrow checker errors.
64113
pub struct ErrorReportingCtx<'a, 'b, 'tcx> {
65114
/// The region inference context used for borrow chekcing this MIR body.
@@ -95,6 +144,22 @@ pub struct ErrorConstraintInfo {
95144
pub(super) span: Span,
96145
}
97146

147+
impl<'tcx> RegionErrors<'tcx> {
148+
pub fn new() -> Self {
149+
RegionErrors {
150+
errors: smallvec::SmallVec::new(),
151+
}
152+
}
153+
154+
pub fn push(&mut self, error: RegionErrorKind<'tcx>) {
155+
self.errors.push(error)
156+
}
157+
158+
pub fn into_iter(self) -> impl Iterator<Item=RegionErrorKind<'tcx>> {
159+
self.errors.into_iter()
160+
}
161+
}
162+
98163
impl<'tcx> RegionInferenceContext<'tcx> {
99164
/// Converts a region inference variable into a `ty::Region` that
100165
/// we can use for error reporting. If `r` is universally bound,

src/librustc_mir/borrow_check/mod.rs

Lines changed: 115 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use rustc::hir::{self, HirId};
44
use rustc::hir::Node;
55
use rustc::hir::def_id::DefId;
6-
use rustc::infer::InferCtxt;
6+
use rustc::infer::{opaque_types, InferCtxt};
77
use rustc::lint::builtin::UNUSED_MUT;
88
use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT};
99
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
@@ -39,12 +39,15 @@ use crate::dataflow::MoveDataParamEnv;
3939
use crate::dataflow::{do_dataflow, DebugFormatted};
4040
use crate::dataflow::EverInitializedPlaces;
4141
use crate::dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
42+
use crate::transform::MirSource;
4243

4344
use self::flows::Flows;
4445
use self::location::LocationTable;
4546
use self::prefixes::PrefixSet;
4647
use self::MutateMode::{JustWrite, WriteAndRead};
47-
use self::diagnostics::AccessKind;
48+
use self::diagnostics::{
49+
AccessKind, RegionErrors, RegionErrorKind, OutlivesSuggestionBuilder, RegionErrorNamingCtx,
50+
};
4851

4952
use self::path_utils::*;
5053

@@ -211,20 +214,40 @@ fn do_mir_borrowck<'a, 'tcx>(
211214
let borrow_set = Rc::new(BorrowSet::build(
212215
tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));
213216

214-
// If we are in non-lexical mode, compute the non-lexical lifetimes.
215-
let (regioncx, polonius_output, opt_closure_req) = nll::compute_regions(
217+
// Compute non-lexical lifetimes.
218+
let nll::NllOutput {
219+
regioncx, polonius_output, opt_closure_req, nll_errors
220+
} = nll::compute_regions(
216221
infcx,
217222
def_id,
218223
free_regions,
219224
body,
220225
&promoted,
221-
&local_names,
222-
&upvars,
223226
location_table,
224227
param_env,
225228
&mut flow_inits,
226229
&mdpe.move_data,
227230
&borrow_set,
231+
);
232+
233+
// Dump MIR results into a file, if that is enabled. This let us
234+
// write unit-tests, as well as helping with debugging.
235+
nll::dump_mir_results(
236+
infcx,
237+
MirSource::item(def_id),
238+
&body,
239+
&regioncx,
240+
&opt_closure_req,
241+
);
242+
243+
// We also have a `#[rustc_nll]` annotation that causes us to dump
244+
// information.
245+
nll::dump_annotation(
246+
infcx,
247+
&body,
248+
def_id,
249+
&regioncx,
250+
&opt_closure_req,
228251
&mut errors_buffer,
229252
);
230253

@@ -297,6 +320,9 @@ fn do_mir_borrowck<'a, 'tcx>(
297320
local_names,
298321
};
299322

323+
// Compute and report region errors, if any.
324+
mbcx.report_region_errors(nll_errors);
325+
300326
let mut state = Flows::new(
301327
flow_borrows,
302328
flow_uninits,
@@ -1560,6 +1586,89 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15601586
// initial reservation.
15611587
}
15621588
}
1589+
1590+
/// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`.
1591+
fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
1592+
// Iterate through all the errors, producing a diagnostic for each one. The diagnostics are
1593+
// buffered in the `MirBorrowckCtxt`.
1594+
1595+
// TODO(mark-i-m): Would be great to get rid of the naming context.
1596+
let mut region_naming = RegionErrorNamingCtx::new();
1597+
let mut outlives_suggestion = OutlivesSuggestionBuilder::new(self.mir_def_id, &self.local_names);
1598+
1599+
for nll_error in nll_errors.into_iter() {
1600+
match nll_error {
1601+
RegionErrorKind::TypeTestDoesNotLiveLongEnough { span, generic } => {
1602+
// FIXME. We should handle this case better. It
1603+
// indicates that we have e.g., some region variable
1604+
// whose value is like `'a+'b` where `'a` and `'b` are
1605+
// distinct unrelated univesal regions that are not
1606+
// known to outlive one another. It'd be nice to have
1607+
// some examples where this arises to decide how best
1608+
// to report it; we could probably handle it by
1609+
// iterating over the universal regions and reporting
1610+
// an error that multiple bounds are required.
1611+
self.infcx.tcx.sess
1612+
.struct_span_err(
1613+
span,
1614+
&format!("`{}` does not live long enough", generic),
1615+
)
1616+
.buffer(&mut self.errors_buffer);
1617+
},
1618+
1619+
RegionErrorKind::TypeTestGenericBoundError {
1620+
span, generic, lower_bound_region
1621+
} => {
1622+
let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id);
1623+
self.infcx
1624+
.construct_generic_bound_failure(
1625+
region_scope_tree,
1626+
span,
1627+
None,
1628+
generic,
1629+
lower_bound_region,
1630+
)
1631+
.buffer(&mut self.errors_buffer);
1632+
},
1633+
1634+
RegionErrorKind::UnexpectedHiddenRegion {
1635+
opaque_type_def_id, hidden_ty, member_region,
1636+
} => {
1637+
let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id);
1638+
opaque_types::unexpected_hidden_region_diagnostic(
1639+
self.infcx.tcx,
1640+
Some(region_scope_tree),
1641+
opaque_type_def_id,
1642+
hidden_ty,
1643+
member_region,
1644+
)
1645+
.buffer(&mut self.errors_buffer);
1646+
}
1647+
1648+
RegionErrorKind::RegionError {
1649+
fr_origin, longer_fr, shorter_fr,
1650+
} => {
1651+
let db = self.nonlexical_regioncx.report_error(
1652+
&self.body,
1653+
&self.local_names,
1654+
&self.upvars,
1655+
self.infcx,
1656+
self.mir_def_id,
1657+
longer_fr,
1658+
fr_origin,
1659+
shorter_fr,
1660+
&mut outlives_suggestion,
1661+
&mut region_naming,
1662+
);
1663+
1664+
db.buffer(&mut self.errors_buffer);
1665+
1666+
// Emit outlives suggestions
1667+
//outlives_suggestion.add_suggestion(body, self, infcx, errors_buffer, region_naming);
1668+
}
1669+
}
1670+
}
1671+
}
15631672
}
15641673

15651674
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {

0 commit comments

Comments
 (0)