|
1 | 1 | //! This query borrow-checks the MIR to (further) ensure it is not broken.
|
2 | 2 |
|
3 |
| -use rustc::hir::def_id::DefId; |
4 |
| -use rustc::hir::Node; |
5 |
| -use rustc::hir::{self, HirId}; |
6 |
| -use rustc::infer::InferCtxt; |
| 3 | +use rustc::hir::{self, def_id::DefId, HirId, Node}; |
| 4 | +use rustc::infer::{opaque_types, InferCtxt}; |
7 | 5 | use rustc::lint::builtin::MUTABLE_BORROW_RESERVATION_CONFLICT;
|
8 | 6 | use rustc::lint::builtin::UNUSED_MUT;
|
9 | 7 | use rustc::mir::{
|
@@ -39,8 +37,11 @@ use crate::dataflow::FlowAtLocation;
|
39 | 37 | use crate::dataflow::MoveDataParamEnv;
|
40 | 38 | use crate::dataflow::{do_dataflow, DebugFormatted};
|
41 | 39 | use crate::dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
|
| 40 | +use crate::transform::MirSource; |
42 | 41 |
|
43 |
| -use self::diagnostics::AccessKind; |
| 42 | +use self::diagnostics::{ |
| 43 | + AccessKind, OutlivesSuggestionBuilder, RegionErrorKind, RegionErrorNamingCtx, RegionErrors, |
| 44 | +}; |
44 | 45 | use self::flows::Flows;
|
45 | 46 | use self::location::LocationTable;
|
46 | 47 | use self::prefixes::PrefixSet;
|
@@ -202,22 +203,28 @@ fn do_mir_borrowck<'a, 'tcx>(
|
202 | 203 | let borrow_set =
|
203 | 204 | Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));
|
204 | 205 |
|
205 |
| - // If we are in non-lexical mode, compute the non-lexical lifetimes. |
206 |
| - let (regioncx, polonius_output, opt_closure_req) = nll::compute_regions( |
207 |
| - infcx, |
208 |
| - def_id, |
209 |
| - free_regions, |
210 |
| - body, |
211 |
| - &promoted, |
212 |
| - &local_names, |
213 |
| - &upvars, |
214 |
| - location_table, |
215 |
| - param_env, |
216 |
| - &mut flow_inits, |
217 |
| - &mdpe.move_data, |
218 |
| - &borrow_set, |
219 |
| - &mut errors_buffer, |
220 |
| - ); |
| 206 | + // Compute non-lexical lifetimes. |
| 207 | + let nll::NllOutput { regioncx, polonius_output, opt_closure_req, nll_errors } = |
| 208 | + nll::compute_regions( |
| 209 | + infcx, |
| 210 | + def_id, |
| 211 | + free_regions, |
| 212 | + body, |
| 213 | + &promoted, |
| 214 | + location_table, |
| 215 | + param_env, |
| 216 | + &mut flow_inits, |
| 217 | + &mdpe.move_data, |
| 218 | + &borrow_set, |
| 219 | + ); |
| 220 | + |
| 221 | + // Dump MIR results into a file, if that is enabled. This let us |
| 222 | + // write unit-tests, as well as helping with debugging. |
| 223 | + nll::dump_mir_results(infcx, MirSource::item(def_id), &body, ®ioncx, &opt_closure_req); |
| 224 | + |
| 225 | + // We also have a `#[rustc_nll]` annotation that causes us to dump |
| 226 | + // information. |
| 227 | + nll::dump_annotation(infcx, &body, def_id, ®ioncx, &opt_closure_req, &mut errors_buffer); |
221 | 228 |
|
222 | 229 | // The various `flow_*` structures can be large. We drop `flow_inits` here
|
223 | 230 | // so it doesn't overlap with the others below. This reduces peak memory
|
@@ -288,6 +295,9 @@ fn do_mir_borrowck<'a, 'tcx>(
|
288 | 295 | local_names,
|
289 | 296 | };
|
290 | 297 |
|
| 298 | + // Compute and report region errors, if any. |
| 299 | + mbcx.report_region_errors(nll_errors); |
| 300 | + |
291 | 301 | let mut state = Flows::new(flow_borrows, flow_uninits, flow_ever_inits, polonius_output);
|
292 | 302 |
|
293 | 303 | if let Some(errors) = move_errors {
|
@@ -1464,6 +1474,131 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
1464 | 1474 | // initial reservation.
|
1465 | 1475 | }
|
1466 | 1476 | }
|
| 1477 | + |
| 1478 | + /// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`. |
| 1479 | + fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) { |
| 1480 | + // Iterate through all the errors, producing a diagnostic for each one. The diagnostics are |
| 1481 | + // buffered in the `MirBorrowckCtxt`. |
| 1482 | + |
| 1483 | + // FIXME(mark-i-m): Would be great to get rid of the naming context. |
| 1484 | + let mut region_naming = RegionErrorNamingCtx::new(); |
| 1485 | + let mut outlives_suggestion = |
| 1486 | + OutlivesSuggestionBuilder::new(self.mir_def_id, &self.local_names); |
| 1487 | + |
| 1488 | + for nll_error in nll_errors.into_iter() { |
| 1489 | + match nll_error { |
| 1490 | + RegionErrorKind::TypeTestDoesNotLiveLongEnough { span, generic } => { |
| 1491 | + // FIXME. We should handle this case better. It |
| 1492 | + // indicates that we have e.g., some region variable |
| 1493 | + // whose value is like `'a+'b` where `'a` and `'b` are |
| 1494 | + // distinct unrelated univesal regions that are not |
| 1495 | + // known to outlive one another. It'd be nice to have |
| 1496 | + // some examples where this arises to decide how best |
| 1497 | + // to report it; we could probably handle it by |
| 1498 | + // iterating over the universal regions and reporting |
| 1499 | + // an error that multiple bounds are required. |
| 1500 | + self.infcx |
| 1501 | + .tcx |
| 1502 | + .sess |
| 1503 | + .struct_span_err(span, &format!("`{}` does not live long enough", generic)) |
| 1504 | + .buffer(&mut self.errors_buffer); |
| 1505 | + } |
| 1506 | + |
| 1507 | + RegionErrorKind::TypeTestGenericBoundError { |
| 1508 | + span, |
| 1509 | + generic, |
| 1510 | + lower_bound_region, |
| 1511 | + } => { |
| 1512 | + let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id); |
| 1513 | + self.infcx |
| 1514 | + .construct_generic_bound_failure( |
| 1515 | + region_scope_tree, |
| 1516 | + span, |
| 1517 | + None, |
| 1518 | + generic, |
| 1519 | + lower_bound_region, |
| 1520 | + ) |
| 1521 | + .buffer(&mut self.errors_buffer); |
| 1522 | + } |
| 1523 | + |
| 1524 | + RegionErrorKind::UnexpectedHiddenRegion { |
| 1525 | + opaque_type_def_id, |
| 1526 | + hidden_ty, |
| 1527 | + member_region, |
| 1528 | + } => { |
| 1529 | + let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id); |
| 1530 | + opaque_types::unexpected_hidden_region_diagnostic( |
| 1531 | + self.infcx.tcx, |
| 1532 | + Some(region_scope_tree), |
| 1533 | + opaque_type_def_id, |
| 1534 | + hidden_ty, |
| 1535 | + member_region, |
| 1536 | + ) |
| 1537 | + .buffer(&mut self.errors_buffer); |
| 1538 | + } |
| 1539 | + |
| 1540 | + RegionErrorKind::BoundUniversalRegionError { |
| 1541 | + longer_fr, |
| 1542 | + fr_origin, |
| 1543 | + error_region, |
| 1544 | + } => { |
| 1545 | + // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. |
| 1546 | + let (_, span) = self.nonlexical_regioncx.find_outlives_blame_span( |
| 1547 | + &self.body, |
| 1548 | + longer_fr, |
| 1549 | + fr_origin, |
| 1550 | + error_region, |
| 1551 | + ); |
| 1552 | + |
| 1553 | + // FIXME: improve this error message |
| 1554 | + self.infcx |
| 1555 | + .tcx |
| 1556 | + .sess |
| 1557 | + .struct_span_err(span, "higher-ranked subtype error") |
| 1558 | + .buffer(&mut self.errors_buffer); |
| 1559 | + } |
| 1560 | + |
| 1561 | + RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => { |
| 1562 | + if is_reported { |
| 1563 | + let db = self.nonlexical_regioncx.report_error( |
| 1564 | + &self.body, |
| 1565 | + &self.local_names, |
| 1566 | + &self.upvars, |
| 1567 | + self.infcx, |
| 1568 | + self.mir_def_id, |
| 1569 | + longer_fr, |
| 1570 | + fr_origin, |
| 1571 | + shorter_fr, |
| 1572 | + &mut outlives_suggestion, |
| 1573 | + &mut region_naming, |
| 1574 | + ); |
| 1575 | + |
| 1576 | + db.buffer(&mut self.errors_buffer); |
| 1577 | + } else { |
| 1578 | + // We only report the first error, so as not to overwhelm the user. See |
| 1579 | + // `RegRegionErrorKind` docs. |
| 1580 | + // |
| 1581 | + // FIXME: currently we do nothing with these, but perhaps we can do better? |
| 1582 | + // FIXME: try collecting these constraints on the outlives suggestion |
| 1583 | + // builder. Does it make the suggestions any better? |
| 1584 | + debug!( |
| 1585 | + "Unreported region error: can't prove that {:?}: {:?}", |
| 1586 | + longer_fr, shorter_fr |
| 1587 | + ); |
| 1588 | + } |
| 1589 | + } |
| 1590 | + } |
| 1591 | + } |
| 1592 | + |
| 1593 | + // Emit one outlives suggestions for each MIR def we borrowck |
| 1594 | + outlives_suggestion.add_suggestion( |
| 1595 | + &self.body, |
| 1596 | + &self.nonlexical_regioncx, |
| 1597 | + self.infcx, |
| 1598 | + &mut self.errors_buffer, |
| 1599 | + &mut region_naming, |
| 1600 | + ); |
| 1601 | + } |
1467 | 1602 | }
|
1468 | 1603 |
|
1469 | 1604 | impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|
0 commit comments