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
125
126
127
128
129
130
131
132
133
134
// Copyright 2012-2013 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 one region is named and the other is anonymous.
use infer::error_reporting::nice_region_error::NiceRegionError;
use ty;
use util::common::ErrorReported;

impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
    /// When given a `ConcreteFailure` for a function with arguments containing a named region and
    /// an anonymous region, emit an descriptive diagnostic error.
    pub(super) fn try_report_named_anon_conflict(&self) -> Option<ErrorReported> {
        let (span, sub, sup) = self.get_regions();

        debug!(
            "try_report_named_anon_conflict(sub={:?}, sup={:?})",
            sub,
            sup
        );

        // Determine whether the sub and sup consist of one named region ('a)
        // and one anonymous (elided) region. If so, find the parameter arg
        // where the anonymous region appears (there must always be one; we
        // only introduced anonymous regions in parameters) as well as a
        // version new_ty of its type where the anonymous region is replaced
        // with the named one.//scope_def_id
        let (named, anon, anon_arg_info, region_info) = if self.is_named_region(sub)
            && self.is_suitable_region(sup).is_some()
            && self.find_arg_with_region(sup, sub).is_some()
        {
            (
                sub,
                sup,
                self.find_arg_with_region(sup, sub).unwrap(),
                self.is_suitable_region(sup).unwrap(),
            )
        } else if self.is_named_region(sup) && self.is_suitable_region(sub).is_some()
            && self.find_arg_with_region(sub, sup).is_some()
        {
            (
                sup,
                sub,
                self.find_arg_with_region(sub, sup).unwrap(),
                self.is_suitable_region(sub).unwrap(),
            )
        } else {
            return None; // inapplicable
        };

        debug!("try_report_named_anon_conflict: named = {:?}", named);
        debug!(
            "try_report_named_anon_conflict: anon_arg_info = {:?}",
            anon_arg_info
        );
        debug!(
            "try_report_named_anon_conflict: region_info = {:?}",
            region_info
        );

        let (arg, new_ty, br, is_first, scope_def_id, is_impl_item) = (
            anon_arg_info.arg,
            anon_arg_info.arg_ty,
            anon_arg_info.bound_region,
            anon_arg_info.is_first,
            region_info.def_id,
            region_info.is_impl_item,
        );
        match br {
            ty::BrAnon(_) => {}
            _ => {
                /* not an anonymous region */
                debug!("try_report_named_anon_conflict: not an anonymous region");
                return None;
            }
        }

        if is_impl_item {
            debug!("try_report_named_anon_conflict: impl item, bail out");
            return None;
        }

        if let Some((_, fndecl)) = self.find_anon_type(anon, &br) {
            if self.is_return_type_anon(scope_def_id, br, fndecl).is_some()
                || self.is_self_anon(is_first, scope_def_id)
            {
                return None;
            }
        }

        let (error_var, span_label_var) = if let Some(simple_name) = arg.pat.simple_name() {
            (
                format!("the type of `{}`", simple_name),
                format!("the type of `{}`", simple_name),
            )
        } else {
            ("parameter type".to_owned(), "type".to_owned())
        };

        struct_span_err!(
            self.tcx.sess,
            span,
            E0621,
            "explicit lifetime required in {}",
            error_var
        ).span_label(
            arg.pat.span,
            format!("consider changing {} to `{}`", span_label_var, new_ty),
        )
            .span_label(span, format!("lifetime `{}` required", named))
            .emit();
        return Some(ErrorReported);
    }

    // This method returns whether the given Region is Named
    pub(super) fn is_named_region(&self, region: ty::Region<'tcx>) -> bool {
        match *region {
            ty::ReStatic => true,
            ty::ReFree(ref free_region) => match free_region.bound_region {
                ty::BrNamed(..) => true,
                _ => false,
            },
            ty::ReEarlyBound(_) => true,
            _ => false,
        }
    }
}