Skip to content

Commit 3f64170

Browse files
committed
[ty] Run background tasks with panic handler
1 parent 8fcdf96 commit 3f64170

File tree

9 files changed

+126
-72
lines changed

9 files changed

+126
-72
lines changed

crates/ruff_benchmark/benches/ty.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ fn benchmark_incremental(criterion: &mut Criterion) {
131131
fn setup() -> Case {
132132
let case = setup_tomllib_case();
133133

134-
let result: Vec<_> = case.db.check().unwrap();
134+
let result: Vec<_> = case.db.check();
135135

136136
assert_diagnostics(&case.db, &result, EXPECTED_TOMLLIB_DIAGNOSTICS);
137137

@@ -159,7 +159,7 @@ fn benchmark_incremental(criterion: &mut Criterion) {
159159
None,
160160
);
161161

162-
let result = db.check().unwrap();
162+
let result = db.check();
163163

164164
assert_eq!(result.len(), EXPECTED_TOMLLIB_DIAGNOSTICS.len());
165165
}
@@ -179,7 +179,7 @@ fn benchmark_cold(criterion: &mut Criterion) {
179179
setup_tomllib_case,
180180
|case| {
181181
let Case { db, .. } = case;
182-
let result: Vec<_> = db.check().unwrap();
182+
let result: Vec<_> = db.check();
183183

184184
assert_diagnostics(db, &result, EXPECTED_TOMLLIB_DIAGNOSTICS);
185185
},
@@ -293,7 +293,7 @@ fn benchmark_many_string_assignments(criterion: &mut Criterion) {
293293
},
294294
|case| {
295295
let Case { db, .. } = case;
296-
let result = db.check().unwrap();
296+
let result = db.check();
297297
assert_eq!(result.len(), 0);
298298
},
299299
BatchSize::SmallInput,
@@ -339,7 +339,7 @@ fn benchmark_many_tuple_assignments(criterion: &mut Criterion) {
339339
},
340340
|case| {
341341
let Case { db, .. } = case;
342-
let result = db.check().unwrap();
342+
let result = db.check();
343343
assert_eq!(result.len(), 0);
344344
},
345345
BatchSize::SmallInput,

crates/ruff_db/src/panic.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::any::Any;
12
use std::backtrace::BacktraceStatus;
23
use std::cell::Cell;
34
use std::panic::Location;
@@ -24,17 +25,25 @@ impl Payload {
2425
None
2526
}
2627
}
28+
29+
pub fn downcast_ref<R: Any>(&self) -> Option<&R> {
30+
self.0.downcast_ref::<R>()
31+
}
2732
}
2833

