makepad/libs/relax/compiler/tests/dyn_tail.rs
Admin b22a714840 makepad run: the Rust JIT (libs/relax) and makepad-remote
The JIT that runs makepad apps from source: lexer, front end, type checker,
lazy borrow checker (Gandalf; `--check-first` opts in), codegen, session and
warm/cold caches keyed by compiler stamp, provided crates bound late,
startup images, live patching. User-facing name is `makepad run` (binary
`makepad`, MAKEPAD_RUN_* env, ~/.makepad-run); libs/relax stays the internal
library name. `makepad check` reports rustc-style diagnostics with rustc
error codes and checks a whole workspace (`--workspace`). Runs on macOS,
Linux, Windows and Android. makepad-remote: one tool schema for apps and the
WM (app/1): grabs, captures, traces, frame profiles and tweaks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 12:26:21 +02:00

78 lines
3.5 KiB
Rust

// unsizing through struct tails (`Arc<Mutex<F>>` -> `Arc<Mutex<dyn Fn(u8) -> u32>>`, rustc
// CoerceUnsized + Unsize for structs), and the tail's offset from the dynamic alignment
// (vtable align): a closure capturing only a u8 sits right after the mutex's flags
use std::sync::{Arc, Mutex};
use std::rc::Rc;
use std::cell::RefCell;
struct Wrap<T: ?Sized> { tag: u8, val: T }
#[test]
fn struct_tail_unsizing() {
let k: u8 = 3;
let f: Arc<Mutex<dyn Fn(u8) -> u32>> = Arc::new(Mutex::new(move |x: u8| (x + k) as u32));
assert_eq!(f.lock().unwrap()(4), 7);
let big: u64 = 1 << 40;
let g: Arc<Mutex<dyn Fn(u8) -> u64>> = Arc::new(Mutex::new(move |x: u8| big + x as u64));
assert_eq!(g.lock().unwrap()(1), (1 << 40) + 1);
let r: Rc<RefCell<dyn FnMut() -> u32>> = Rc::new(RefCell::new({ let mut n = 0u32; move || { n += 1; n } }));
r.borrow_mut()();
assert_eq!(r.borrow_mut()(), 2);
let w: Box<Wrap<dyn std::fmt::Debug>> = Box::new(Wrap { tag: 9, val: 5u8 });
assert_eq!(w.tag, 9);
assert_eq!(format!("{:?}", &w.val), "5");
let w2: Box<Wrap<dyn std::fmt::Debug>> = Box::new(Wrap { tag: 1, val: 7u64 });
assert_eq!(format!("{:?}", &w2.val), "7");
}
// a literal tail (`Wrapper(&mut x, 123)`) unsizes to a trait several integer types implement:
// the obligation waits for the literal's i32 fallback (rustc issue-26709); auto traits too
struct Wrapper<'a, T: ?Sized>(&'a mut i32, #[allow(dead_code)] T);
impl<'a, T: ?Sized> Drop for Wrapper<'a, T> { fn drop(&mut self) { *self.0 = 432; } }
#[test]
fn literal_tail_unsizing() {
let mut x = 0;
{ let w = Box::new(Wrapper(&mut x, 123)); let d: Box<Wrapper<dyn std::fmt::Debug>> = w; assert_eq!(format!("{:?}", &d.1), "123"); }
let mut y = 0;
{ let w = Box::new(Wrapper(&mut y, 1.5)); let _: Box<Wrapper<dyn Send>> = w; }
assert_eq!((x, y), (432, 432));
}
// a packed struct with a dyn tail: the tail's alignment is min(packed, vtable align) at run
// time (size, align and offset equal before and after unsizing); a one-field union tail
// (ManuallyDrop) is the unsized tail
#[test]
fn packed_dyn_tail() {
#[repr(C, packed(2))]
struct Packed<T: ?Sized>(u8, core::mem::ManuallyDrop<T>);
let p = Packed(0, core::mem::ManuallyDrop::new(1usize));
let p: &Packed<usize> = &p;
let sized = (core::mem::size_of_val(p), core::mem::align_of_val(p));
let so = unsafe { std::ptr::addr_of!(p.1).cast::<u8>().offset_from(std::ptr::addr_of!(p.0)) };
let p: &Packed<dyn Send> = p;
let un = (core::mem::size_of_val(p), core::mem::align_of_val(p));
let uo = unsafe { std::ptr::addr_of!(p.1).cast::<u8>().offset_from(std::ptr::addr_of!(p.0)) };
assert_eq!((sized, so), (un, uo));
assert_eq!(un, (10, 2));
}
// `self: Box<Self>` on a box of a boxed trait object: autoderef passes the inner Box<dyn Tr>
trait Double { fn double(self: Box<Self>) -> usize; }
impl Double for usize { fn double(self: Box<usize>) -> usize { *self * 2 } }
#[test]
fn boxed_box_self() {
let y: Box<dyn Double> = Box::new(3usize);
assert_eq!(y.double(), 6);
let x: Box<_> = Box::new(Box::new(4usize) as Box<dyn Double>);
assert_eq!(x.double(), 8);
}
// an unsized tail behind a projection (`A::Dyn` with `type Dyn = DynRef`): references to the
// struct are fat (rustc issue-60431)
pub trait Arena { type Dyn: ?Sized; }
pub struct DynRef { _d: [()] }
pub struct RefA<A: Arena> { _v: u8, _d: A::Dyn }
pub struct Ob;
impl Arena for Ob { type Dyn = DynRef; }
#[test]
fn projection_tail() {
assert_eq!(std::mem::size_of::<&RefA<Ob>>(), std::mem::size_of::<&[()]>());
}