1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Error Reporting for Anonymous Region Lifetime Errors
//! where both the regions are anonymous.

use infer::error_reporting::nice_region_error::NiceRegionError;
use infer::SubregionOrigin;
use ty::RegionKind;
use hir::{Expr, ExprKind::Closure};
use hir::map::NodeExpr;
use util::common::ErrorReported;
use infer::lexical_region_resolve::RegionResolutionError::SubSupConflict;

impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
    /// Print the error message for lifetime errors when binding excapes a closure.
    ///
    /// Consider a case where we have
    ///
    /// ```no_run
    /// fn with_int<F>(f: F) where F: FnOnce(&isize) {
    ///     let x = 3;
    ///     f(&x);
    /// }
    /// fn main() {
    ///     let mut x = None;
    ///     with_int(|y| x = Some(y));
    /// }
    /// ```
    ///
    /// the output will be
    ///
    /// ```text
    ///     let mut x = None;
    ///         ----- borrowed data cannot be stored into here...
    ///     with_int(|y| x = Some(y));
    ///              ---          ^ cannot be stored outside of its closure
    ///              |
    ///              ...because it cannot outlive this closure
    /// ```
    pub(super) fn try_report_outlives_closure(&self) -> Option<ErrorReported> {
        if let Some(SubSupConflict(origin,
                                   ref sub_origin,
                                   _,
                                   ref sup_origin,
                                   sup_region)) = self.error {

            // #45983: when trying to assign the contents of an argument to a binding outside of a
            // closure, provide a specific message pointing this out.
            if let (&SubregionOrigin::BindingTypeIsNotValidAtDecl(ref external_span),
                    &RegionKind::ReFree(ref free_region)) = (&sub_origin, sup_region) {
                let hir = &self.tcx.hir;
                if let Some(node_id) = hir.as_local_node_id(free_region.scope) {
                    match hir.get(node_id) {
                        NodeExpr(Expr {
                            node: Closure(_, _, _, closure_span, None),
                            ..
                        }) => {
                            let sup_sp = sup_origin.span();
                            let origin_sp = origin.span();
                            let mut err = self.tcx.sess.struct_span_err(
                                sup_sp,
                                "borrowed data cannot be stored outside of its closure");
                            err.span_label(sup_sp, "cannot be stored outside of its closure");
                            if origin_sp == sup_sp || origin_sp.contains(sup_sp) {
// // sup_sp == origin.span():
//
// let mut x = None;
//     ----- borrowed data cannot be stored into here...
// with_int(|y| x = Some(y));
//          ---          ^ cannot be stored outside of its closure
//          |
//          ...because it cannot outlive this closure
//
// // origin.contains(&sup_sp):
//
// let mut f: Option<&u32> = None;
//     ----- borrowed data cannot be stored into here...
// closure_expecting_bound(|x: &'x u32| {
//                         ------------ ... because it cannot outlive this closure
//     f = Some(x);
//              ^ cannot be stored outside of its closure
                                err.span_label(*external_span,
                                               "borrowed data cannot be stored into here...");
                                err.span_label(*closure_span,
                                               "...because it cannot outlive this closure");
                            } else {
// FIXME: the wording for this case could be much improved
//
// let mut lines_to_use: Vec<&CrateId> = Vec::new();
//                           - cannot infer an appropriate lifetime...
// let push_id = |installed_id: &CrateId| {
//     -------   ------------------------ borrowed data cannot outlive this closure
//     |
//     ...so that variable is valid at time of its declaration
//     lines_to_use.push(installed_id);
//                       ^^^^^^^^^^^^ cannot be stored outside of its closure
                                err.span_label(origin_sp,
                                               "cannot infer an appropriate lifetime...");
                                err.span_label(*external_span,
                                               "...so that variable is valid at time of its \
                                                declaration");
                                err.span_label(*closure_span,
                                               "borrowed data cannot outlive this closure");
                            }
                            err.emit();
                            return Some(ErrorReported);
                        }
                        _ => {}
                    }
                }
            }
        }
        None
    }
}