2934
impl std::fmt::Display for PanicError {
3035
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31-
writeln!(f, "panicked at")?;
36+
write!(f, "panicked at")?;
3237
if let Some(location) = &self.location {
3338
write!(f, " {location}")?;
3439
}
3540
if let Some(payload) = self.payload.as_str() {
3641
write!(f, ":\n{payload}")?;
3742
}
43+
if let Some(query_trace) = self.salsa_backtrace.as_ref() {
44+
let _ = writeln!(f, "{query_trace}");
45+
}
46+
3847
if let Some(backtrace) = &self.backtrace {
3948
match backtrace.status() {
4049
BacktraceStatus::Disabled => {
@@ -49,6 +58,7 @@ impl std::fmt::Display for PanicError {
4958
_ => {}
5059
}
5160
}
61+
5262
Ok(())
5363
}
5464
}

crates/ty/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,12 +243,14 @@ impl MainLoop {
243243
MainLoopMessage::CheckWorkspace => {
244244
let db = db.clone();
245245
let sender = self.sender.clone();
246-
let mut reporter = R::default();
247246

248247
// Spawn a new task that checks the project. This needs to be done in a separate thread
249248
// to prevent blocking the main loop here.
250249
rayon::spawn(move || {
251-
match db.check_with_reporter(&mut reporter) {
250+
match salsa::Cancelled::catch(|| {
251+
let mut reporter = R::default();
252+
db.check_with_reporter(&mut reporter)
253+
}) {
252254
Ok(result) => {
253255
// Send the result back to the main loop for printing.
254256
sender

crates/ty/tests/file_watching.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,7 +1135,7 @@ print(sys.last_exc, os.getegid())
11351135
Ok(())
11361136
})?;
11371137

1138-
let diagnostics = case.db.check().context("Failed to check project.")?;
1138+
let diagnostics = case.db.check();
11391139

11401140
assert_eq!(diagnostics.len(), 2);
11411141
assert_eq!(
@@ -1160,7 +1160,7 @@ print(sys.last_exc, os.getegid())
11601160
})
11611161
.expect("Search path settings to be valid");
11621162

1163-
let diagnostics = case.db.check().context("Failed to check project.")?;
1163+
let diagnostics = case.db.check();
11641164
assert!(diagnostics.is_empty());
11651165

11661166
Ok(())
@@ -1767,10 +1767,7 @@ fn changes_to_user_configuration() -> anyhow::Result<()> {
17671767
let foo = case
17681768
.system_file(case.project_path("foo.py"))
17691769
.expect("foo.py to exist");
1770-
let diagnostics = case
1771-
.db()
1772-
.check_file(foo)
1773-
.context("Failed to check project.")?;
1770+
let diagnostics = case.db().check_file(foo);
17741771

17751772
assert!(
17761773
diagnostics.is_empty(),
@@ -1790,10 +1787,7 @@ fn changes_to_user_configuration() -> anyhow::Result<()> {
17901787

17911788
case.apply_changes(changes);
17921789

1793-
let diagnostics = case
1794-
.db()
1795-
.check_file(foo)
1796-
.context("Failed to check project.")?;
1790+
let diagnostics = case.db().check_file(foo);
17971791

17981792
assert!(
17991793
diagnostics.len() == 1,

crates/ty_project/src/db.rs

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use ruff_db::files::{File, Files};
88
use ruff_db::system::System;
99
use ruff_db::vendored::VendoredFileSystem;
1010
use ruff_db::{Db as SourceDb, Upcast};
11+
use salsa::Event;
1112
use salsa::plumbing::ZalsaDatabase;
12-
use salsa::{Cancelled, Event};
1313
use ty_ide::Db as IdeDb;
1414
use ty_python_semantic::lint::{LintRegistry, RuleSelection};
1515
use ty_python_semantic::{Db as SemanticDb, Program};
@@ -24,10 +24,10 @@ pub trait Db: SemanticDb + Upcast<dyn SemanticDb> {
2424
#[salsa::db]
2525
#[derive(Clone)]
2626
pub struct ProjectDatabase {
27+
system: Arc<dyn System + Send + Sync + RefUnwindSafe>,
2728
project: Option<Project>,
28-
storage: salsa::Storage<ProjectDatabase>,
2929
files: Files,
30-
system: Arc<dyn System + Send + Sync + RefUnwindSafe>,
30+
storage: salsa::Storage<ProjectDatabase>,
3131
}
3232

3333
impl ProjectDatabase {
@@ -68,24 +68,21 @@ impl ProjectDatabase {
6868
}
6969

7070
/// Checks all open files in the project and its dependencies.
71-
pub fn check(&self) -> Result<Vec<Diagnostic>, Cancelled> {
71+
pub fn check(&self) -> Vec<Diagnostic> {
7272
let mut reporter = DummyReporter;
7373
let reporter = AssertUnwindSafe(&mut reporter as &mut dyn Reporter);
74-
self.with_db(|db| db.project().check(db, reporter))
74+
self.project().check(self, reporter)
7575
}
7676

7777
/// Checks all open files in the project and its dependencies, using the given reporter.
78-
pub fn check_with_reporter(
79-
&self,
80-
reporter: &mut dyn Reporter,
81-
) -> Result<Vec<Diagnostic>, Cancelled> {
78+
pub fn check_with_reporter(&self, reporter: &mut dyn Reporter) -> Vec<Diagnostic> {
8279
let reporter = AssertUnwindSafe(reporter);
83-
self.with_db(|db| db.project().check(db, reporter))
80+
self.project().check(self, reporter)
8481
}
8582

8683
#[tracing::instrument(level = "debug", skip(self))]
87-
pub fn check_file(&self, file: File) -> Result<Vec<Diagnostic>, Cancelled> {
88-
self.with_db(|db| self.project().check_file(db, file))
84+
pub fn check_file(&self, file: File) -> Vec<Diagnostic> {
85+
self.project().check_file(self, file)
8986
}
9087

9188
/// Returns a mutable reference to the system.
@@ -99,13 +96,6 @@ impl ProjectDatabase {
9996
Arc::get_mut(&mut self.system)
10097
.expect("ref count should be 1 because `zalsa_mut` drops all other DB references.")
10198
}
102-
103-
pub(crate) fn with_db<F, T>(&self, f: F) -> Result<T, Cancelled>
104-
where
105-
F: FnOnce(&ProjectDatabase) -> T + std::panic::UnwindSafe,
106-
{
107-
Cancelled::catch(|| f(self))
108-
}
10999
}
110100

111101
impl Upcast<dyn SemanticDb> for ProjectDatabase {

crates/ty_server/src/server.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
//! Scheduling, I/O, and API endpoints.
22
3-
use std::num::NonZeroUsize;
4-
// The new PanicInfoHook name requires MSRV >= 1.82
5-
#[expect(deprecated)]
6-
use std::panic::PanicInfo;
7-
83
use lsp_server::Message;
94
use lsp_types::{
105
ClientCapabilities, DiagnosticOptions, DiagnosticServerCapabilities,
@@ -13,6 +8,8 @@ use lsp_types::{
138
TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions,
149
TypeDefinitionProviderCapability, Url,
1510
};
11+
use std::num::NonZeroUsize;
12+
use std::panic::PanicHookInfo;
1613

1714
use self::connection::{Connection, ConnectionInitializer};
1815
use self::schedule::event_loop_thread;
@@ -115,9 +112,7 @@ impl Server {
115112
}
116113

117114
pub(crate) fn run(self) -> crate::Result<()> {
118-
// The new PanicInfoHook name requires MSRV >= 1.82
119-
#[expect(deprecated)]
120-
type PanicHook = Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>;
115+
type PanicHook = Box<dyn Fn(&PanicHookInfo<'_>) + 'static + Sync + Send>;
121116
struct RestorePanicHook {
122117
hook: Option<PanicHook>,
123118
}

0 commit comments

Comments
 (0)