]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/prefixes.rs
Rollup merge of #105400 - BoxyUwU:braced_param_evaluatability, r=oli-obk
[rust.git] / compiler / rustc_borrowck / src / prefixes.rs
1 #![deny(rustc::untranslatable_diagnostic)]
2 #![deny(rustc::diagnostic_outside_of_impl)]
3 //! From the NLL RFC: "The deep [aka 'supporting'] prefixes for an
4 //! place are formed by stripping away fields and derefs, except that
5 //! we stop when we reach the deref of a shared reference. [...] "
6 //!
7 //! "Shallow prefixes are found by stripping away fields, but stop at
8 //! any dereference. So: writing a path like `a` is illegal if `a.b`
9 //! is borrowed. But: writing `a` is legal if `*a` is borrowed,
10 //! whether or not `a` is a shared or mutable reference. [...] "
11
12 use super::MirBorrowckCtxt;
13
14 use rustc_hir as hir;
15 use rustc_middle::mir::{Body, PlaceRef, ProjectionElem};
16 use rustc_middle::ty::{self, TyCtxt};
17
18 pub trait IsPrefixOf<'tcx> {
19     fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool;
20 }
21
22 impl<'tcx> IsPrefixOf<'tcx> for PlaceRef<'tcx> {
23     fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool {
24         self.local == other.local
25             && self.projection.len() <= other.projection.len()
26             && self.projection == &other.projection[..self.projection.len()]
27     }
28 }
29
30 pub(super) struct Prefixes<'cx, 'tcx> {
31     body: &'cx Body<'tcx>,
32     tcx: TyCtxt<'tcx>,
33     kind: PrefixSet,
34     next: Option<PlaceRef<'tcx>>,
35 }
36
37 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
38 pub(super) enum PrefixSet {
39     /// Doesn't stop until it returns the base case (a Local or
40     /// Static prefix).
41     All,
42     /// Stops at any dereference.
43     Shallow,
44     /// Stops at the deref of a shared reference.
45     Supporting,
46 }
47
48 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
49     /// Returns an iterator over the prefixes of `place`
50     /// (inclusive) from longest to smallest, potentially
51     /// terminating the iteration early based on `kind`.
52     pub(super) fn prefixes(
53         &self,
54         place_ref: PlaceRef<'tcx>,
55         kind: PrefixSet,
56     ) -> Prefixes<'cx, 'tcx> {
57         Prefixes { next: Some(place_ref), kind, body: self.body, tcx: self.infcx.tcx }
58     }
59 }
60
61 impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
62     type Item = PlaceRef<'tcx>;
63     fn next(&mut self) -> Option<Self::Item> {
64         let mut cursor = self.next?;
65
66         // Post-processing `place`: Enqueue any remaining
67         // work. Also, `place` may not be a prefix itself, but
68         // may hold one further down (e.g., we never return
69         // downcasts here, but may return a base of a downcast).
70
71         'cursor: loop {
72             match cursor.last_projection() {
73                 None => {
74                     self.next = None;
75                     return Some(cursor);
76                 }
77                 Some((cursor_base, elem)) => {
78                     match elem {
79                         ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
80                             // FIXME: add union handling
81                             self.next = Some(cursor_base);
82                             return Some(cursor);
83                         }
84                         ProjectionElem::Downcast(..)
85                         | ProjectionElem::Subslice { .. }
86                         | ProjectionElem::OpaqueCast { .. }
87                         | ProjectionElem::ConstantIndex { .. }
88                         | ProjectionElem::Index(_) => {
89                             cursor = cursor_base;
90                             continue 'cursor;
91                         }
92                         ProjectionElem::Deref => {
93                             // (handled below)
94                         }
95                     }
96
97                     assert_eq!(elem, ProjectionElem::Deref);
98
99                     match self.kind {
100                         PrefixSet::Shallow => {
101                             // Shallow prefixes are found by stripping away
102                             // fields, but stop at *any* dereference.
103                             // So we can just stop the traversal now.
104                             self.next = None;
105                             return Some(cursor);
106                         }
107                         PrefixSet::All => {
108                             // All prefixes: just blindly enqueue the base
109                             // of the projection.
110                             self.next = Some(cursor_base);
111                             return Some(cursor);
112                         }
113                         PrefixSet::Supporting => {
114                             // Fall through!
115                         }
116                     }
117
118                     assert_eq!(self.kind, PrefixSet::Supporting);
119                     // Supporting prefixes: strip away fields and
120                     // derefs, except we stop at the deref of a shared
121                     // reference.
122
123                     let ty = cursor_base.ty(self.body, self.tcx).ty;
124                     match ty.kind() {
125                         ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => {
126                             // don't continue traversing over derefs of raw pointers or shared
127                             // borrows.
128                             self.next = None;
129                             return Some(cursor);
130                         }
131
132                         ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Mut) => {
133                             self.next = Some(cursor_base);
134                             return Some(cursor);
135                         }
136
137                         ty::Adt(..) if ty.is_box() => {
138                             self.next = Some(cursor_base);
139                             return Some(cursor);
140                         }
141
142                         _ => panic!("unknown type fed to Projection Deref."),
143                     }
144                 }
145             }
146         }
147     }
148 }