mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 14:33:29 +00:00
93 lines
2.5 KiB
Rust
93 lines
2.5 KiB
Rust
use salsa::{Database, ParallelDatabase, Snapshot};
|
|
use std::panic::{self, AssertUnwindSafe};
|
|
use std::sync::atomic::{AtomicU32, Ordering::SeqCst};
|
|
|
|
#[salsa::query_group(PanicSafelyStruct)]
|
|
trait PanicSafelyDatabase: salsa::Database {
|
|
#[salsa::input]
|
|
fn one(&self) -> usize;
|
|
|
|
fn panic_safely(&self) -> ();
|
|
|
|
fn outer(&self) -> ();
|
|
}
|
|
|
|
fn panic_safely(db: &dyn PanicSafelyDatabase) {
|
|
assert_eq!(db.one(), 1);
|
|
}
|
|
|
|
static OUTER_CALLS: AtomicU32 = AtomicU32::new(0);
|
|
|
|
fn outer(db: &dyn PanicSafelyDatabase) {
|
|
OUTER_CALLS.fetch_add(1, SeqCst);
|
|
db.panic_safely();
|
|
}
|
|
|
|
#[salsa::database(PanicSafelyStruct)]
|
|
#[derive(Default)]
|
|
struct DatabaseStruct {
|
|
storage: salsa::Storage<Self>,
|
|
}
|
|
|
|
impl salsa::Database for DatabaseStruct {}
|
|
|
|
impl salsa::ParallelDatabase for DatabaseStruct {
|
|
fn snapshot(&self) -> Snapshot<Self> {
|
|
Snapshot::new(DatabaseStruct { storage: self.storage.snapshot() })
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn should_panic_safely() {
|
|
let mut db = DatabaseStruct::default();
|
|
db.set_one(0);
|
|
|
|
// Invoke `db.panic_safely() without having set `db.one`. `db.one` will
|
|
// return 0 and we should catch the panic.
|
|
let result = panic::catch_unwind(AssertUnwindSafe({
|
|
let db = db.snapshot();
|
|
move || db.panic_safely()
|
|
}));
|
|
assert!(result.is_err());
|
|
|
|
// Set `db.one` to 1 and assert ok
|
|
db.set_one(1);
|
|
let result = panic::catch_unwind(AssertUnwindSafe(|| db.panic_safely()));
|
|
assert!(result.is_ok());
|
|
|
|
// Check, that memoized outer is not invalidated by a panic
|
|
{
|
|
assert_eq!(OUTER_CALLS.load(SeqCst), 0);
|
|
db.outer();
|
|
assert_eq!(OUTER_CALLS.load(SeqCst), 1);
|
|
|
|
db.set_one(0);
|
|
let result = panic::catch_unwind(AssertUnwindSafe(|| db.outer()));
|
|
assert!(result.is_err());
|
|
assert_eq!(OUTER_CALLS.load(SeqCst), 1);
|
|
|
|
db.set_one(1);
|
|
db.outer();
|
|
assert_eq!(OUTER_CALLS.load(SeqCst), 2);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn storages_are_unwind_safe() {
|
|
fn check_unwind_safe<T: std::panic::UnwindSafe>() {}
|
|
check_unwind_safe::<&DatabaseStruct>();
|
|
}
|
|
|
|
#[test]
|
|
fn panics_clear_query_stack() {
|
|
let db = DatabaseStruct::default();
|
|
|
|
// Invoke `db.panic_if_not_one() without having set `db.input`. `db.input`
|
|
// will default to 0 and we should catch the panic.
|
|
let result = panic::catch_unwind(AssertUnwindSafe(|| db.panic_safely()));
|
|
assert!(result.is_err());
|
|
|
|
// The database has been poisoned and any attempt to increment the
|
|
// revision should panic.
|
|
assert_eq!(db.salsa_runtime().active_query(), None);
|
|
}
|