Skip to main content

rustc_borrowck/
prefixes.rs

1//! From the NLL RFC:
2//! "Shallow prefixes are found by stripping away fields, but stop at
3//! any dereference. So: writing a path like `a` is illegal if `a.b`
4//! is borrowed. But: writing `a` is legal if `*a` is borrowed,
5//! whether or not `a` is a shared or mutable reference. [...] "
6
7use rustc_middle::mir::{PlaceRef, ProjectionElem};
8
9use super::MirBorrowckCtxt;
10
11pub(super) struct Prefixes<'tcx> {
12    kind: PrefixSet,
13    next: Option<PlaceRef<'tcx>>,
14}
15
16#[derive(#[automatically_derived]
impl ::core::marker::Copy for PrefixSet { }Copy, #[automatically_derived]
impl ::core::clone::Clone for PrefixSet {
    #[inline]
    fn clone(&self) -> PrefixSet { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for PrefixSet {
    #[inline]
    fn eq(&self, other: &PrefixSet) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for PrefixSet {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::fmt::Debug for PrefixSet {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                PrefixSet::All => "All",
                PrefixSet::Shallow => "Shallow",
            })
    }
}Debug)]
17pub(super) enum PrefixSet {
18    /// Doesn't stop until it returns the base case (a Local or
19    /// Static prefix).
20    All,
21    /// Stops at any dereference.
22    Shallow,
23}
24
25impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
26    /// Returns an iterator over the prefixes of `place`
27    /// (inclusive) from longest to smallest, potentially
28    /// terminating the iteration early based on `kind`.
29    pub(super) fn prefixes(&self, place_ref: PlaceRef<'tcx>, kind: PrefixSet) -> Prefixes<'tcx> {
30        Prefixes { next: Some(place_ref), kind }
31    }
32}
33
34impl<'tcx> Iterator for Prefixes<'tcx> {
35    type Item = PlaceRef<'tcx>;
36    fn next(&mut self) -> Option<Self::Item> {
37        let mut cursor = self.next?;
38
39        // Post-processing `place`: Enqueue any remaining
40        // work. Also, `place` may not be a prefix itself, but
41        // may hold one further down (e.g., we never return
42        // downcasts here, but may return a base of a downcast).
43
44        loop {
45            match cursor.last_projection() {
46                None => {
47                    self.next = None;
48                    return Some(cursor);
49                }
50                Some((cursor_base, elem)) => {
51                    match elem {
52                        ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
53                            // FIXME: add union handling
54                            self.next = Some(cursor_base);
55                            return Some(cursor);
56                        }
57                        ProjectionElem::UnwrapUnsafeBinder(_) => {
58                            self.next = Some(cursor_base);
59                            return Some(cursor);
60                        }
61                        ProjectionElem::Downcast(..)
62                        | ProjectionElem::Subslice { .. }
63                        | ProjectionElem::OpaqueCast { .. }
64                        | ProjectionElem::ConstantIndex { .. }
65                        | ProjectionElem::Index(_) => {
66                            cursor = cursor_base;
67                        }
68                        ProjectionElem::Deref => {
69                            match self.kind {
70                                PrefixSet::Shallow => {
71                                    // Shallow prefixes are found by stripping away
72                                    // fields, but stop at *any* dereference.
73                                    // So we can just stop the traversal now.
74                                    self.next = None;
75                                    return Some(cursor);
76                                }
77                                PrefixSet::All => {
78                                    // All prefixes: just blindly enqueue the base
79                                    // of the projection.
80                                    self.next = Some(cursor_base);
81                                    return Some(cursor);
82                                }
83                            }
84                        }
85                    }
86                }
87            }
88        }
89    }
90}