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
use crate::layout;

/// Context necessary to answer the question "Are these types transmutable?".
pub(crate) trait QueryContext {
    type Def: layout::Def;
    type Ref: layout::Ref;
    type Scope: Copy;

    /// Is `def` accessible from the defining module of `scope`?
    fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool;

    fn min_align(&self, reference: Self::Ref) -> usize;
}

#[cfg(test)]
pub(crate) mod test {
    use super::QueryContext;

    pub(crate) struct UltraMinimal;

    #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
    pub(crate) enum Def {
        Visible,
        Invisible,
    }

    impl crate::layout::Def for Def {}

    impl QueryContext for UltraMinimal {
        type Def = Def;
        type Ref = !;
        type Scope = ();

        fn is_accessible_from(&self, def: Def, scope: ()) -> bool {
            matches!(Def::Visible, def)
        }

        fn min_align(&self, reference: !) -> usize {
            unimplemented!()
        }
    }
}

#[cfg(feature = "rustc")]
mod rustc {
    use super::*;
    use rustc_middle::ty::{Ty, TyCtxt};

    impl<'tcx> super::QueryContext for TyCtxt<'tcx> {
        type Def = layout::rustc::Def<'tcx>;
        type Ref = layout::rustc::Ref<'tcx>;

        type Scope = Ty<'tcx>;

        #[instrument(level = "debug", skip(self))]
        fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool {
            use layout::rustc::Def;
            use rustc_middle::ty;

            let parent = if let ty::Adt(adt_def, ..) = scope.kind() {
                use rustc_middle::ty::DefIdTree;
                let parent = self.parent(adt_def.did());
                parent
            } else {
                // Is this always how we want to handle a non-ADT scope?
                return false;
            };

            let def_id = match def {
                Def::Adt(adt_def) => adt_def.did(),
                Def::Variant(variant_def) => variant_def.def_id,
                Def::Field(field_def) => field_def.did,
                Def::Primitive => {
                    // primitives do not have a def_id, but they're always accessible
                    return true;
                }
            };

            let ret = if self.visibility(def_id).is_accessible_from(parent, *self) {
                true
            } else {
                false
            };

            trace!(?ret, "ret");
            ret
        }

        fn min_align(&self, reference: Self::Ref) -> usize {
            unimplemented!()
        }
    }
}