|
3 | 3 | use rustc::hir::{self, HirId};
|
4 | 4 | use rustc::hir::Node;
|
5 | 5 | use rustc::hir::def_id::DefId;
|
6 |
| -use rustc::infer::InferCtxt; |
| 6 | +use rustc::infer::{opaque_types, InferCtxt}; |
7 | 7 | use rustc::lint::builtin::UNUSED_MUT;
|
8 | 8 | use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT};
|
9 | 9 | use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
|
@@ -39,12 +39,15 @@ use crate::dataflow::MoveDataParamEnv;
|
39 | 39 | use crate::dataflow::{do_dataflow, DebugFormatted};
|
40 | 40 | use crate::dataflow::EverInitializedPlaces;
|
41 | 41 | use crate::dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
|
| 42 | +use crate::transform::MirSource; |
42 | 43 |
|
43 | 44 | use self::flows::Flows;
|
44 | 45 | use self::location::LocationTable;
|
45 | 46 | use self::prefixes::PrefixSet;
|
46 | 47 | use self::MutateMode::{JustWrite, WriteAndRead};
|
47 |
| -use self::diagnostics::AccessKind; |
| 48 | +use self::diagnostics::{ |
| 49 | + AccessKind, RegionErrors, RegionErrorKind, OutlivesSuggestionBuilder, RegionErrorNamingCtx, |
| 50 | +}; |
48 | 51 |
|
49 | 52 | use self::path_utils::*;
|
50 | 53 |
|
@@ -211,20 +214,40 @@ fn do_mir_borrowck<'a, 'tcx>(
|
211 | 214 | let borrow_set = Rc::new(BorrowSet::build(
|
212 | 215 | tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));
|
213 | 216 |
|
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( |
216 | 221 | infcx,
|
217 | 222 | def_id,
|
218 | 223 | free_regions,
|
219 | 224 | body,
|
220 | 225 | &promoted,
|
221 |
| - &local_names, |
222 |
| - &upvars, |
223 | 226 | location_table,
|
224 | 227 | param_env,
|
225 | 228 | &mut flow_inits,
|
226 | 229 | &mdpe.move_data,
|
227 | 230 | &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 | + ®ioncx, |
| 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 | + ®ioncx, |
| 250 | + &opt_closure_req, |
228 | 251 | &mut errors_buffer,
|
229 | 252 | );
|
230 | 253 |
|
@@ -297,6 +320,9 @@ fn do_mir_borrowck<'a, 'tcx>(
|
297 | 320 | local_names,
|
298 | 321 | };
|
299 | 322 |
|
| 323 | + // Compute and report region errors, if any. |
| 324 | + mbcx.report_region_errors(nll_errors); |
| 325 | + |
300 | 326 | let mut state = Flows::new(
|
301 | 327 | flow_borrows,
|
302 | 328 | flow_uninits,
|
@@ -1560,6 +1586,129 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
1560 | 1586 | // initial reservation.
|
1561 | 1587 | }
|
1562 | 1588 | }
|
| 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 | + // FIXME(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( |
| 1598 | + self.mir_def_id, &self.local_names |
| 1599 | + ); |
| 1600 | + |
| 1601 | + for nll_error in nll_errors.into_iter() { |
| 1602 | + match nll_error { |
| 1603 | + RegionErrorKind::TypeTestDoesNotLiveLongEnough { span, generic } => { |
| 1604 | + // FIXME. We should handle this case better. It |
| 1605 | + // indicates that we have e.g., some region variable |
| 1606 | + // whose value is like `'a+'b` where `'a` and `'b` are |
| 1607 | + // distinct unrelated univesal regions that are not |
| 1608 | + // known to outlive one another. It'd be nice to have |
| 1609 | + // some examples where this arises to decide how best |
| 1610 | + // to report it; we could probably handle it by |
| 1611 | + // iterating over the universal regions and reporting |
| 1612 | + // an error that multiple bounds are required. |
| 1613 | + self.infcx.tcx.sess |
| 1614 | + .struct_span_err( |
| 1615 | + span, |
| 1616 | + &format!("`{}` does not live long enough", generic), |
| 1617 | + ) |
| 1618 | + .buffer(&mut self.errors_buffer); |
| 1619 | + }, |
| 1620 | + |
| 1621 | + RegionErrorKind::TypeTestGenericBoundError { |
| 1622 | + span, generic, lower_bound_region |
| 1623 | + } => { |
| 1624 | + let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id); |
| 1625 | + self.infcx |
| 1626 | + .construct_generic_bound_failure( |
| 1627 | + region_scope_tree, |
| 1628 | + span, |
| 1629 | + None, |
| 1630 | + generic, |
| 1631 | + lower_bound_region, |
| 1632 | + ) |
| 1633 | + .buffer(&mut self.errors_buffer); |
| 1634 | + }, |
| 1635 | + |
| 1636 | + RegionErrorKind::UnexpectedHiddenRegion { |
| 1637 | + opaque_type_def_id, hidden_ty, member_region, |
| 1638 | + } => { |
| 1639 | + let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id); |
| 1640 | + opaque_types::unexpected_hidden_region_diagnostic( |
| 1641 | + self.infcx.tcx, |
| 1642 | + Some(region_scope_tree), |
| 1643 | + opaque_type_def_id, |
| 1644 | + hidden_ty, |
| 1645 | + member_region, |
| 1646 | + ) |
| 1647 | + .buffer(&mut self.errors_buffer); |
| 1648 | + } |
| 1649 | + |
| 1650 | + RegionErrorKind::BoundUniversalRegionError { |
| 1651 | + longer_fr, fr_origin, error_region, |
| 1652 | + } => { |
| 1653 | + // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. |
| 1654 | + let (_, span) = self.nonlexical_regioncx.find_outlives_blame_span( |
| 1655 | + &self.body, |
| 1656 | + longer_fr, |
| 1657 | + fr_origin, |
| 1658 | + error_region, |
| 1659 | + ); |
| 1660 | + |
| 1661 | + // FIXME: improve this error message |
| 1662 | + self.infcx |
| 1663 | + .tcx |
| 1664 | + .sess |
| 1665 | + .struct_span_err(span, "higher-ranked subtype error") |
| 1666 | + .buffer(&mut self.errors_buffer); |
| 1667 | + } |
| 1668 | + |
| 1669 | + RegionErrorKind::RegionError { |
| 1670 | + fr_origin, longer_fr, shorter_fr, is_reported, |
| 1671 | + } => { |
| 1672 | + if is_reported { |
| 1673 | + let db = self.nonlexical_regioncx.report_error( |
| 1674 | + &self.body, |
| 1675 | + &self.local_names, |
| 1676 | + &self.upvars, |
| 1677 | + self.infcx, |
| 1678 | + self.mir_def_id, |
| 1679 | + longer_fr, |
| 1680 | + fr_origin, |
| 1681 | + shorter_fr, |
| 1682 | + &mut outlives_suggestion, |
| 1683 | + &mut region_naming, |
| 1684 | + ); |
| 1685 | + |
| 1686 | + db.buffer(&mut self.errors_buffer); |
| 1687 | + } else { |
| 1688 | + // We only report the first error, so as not to overwhelm the user. See |
| 1689 | + // `RegRegionErrorKind` docs. |
| 1690 | + // |
| 1691 | + // FIXME: currently we do nothing with these, but perhaps we can do better? |
| 1692 | + // FIXME: try collecting these constraints on the outlives suggestion |
| 1693 | + // builder. Does it make the suggestions any better? |
| 1694 | + debug!( |
| 1695 | + "Unreported region error: can't prove that {:?}: {:?}", |
| 1696 | + longer_fr, shorter_fr |
| 1697 | + ); |
| 1698 | + } |
| 1699 | + } |
| 1700 | + } |
| 1701 | + } |
| 1702 | + |
| 1703 | + // Emit one outlives suggestions for each MIR def we borrowck |
| 1704 | + outlives_suggestion.add_suggestion( |
| 1705 | + &self.body, |
| 1706 | + &self.nonlexical_regioncx, |
| 1707 | + self.infcx, |
| 1708 | + &mut self.errors_buffer, |
| 1709 | + &mut region_naming |
| 1710 | + ); |
| 1711 | + } |
1563 | 1712 | }
|
1564 | 1713 |
|
1565 | 1714 | impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|
0 commit comments