Initial (incomplete) implementation of transmutability trait.
This initial implementation handles transmutations between types with specified layouts, except when references are involved. Co-authored-by: Igor null <m1el.2027@gmail.com>
This commit is contained in:
@@ -0,0 +1,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>;
|
||||
|
||||
#[tracing::instrument(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
|
||||
};
|
||||
|
||||
tracing::trace!(ret = ?ret, "ret");
|
||||
ret
|
||||
}
|
||||
|
||||
fn min_align(&self, reference: Self::Ref) -> usize {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user