Skip to content

Commit 340af29

Browse files
bors[bot]matklad
andauthored
Merge #10080
10080: internal: don't shut up the compiler when it says the code's buggy r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
2 parents b3452dd + e586364 commit 340af29

File tree

2 files changed

+96
-57
lines changed

2 files changed

+96
-57
lines changed

crates/rust-analyzer/src/dispatch.rs

+89-46
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! A visitor for downcasting arbitrary request (JSON) into a specific type.
1+
//! See [RequestDispatcher].
22
use std::{fmt, panic, thread};
33

44
use serde::{de::DeserializeOwned, Serialize};
@@ -10,14 +10,30 @@ use crate::{
1010
LspError, Result,
1111
};
1212

13+
/// A visitor for routing a raw JSON request to an appropriate handler function.
14+
///
15+
/// Most requests are read-only and async and are handled on the threadpool
16+
/// (`on` method).
17+
///
18+
/// Some read-only requests are latency sensitive, and are immediately handled
19+
/// on the main loop thread (`on_sync`). These are typically typing-related
20+
/// requests.
21+
///
22+
/// Some requests modify the state, and are run on the main thread to get
23+
/// `&mut`.
24+
///
25+
/// Read-only requests are wrapped into `catch_unwind` -- they don't modify the
26+
/// state, so it's OK to recover from their failures.
1327
pub(crate) struct RequestDispatcher<'a> {
1428
pub(crate) req: Option<lsp_server::Request>,
1529
pub(crate) global_state: &'a mut GlobalState,
1630
}
1731

