Skip to main content

TermCaches

Struct TermCaches 

Source
pub(crate) struct TermCaches<'z3, 'tcx> {
    pub(crate) sizes: FxHashMap<Ty<'tcx>, Int<'z3>>,
    pub(crate) aligns: FxHashMap<Ty<'tcx>, Int<'z3>>,
    pub(crate) not_mask_terms: FxHashSet<Int<'z3>>,
    pub(crate) exact_div_roots: FxHashMap<Int<'z3>, Int<'z3>>,
    pub(crate) div_roots: FxHashMap<Int<'z3>, (Int<'z3>, Int<'z3>)>,
    pub(crate) iter_ptr_offset: FxHashMap<AllocId, (Int<'z3>, Option<Int<'z3>>)>,
    pub(crate) uninit_byte: Option<Int<'z3>>,
}
Expand description

Term-provenance caches, one per phenomenon the VM must shape by hand.

Z3’s nonlinear integer solver (NIA) cannot rewrite degree-3 products or deeply-nested pointer chains, so the VM records the semantic meaning of a symbol (what it divides, which iterator it indexes, …) and uses that provenance later to emit a compact, degree-≤2 term instead. Each cache is independent — they share only the path-scoped, monotonic lifetime.

Fields§

§sizes: FxHashMap<Ty<'tcx>, Int<'z3>>

sizeof_T for each generic type, one symbolic constant per type. Keeps ptr.add strides, access_bytes element sizes, and allocation sizes consistent so that SMT can cancel the S factor in InBound.

§aligns: FxHashMap<Ty<'tcx>, Int<'z3>>

align_T for each generic type, one symbolic constant per type; linked to the size by the layout constraint sizeof_T % align_T == 0.

§not_mask_terms: FxHashSet<Int<'z3>>

Terms that are the result of a bitwise Not (two’s-complement mask). Used to recognize x & !(align-1) alignment patterns in BitAnd so we can derive align = -mask and emit linear bounds for the result.

§exact_div_roots: FxHashMap<Int<'z3>, Int<'z3>>

quotient → dividend for each exact division (lhs % rhs == 0), recording which size each exact_div symbol divides (e.g. us → sizeof_T). Lets a later us_len = (len / ts) * us multiplication emit the byte bound us_len * sizeof_U <= len * sizeof_T.

§div_roots: FxHashMap<Int<'z3>, (Int<'z3>, Int<'z3>)>

quotient → (lhs, rhs) for each non-exact division, recovering the len and divisor (ts) operands at a following us_len = (len / ts) * us.

§iter_ptr_offset: FxHashMap<AllocId, (Int<'z3>, Option<Int<'z3>>)>

Per-iterator element index, keyed by the buffer the iterator walks (end field’s provenance alloc id, which is frame-independent). The value is (offset, base_len): the current element index and the total element count (the end field’s Element offset, None when unknown). Caching both keeps next/len/is_empty checks linear (base_len - offset) instead of a deeply-nested ((base + S) + S) … pointer chain that Z3’s NIA cannot reason about.

§uninit_byte: Option<Int<'z3>>

UNINIT sentinel byte value (≥ 256, outside the u8 value range). The default element of every byte array; select(array, i) != UNINIT is how “byte i was written” is decided.

Trait Implementations§

Source§

impl<'z3, 'tcx> Default for TermCaches<'z3, 'tcx>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<'z3, 'tcx> !DynSend for TermCaches<'z3, 'tcx>

§

impl<'z3, 'tcx> !DynSync for TermCaches<'z3, 'tcx>

§

impl<'z3, 'tcx> !RefUnwindSafe for TermCaches<'z3, 'tcx>

§

impl<'z3, 'tcx> !Send for TermCaches<'z3, 'tcx>

§

impl<'z3, 'tcx> !Sync for TermCaches<'z3, 'tcx>

§

impl<'z3, 'tcx> !UnwindSafe for TermCaches<'z3, 'tcx>

§

impl<'z3, 'tcx> Freeze for TermCaches<'z3, 'tcx>

§

impl<'z3, 'tcx> Unpin for TermCaches<'z3, 'tcx>

§

impl<'z3, 'tcx> UnsafeUnpin for TermCaches<'z3, 'tcx>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V