pub(crate) fn unsized_info<'tcx>(
    fx: &mut FunctionCx<'_, '_, 'tcx>,
    source: Ty<'tcx>,
    target: Ty<'tcx>,
    old_info: Option<Value>,
) -> Value {
    let (source, target) =
        fx.tcx.struct_lockstep_tails_for_codegen(source, target, fx.typing_env());
    match (&source.kind(), &target.kind()) {
        (&ty::Array(_, len), &ty::Slice(_)) => fx.bcx.ins().iconst(
            fx.pointer_type,
            len.try_to_target_usize(fx.tcx).expect("expected monomorphic const in codegen") as i64,
        ),
        (&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind))
            if src_dyn_kind == target_dyn_kind =>
        {
            let old_info =
                old_info.expect("unsized_info: missing old info for trait upcasting coercion");
            let b_principal_def_id = data_b.principal_def_id();
            if data_a.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
                // A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables.
                debug_assert!(
                    validate_trivial_unsize(fx.tcx, data_a, data_b),
                    "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
                );
                return old_info;
            }

            // trait upcasting coercion
            let vptr_entry_idx = fx.tcx.supertrait_vtable_slot((source, target));

            if let Some(entry_idx) = vptr_entry_idx {
                let entry_idx = u32::try_from(entry_idx).unwrap();
                let entry_offset = entry_idx * fx.pointer_type.bytes();
                let vptr_ptr = Pointer::new(old_info).offset_i64(fx, entry_offset.into()).load(
                    fx,
                    fx.pointer_type,
                    crate::vtable::vtable_memflags(),
                );
                vptr_ptr
            } else {
                old_info
            }
        }
        (_, ty::Dynamic(data, ..)) => crate::vtable::get_vtable(
            fx,
            source,
            data.principal()
                .map(|principal| fx.tcx.instantiate_bound_regions_with_erased(principal)),
        ),
        _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
    }
}
Retrieve the information we are losing (making dynamic) in an unsizing
adjustment.

The `old_info` argument is a bit funny. It is intended for use
in an upcast, where the new vtable for an object will be derived
from the old one.
src/unsize.rs