1832
impl<'a> RequestDispatcher<'a> {
19-
/// Dispatches the request onto the current thread
20-
pub(crate) fn on_sync<R>(
33+
/// Dispatches the request onto the current thread, given full access to
34+
/// mutable global state. Unlike all other methods here, this one isn't
35+
/// guarded by `catch_unwind`, so, please, don't make bugs :-)
36+
pub(crate) fn on_sync_mut<R>(
2137
&mut self,
2238
f: fn(&mut GlobalState, R::Params) -> Result<R::Result>,
2339
) -> Result<&mut Self>
@@ -26,26 +42,40 @@ impl<'a> RequestDispatcher<'a> {
2642
R::Params: DeserializeOwned + panic::UnwindSafe + fmt::Debug + 'static,
2743
R::Result: Serialize + 'static,
2844
{
29-
let (id, params) = match self.parse::<R>() {
45+
let (id, params, panic_context) = match self.parse::<R>() {
3046
Some(it) => it,
3147
None => return Ok(self),
3248
};
33-
let global_state = panic::AssertUnwindSafe(&mut *self.global_state);
49+
let _pctx = stdx::panic_context::enter(panic_context);
50+
51+
let result = f(&mut self.global_state, params);
52+
let response = result_to_response::<R>(id, result);
53+
54+
self.global_state.respond(response);
55+
Ok(self)
56+
}
57+
58+
/// Dispatches the request onto the current thread.
59+
pub(crate) fn on_sync<R>(
60+
&mut self,
61+
f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
62+
) -> Result<&mut Self>
63+
where
64+
R: lsp_types::request::Request + 'static,
65+
R::Params: DeserializeOwned + panic::UnwindSafe + fmt::Debug + 'static,
66+
R::Result: Serialize + 'static,
67+
{
68+
let (id, params, panic_context) = match self.parse::<R>() {
69+
Some(it) => it,
70+
None => return Ok(self),
71+
};
72+
let global_state_snapshot = self.global_state.snapshot();
3473

3574
let result = panic::catch_unwind(move || {
36-
// Make sure that the whole AssertUnwindSafe is moved into the
37-
// closure, and not just its field.
38-
let panic::AssertUnwindSafe(global_state) = { global_state };
39-
40-
let _pctx = stdx::panic_context::enter(format!(
41-
"\nversion: {}\nrequest: {} {:#?}",
42-
env!("REV"),
43-
R::METHOD,
44-
params
45-
));
46-
f(global_state, params)
75+
let _pctx = stdx::panic_context::enter(panic_context);
76+
f(global_state_snapshot, params)
4777
});
48-
let response = result_to_response::<R>(id, result);
78+
let response = thread_result_to_response::<R>(id, result);
4979

5080
self.global_state.respond(response);
5181
Ok(self)
@@ -61,7 +91,7 @@ impl<'a> RequestDispatcher<'a> {
6191
R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug + 'static,
6292
R::Result: Serialize + 'static,
6393
{
64-
let (id, params) = match self.parse::<R>() {
94+
let (id, params, panic_context) = match self.parse::<R>() {
6595
Some(it) => it,
6696
None => return self,
6797
};
@@ -70,15 +100,10 @@ impl<'a> RequestDispatcher<'a> {
70100
let world = self.global_state.snapshot();
71101
move || {
72102
let result = panic::catch_unwind(move || {
73-
let _pctx = stdx::panic_context::enter(format!(
74-
"\nversion: {}\nrequest: {} {:#?}",
75-
env!("REV"),
76-
R::METHOD,
77-
params
78-
));
103+
let _pctx = stdx::panic_context::enter(panic_context);
79104
f(world, params)
80105
});
81-
let response = result_to_response::<R>(id, result);
106+
let response = thread_result_to_response::<R>(id, result);
82107
Task::Response(response)
83108
}
84109
});
@@ -98,10 +123,10 @@ impl<'a> RequestDispatcher<'a> {
98123
}
99124
}
100125

101-
fn parse<R>(&mut self) -> Option<(lsp_server::RequestId, R::Params)>
126+
fn parse<R>(&mut self) -> Option<(lsp_server::RequestId, R::Params, String)>
102127
where
103128
R: lsp_types::request::Request + 'static,
104-
R::Params: DeserializeOwned + 'static,
129+
R::Params: DeserializeOwned + fmt::Debug + 'static,
105130
{
106131
let req = match &self.req {
107132
Some(req) if req.method == R::METHOD => self.req.take().unwrap(),
@@ -110,7 +135,11 @@ impl<'a> RequestDispatcher<'a> {
110135

111136
let res = crate::from_json(R::METHOD, req.params);
112137
match res {
113-
Ok(params) => Some((req.id, params)),
138+
Ok(params) => {
139+
let panic_context =
140+
format!("\nversion: {}\nrequest: {} {:#?}", env!("REV"), R::METHOD, params);
141+
Some((req.id, params, panic_context))
142+
}
114143
Err(err) => {
115144
let response = lsp_server::Response::new_err(
116145
req.id,
@@ -124,7 +153,7 @@ impl<'a> RequestDispatcher<'a> {
124153
}
125154
}
126155

127-
fn result_to_response<R>(
156+
fn thread_result_to_response<R>(
128157
id: lsp_server::RequestId,
129158
result: thread::Result<Result<R::Result>>,
130159
) -> lsp_server::Response
@@ -134,8 +163,37 @@ where
134163
R::Result: Serialize + 'static,
135164
{
136165
match result {
137-
Ok(Ok(resp)) => lsp_server::Response::new_ok(id, &resp),
138-
Ok(Err(e)) => match e.downcast::<LspError>() {
166+
Ok(result) => result_to_response::<R>(id, result),
167+
Err(panic) => {
168+
let mut message = "server panicked".to_string();
169+
170+
let panic_message = panic
171+
.downcast_ref::<String>()
172+
.map(String::as_str)
173+
.or_else(|| panic.downcast_ref::<&str>().copied());
174+
175+
if let Some(panic_message) = panic_message {
176+
message.push_str(": ");
177+
message.push_str(panic_message)
178+
};
179+
180+
lsp_server::Response::new_err(id, lsp_server::ErrorCode::InternalError as i32, message)
181+
}
182+
}
183+
}
184+
185+
fn result_to_response<R>(
186+
id: lsp_server::RequestId,
187+
result: Result<R::Result>,
188+
) -> lsp_server::Response
189+
where
190+
R: lsp_types::request::Request + 'static,
191+
R::Params: DeserializeOwned + 'static,
192+
R::Result: Serialize + 'static,
193+
{
194+
match result {
195+
Ok(resp) => lsp_server::Response::new_ok(id, &resp),
196+
Err(e) => match e.downcast::<LspError>() {
139197
Ok(lsp_error) => lsp_server::Response::new_err(id, lsp_error.code, lsp_error.message),
140198
Err(e) => {
141199
if is_cancelled(&*e) {
@@ -153,21 +211,6 @@ where
153211
}
154212
}
155213
},
156-
Err(panic) => {
157-
let mut message = "server panicked".to_string();
158-
159-
let panic_message = panic
160-
.downcast_ref::<String>()
161-
.map(String::as_str)
162-
.or_else(|| panic.downcast_ref::<&str>().copied());
163-
164-
if let Some(panic_message) = panic_message {
165-
message.push_str(": ");
166-
message.push_str(panic_message)
167-
};
168-
169-
lsp_server::Response::new_err(id, lsp_server::ErrorCode::InternalError as i32, message)
170-
}
171214
}
172215
}
173216

crates/rust-analyzer/src/main_loop.rs

+7-11
Original file line numberDiff line numberDiff line change
@@ -520,24 +520,20 @@ impl GlobalState {
520520
}
521521

522522
RequestDispatcher { req: Some(req), global_state: self }
523-
.on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| {
523+
.on_sync_mut::<lsp_ext::ReloadWorkspace>(|s, ()| {
524524
s.fetch_workspaces_request();
525525
s.fetch_workspaces_if_needed();
526526
Ok(())
527527
})?
528-
.on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))?
529-
.on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))?
530-
.on_sync::<lsp_types::request::Shutdown>(|s, ()| {
528+
.on_sync_mut::<lsp_types::request::Shutdown>(|s, ()| {
531529
s.shutdown_requested = true;
532530
Ok(())
533531
})?
534-
.on_sync::<lsp_types::request::SelectionRangeRequest>(|s, p| {
535-
handlers::handle_selection_range(s.snapshot(), p)
536-
})?
537-
.on_sync::<lsp_ext::MatchingBrace>(|s, p| {
538-
handlers::handle_matching_brace(s.snapshot(), p)
539-
})?
540-
.on_sync::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))?
532+
.on_sync_mut::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))?
533+
.on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)?
534+
.on_sync::<lsp_ext::OnEnter>(handlers::handle_on_enter)?
535+
.on_sync::<lsp_types::request::SelectionRangeRequest>(handlers::handle_selection_range)?
536+
.on_sync::<lsp_ext::MatchingBrace>(handlers::handle_matching_brace)?
541537
.on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
542538
.on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
543539
.on::<lsp_ext::ViewHir>(handlers::handle_view_hir)

0 commit comments

Comments
 (0)