]> git.lizzy.rs Git - rust.git/blob - src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
intern CodeExtents
[rust.git] / src / librustc_borrowck / borrowck / gather_loans / lifetime.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! This module implements the check that the lifetime of a borrow
12 //! does not exceed the lifetime of the value being borrowed.
13
14 use borrowck::*;
15 use rustc::middle::expr_use_visitor as euv;
16 use rustc::middle::mem_categorization as mc;
17 use rustc::middle::mem_categorization::Categorization;
18 use rustc::middle::region;
19 use rustc::ty;
20
21 use syntax::ast;
22 use syntax_pos::Span;
23
24 type R = Result<(),()>;
25
26 pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
27                                     item_scope: region::CodeExtent<'tcx>,
28                                     span: Span,
29                                     cause: euv::LoanCause,
30                                     cmt: mc::cmt<'tcx>,
31                                     loan_region: ty::Region<'tcx>,
32                                     _: ty::BorrowKind)
33                                     -> Result<(),()> {
34     //! Reports error if `loan_region` is larger than S
35     //! where S is `item_scope` if `cmt` is an upvar,
36     //! and is scope of `cmt` otherwise.
37     debug!("guarantee_lifetime(cmt={:?}, loan_region={:?})",
38            cmt, loan_region);
39     let ctxt = GuaranteeLifetimeContext {bccx: bccx,
40                                          item_scope: item_scope,
41                                          span: span,
42                                          cause: cause,
43                                          loan_region: loan_region,
44                                          cmt_original: cmt.clone()};
45     ctxt.check(&cmt, None)
46 }
47
48 ///////////////////////////////////////////////////////////////////////////
49 // Private
50
51 struct GuaranteeLifetimeContext<'a, 'tcx: 'a> {
52     bccx: &'a BorrowckCtxt<'a, 'tcx>,
53
54     // the scope of the function body for the enclosing item
55     item_scope: region::CodeExtent<'tcx>,
56
57     span: Span,
58     cause: euv::LoanCause,
59     loan_region: ty::Region<'tcx>,
60     cmt_original: mc::cmt<'tcx>
61 }
62
63 impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
64
65     fn check(&self, cmt: &mc::cmt<'tcx>, discr_scope: Option<ast::NodeId>) -> R {
66         //! Main routine. Walks down `cmt` until we find the
67         //! "guarantor".  Reports an error if `self.loan_region` is
68         //! larger than scope of `cmt`.
69         debug!("guarantee_lifetime.check(cmt={:?}, loan_region={:?})",
70                cmt,
71                self.loan_region);
72
73         match cmt.cat {
74             Categorization::Rvalue(..) |
75             Categorization::Local(..) |                         // L-Local
76             Categorization::Upvar(..) |
77             Categorization::Deref(.., mc::BorrowedPtr(..)) |  // L-Deref-Borrowed
78             Categorization::Deref(.., mc::Implicit(..)) |
79             Categorization::Deref(.., mc::UnsafePtr(..)) => {
80                 self.check_scope(self.scope(cmt))
81             }
82
83             Categorization::StaticItem => {
84                 Ok(())
85             }
86
87             Categorization::Downcast(ref base, _) |
88             Categorization::Deref(ref base, _, mc::Unique) |     // L-Deref-Send
89             Categorization::Interior(ref base, _) => {             // L-Field
90                 self.check(base, discr_scope)
91             }
92         }
93     }
94
95     fn check_scope(&self, max_scope: ty::Region<'tcx>) -> R {
96         //! Reports an error if `loan_region` is larger than `max_scope`
97
98         if !self.bccx.is_subregion_of(self.loan_region, max_scope) {
99             Err(self.report_error(err_out_of_scope(max_scope, self.loan_region, self.cause)))
100         } else {
101             Ok(())
102         }
103     }
104
105     fn scope(&self, cmt: &mc::cmt<'tcx>) -> ty::Region<'tcx> {
106         //! Returns the maximal region scope for the which the
107         //! lvalue `cmt` is guaranteed to be valid without any
108         //! rooting etc, and presuming `cmt` is not mutated.
109
110         match cmt.cat {
111             Categorization::Rvalue(temp_scope, _) => {
112                 temp_scope
113             }
114             Categorization::Upvar(..) => {
115                 self.bccx.tcx.mk_region(ty::ReScope(self.item_scope))
116             }
117             Categorization::Local(local_id) => {
118                 self.bccx.tcx.mk_region(ty::ReScope(
119                     self.bccx.tcx.region_maps().var_scope(local_id)))
120             }
121             Categorization::StaticItem |
122             Categorization::Deref(.., mc::UnsafePtr(..)) => {
123                 self.bccx.tcx.types.re_static
124             }
125             Categorization::Deref(.., mc::BorrowedPtr(_, r)) |
126             Categorization::Deref(.., mc::Implicit(_, r)) => {
127                 r
128             }
129             Categorization::Downcast(ref cmt, _) |
130             Categorization::Deref(ref cmt, _, mc::Unique) |
131             Categorization::Interior(ref cmt, _) => {
132                 self.scope(cmt)
133             }
134         }
135     }
136
137     fn report_error(&self, code: bckerr_code<'tcx>) {
138         self.bccx.report(BckError { cmt: self.cmt_original.clone(),
139                                     span: self.span,
140                                     cause: BorrowViolation(self.cause),
141                                     code: code });
142     }
143 }