|  | 
| 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