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>
78 lines
3.6 KiB
Rust
78 lines
3.6 KiB
Rust
//@ edition: 2024
|
|
// Drop order of temporaries against bindings (sequences = rustc --edition 2024 --test):
|
|
// - parameter patterns (`fn f((_x, _): (D, D))`, closures too): the argument is a variable
|
|
// declared before the pattern's bindings, so it drops after them (closures leaked it);
|
|
// - operands already evaluated when a later one unwinds / exits (`(D(4), &D(5), panic)`) drop
|
|
// before the statement's temporaries (their scope is the using expression's, nested inside);
|
|
// - arrays iterated by value (`for (_a, _) in [(D(6), D(5))]`): items whose type needs drop go
|
|
// through `IntoIterator for [T; N]` (the index loop leaked `_` parts and the rest after a break);
|
|
// - edition 2024 `if let` / match-guard `let` chains: each scrutinee's temporaries drop with the
|
|
// chain's bindings in reverse creation order, at the end of the then block / arm.
|
|
use std::cell::RefCell;
|
|
thread_local! { static LOG: RefCell<Vec<u32>> = RefCell::new(Vec::new()); }
|
|
fn take() -> Vec<u32> { LOG.with(|l| std::mem::take(&mut *l.borrow_mut())) }
|
|
struct D(u32);
|
|
impl Drop for D { fn drop(&mut self) { LOG.with(|l| l.borrow_mut().push(self.0)); } }
|
|
fn ok(m: u32) -> Result<D, D> { Ok(D(m)) }
|
|
fn boom() { panic!() }
|
|
|
|
fn params((_x, _): (D, D), (_, _y): (D, D)) {}
|
|
|
|
#[test]
|
|
fn parameter_patterns() {
|
|
params((D(3), D(4)), (D(2), D(1)));
|
|
assert_eq!(take(), [1, 2, 3, 4]);
|
|
let c = |(_x, _): (D, D), (_, _y): (D, D)| {};
|
|
c((D(3), D(4)), (D(2), D(1)));
|
|
assert_eq!(take(), [1, 2, 3, 4]);
|
|
// arrays by value: each item drops per iteration, the rest when the loop is left
|
|
for (_a, _) in [(D(6), D(5))] {}
|
|
assert_eq!(take(), [6, 5]);
|
|
for x in [D(1), D(2), D(3)] { if x.0 == 1 { break; } }
|
|
assert_eq!(take(), [1, 2, 3]);
|
|
for _ in [D(4)] {}
|
|
assert_eq!(take(), [4]);
|
|
}
|
|
|
|
#[test]
|
|
fn operands_before_statement_temporaries() {
|
|
std::panic::set_hook(Box::new(|_| {}));
|
|
let _ = std::panic::catch_unwind(|| { (D(4), &D(5), D(6), &D(7), boom()); });
|
|
assert_eq!(take(), [6, 4, 7, 5]);
|
|
let _ = std::panic::catch_unwind(|| { (&D(1), D(2), { let _x = &D(9); let _y = D(8); boom() }); });
|
|
assert_eq!(take(), [8, 9, 2, 1]);
|
|
let _ = std::panic::take_hook();
|
|
let r = (|| -> Option<u32> { let _t = (D(1), &D(2), None::<u32>?); Some(1) })();
|
|
assert_eq!((r, take()), (None, vec![1, 2]));
|
|
}
|
|
|
|
#[test]
|
|
fn if_let_chain_rescope() {
|
|
if ok(1).is_ok() && let true = ok(9).is_ok() && let Ok(_v) = ok(8) && let Ok(_) = ok(7) && let Ok(_) = ok(6).as_ref() && let Ok(_v) = ok(5) && let Ok(_) = ok(4).as_ref() {
|
|
LOG.with(|l| l.borrow_mut().push(3));
|
|
}
|
|
assert_eq!(take(), [1, 3, 4, 5, 6, 7, 8, 9]);
|
|
let x = (D(1), if let Some(_) = D(2).0.checked_add(0) && let D(..) = D(3) { D(4) } else { D(5) });
|
|
assert_eq!(take(), [3, 2]);
|
|
drop(x);
|
|
assert_eq!(take(), [1, 4]);
|
|
match () {
|
|
() if let Ok(_v) = ok(8) && let Ok(_) = ok(7).as_ref() && let Err(_) = ok(6) => {}
|
|
_ => LOG.with(|l| l.borrow_mut().push(9)),
|
|
}
|
|
assert_eq!(take(), [6, 7, 8, 9]);
|
|
match () {
|
|
() if let Ok(_v) = ok(5) && let Ok(_) = ok(4).as_ref() => LOG.with(|l| l.borrow_mut().push(3)),
|
|
_ => {}
|
|
}
|
|
assert_eq!(take(), [3, 4, 5]);
|
|
// a guard run once per or-alternative: each failed run drops its own temporaries once
|
|
let mut n = 1;
|
|
match D(8) {
|
|
_ | _ | _ if let _ = D(n) && { n += 1; false } => unreachable!(),
|
|
_ if let _ = D(5) && { LOG.with(|l| l.borrow_mut().push(4)); false } => unreachable!(),
|
|
_ if let _ = D(7) && true => { LOG.with(|l| l.borrow_mut().push(6)); }
|
|
_ => unreachable!(),
|
|
}
|
|
assert_eq!(take(), [1, 2, 3, 4, 5, 6, 7, 8]);
|
|
}
|