Skip to content

Commit f85fc28

Browse files
committed
Auto merge of rust-lang#14412 - Veykril:proc-macro-op-queue, r=Veykril
internal: Handle proc macro fetching via OpQueue
2 parents 27c076a + ee02213 commit f85fc28

File tree

17 files changed

+121
-92
lines changed

17 files changed

+121
-92
lines changed

crates/base-db/src/input.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ use syntax::SmolStr;
1515
use tt::token_id::Subtree;
1616
use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath};
1717

18-
pub type ProcMacroPaths = FxHashMap<CrateId, Result<(Option<String>, AbsPathBuf), String>>;
18+
// Map from crate id to the name of the crate and path of the proc-macro. If the value is `None`,
19+
// then the crate for the proc-macro hasn't been build yet as the build data is missing.
20+
pub type ProcMacroPaths = FxHashMap<CrateId, Option<(Option<String>, AbsPathBuf)>>;
1921
pub type ProcMacros = FxHashMap<CrateId, ProcMacroLoadResult>;
2022

2123
/// Files are grouped into source roots. A source root is a directory on the

crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,21 @@ pub(crate) fn unresolved_proc_macro(
2525
_ => proc_macros_enabled,
2626
};
2727

28-
let message = match &d.macro_name {
28+
let not_expanded_message = match &d.macro_name {
2929
Some(name) => format!("proc macro `{name}` not expanded"),
3030
None => "proc macro not expanded".to_string(),
3131
};
3232
let severity = if config_enabled { Severity::Error } else { Severity::WeakWarning };
3333
let def_map = ctx.sema.db.crate_def_map(d.krate);
34-
let message = format!(
35-
"{message}: {}",
36-
if config_enabled {
37-
def_map.proc_macro_loading_error().unwrap_or("proc macro not found in the built dylib")
38-
} else {
39-
match d.kind {
40-
hir::MacroKind::Attr if proc_macros_enabled => {
41-
"attribute macro expansion is disabled"
42-
}
43-
_ => "proc-macro expansion is disabled",
44-
}
45-
},
46-
);
34+
let message = if config_enabled {
35+
def_map.proc_macro_loading_error().unwrap_or("proc macro not found in the built dylib")
36+
} else {
37+
match d.kind {
38+
hir::MacroKind::Attr if proc_macros_enabled => "attribute macro expansion is disabled",
39+
_ => "proc-macro expansion is disabled",
40+
}
41+
};
42+
let message = format!("{not_expanded_message}: {message}");
4743

4844
Diagnostic::new("unresolved-proc-macro", message, display_range).severity(severity)
4945
}

crates/project-model/src/workspace.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ fn project_json_to_crate_graph(
707707
if let Some(path) = krate.proc_macro_dylib_path.clone() {
708708
proc_macros.insert(
709709
crate_id,
710-
Ok((
710+
Some((
711711
krate.display_name.as_ref().map(|it| it.canonical_name().to_owned()),
712712
path,
713713
)),
@@ -1185,12 +1185,14 @@ fn add_target_crate_root(
11851185
CrateOrigin::CratesIo { repo: pkg.repository.clone(), name: Some(pkg.name.clone()) },
11861186
target_layout,
11871187
);
1188-
let proc_macro = match build_data.as_ref().map(|it| &it.proc_macro_dylib_path) {
1189-
Some(it) => it.clone().map(Ok),
1190-
None => Some(Err("crate has not (yet) been built".into())),
1191-
};
1192-
if let Some(proc_macro) = proc_macro {
1193-
proc_macros.insert(crate_id, proc_macro.map(|path| (Some(cargo_name.to_owned()), path)));
1188+
if is_proc_macro {
1189+
let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) {
1190+
Some(it) => it.cloned().map(|path| Some((Some(cargo_name.to_owned()), path))),
1191+
None => Some(None),
1192+
};
1193+
if let Some(proc_macro) = proc_macro {
1194+
proc_macros.insert(crate_id, proc_macro);
1195+
}
11941196
}
11951197

11961198
crate_id

crates/rust-analyzer/src/cli/load_cargo.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,10 @@ pub fn load_workspace(
101101
.map(|(crate_id, path)| {
102102
(
103103
crate_id,
104-
path.and_then(|(_, path)| load_proc_macro(proc_macro_server, &path, &[])),
104+
path.map_or_else(
105+
|| Err("proc macro crate is missing dylib".to_owned()),
106+
|(_, path)| load_proc_macro(proc_macro_server, &path, &[]),
107+
),
105108
)
106109
})
107110
.collect()

crates/rust-analyzer/src/config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,10 @@ impl Config {
11061106
&self.data.procMacro_ignored
11071107
}
11081108

1109+
pub fn expand_proc_macros(&self) -> bool {
1110+
self.data.procMacro_enable
1111+
}
1112+
11091113
pub fn expand_proc_attr_macros(&self) -> bool {
11101114
self.data.procMacro_enable && self.data.procMacro_attributes_enable
11111115
}

crates/rust-analyzer/src/global_state.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::{sync::Arc, time::Instant};
88
use crossbeam_channel::{unbounded, Receiver, Sender};
99
use flycheck::FlycheckHandle;
1010
use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId};
11-
use ide_db::base_db::{CrateId, FileLoader, SourceDatabase};
11+
use ide_db::base_db::{CrateId, FileLoader, ProcMacroPaths, SourceDatabase};
1212
use lsp_types::{SemanticTokens, Url};
1313
use parking_lot::{Mutex, RwLock};
1414
use proc_macro_api::ProcMacroServer;
@@ -101,11 +101,12 @@ pub(crate) struct GlobalState {
101101
/// the user just adds comments or whitespace to Cargo.toml, we do not want
102102
/// to invalidate any salsa caches.
103103
pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
104-
pub(crate) fetch_workspaces_queue: OpQueue<Option<Vec<anyhow::Result<ProjectWorkspace>>>>,
104+
pub(crate) fetch_workspaces_queue: OpQueue<(), Option<Vec<anyhow::Result<ProjectWorkspace>>>>,
105105
pub(crate) fetch_build_data_queue:
106-
OpQueue<(Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)>,
106+
OpQueue<(), (Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)>,
107+
pub(crate) fetch_proc_macros_queue: OpQueue<Vec<ProcMacroPaths>, bool>,
107108

108-
pub(crate) prime_caches_queue: OpQueue<()>,
109+
pub(crate) prime_caches_queue: OpQueue,
109110
}
110111

111112
/// An immutable snapshot of the world's state at a point in time.
@@ -117,6 +118,7 @@ pub(crate) struct GlobalStateSnapshot {
117118
pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
118119
vfs: Arc<RwLock<(vfs::Vfs, NoHashHashMap<FileId, LineEndings>)>>,
119120
pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
121+
// used to signal semantic highlighting to fall back to syntax based highlighting until proc-macros have been loaded
120122
pub(crate) proc_macros_loaded: bool,
121123
pub(crate) flycheck: Arc<[FlycheckHandle]>,
122124
}
@@ -170,9 +172,10 @@ impl GlobalState {
170172

171173
workspaces: Arc::new(Vec::new()),
172174
fetch_workspaces_queue: OpQueue::default(),
173-
prime_caches_queue: OpQueue::default(),
174-
175175
fetch_build_data_queue: OpQueue::default(),
176+
fetch_proc_macros_queue: OpQueue::default(),
177+
178+
prime_caches_queue: OpQueue::default(),
176179
};
177180
// Apply any required database inputs from the config.
178181
this.update_configuration(config);
@@ -286,7 +289,7 @@ impl GlobalState {
286289
// crate see https://github.com/rust-lang/rust-analyzer/issues/13029
287290
if let Some(path) = workspace_structure_change {
288291
self.fetch_workspaces_queue
289-
.request_op(format!("workspace vfs file change: {}", path.display()));
292+
.request_op(format!("workspace vfs file change: {}", path.display()), ());
290293
}
291294
self.proc_macro_changed =
292295
changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| {
@@ -309,7 +312,8 @@ impl GlobalState {
309312
check_fixes: Arc::clone(&self.diagnostics.check_fixes),
310313
mem_docs: self.mem_docs.clone(),
311314
semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache),
312-
proc_macros_loaded: !self.fetch_build_data_queue.last_op_result().0.is_empty(),
315+
proc_macros_loaded: !self.config.expand_proc_macros()
316+
|| *self.fetch_proc_macros_queue.last_op_result(),
313317
flycheck: self.flycheck.clone(),
314318
}
315319
}

crates/rust-analyzer/src/handlers.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,15 @@ pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result<
4848
state.proc_macro_clients = Arc::new([]);
4949
state.proc_macro_changed = false;
5050

51-
state.fetch_workspaces_queue.request_op("reload workspace request".to_string());
52-
state.fetch_build_data_queue.request_op("reload workspace request".to_string());
51+
state.fetch_workspaces_queue.request_op("reload workspace request".to_string(), ());
5352
Ok(())
5453
}
5554

56-
pub(crate) fn handle_proc_macros_reload(state: &mut GlobalState, _: ()) -> Result<()> {
55+
pub(crate) fn handle_proc_macros_rebuild(state: &mut GlobalState, _: ()) -> Result<()> {
5756
state.proc_macro_clients = Arc::new([]);
5857
state.proc_macro_changed = false;
5958

60-
state.fetch_build_data_queue.request_op("reload proc macros request".to_string());
59+
state.fetch_build_data_queue.request_op("rebuild proc macros request".to_string(), ());
6160
Ok(())
6261
}
6362

crates/rust-analyzer/src/lsp_ext.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ impl Request for ReloadWorkspace {
5151
const METHOD: &'static str = "rust-analyzer/reloadWorkspace";
5252
}
5353

54-
pub enum ReloadProcMacros {}
54+
pub enum RebuildProcMacros {}
5555

56-
impl Request for ReloadProcMacros {
56+
impl Request for RebuildProcMacros {
5757
type Params = ();
5858
type Result = ();
59-
const METHOD: &'static str = "rust-analyzer/reloadProcMacros";
59+
const METHOD: &'static str = "rust-analyzer/rebuildProcMacros";
6060
}
6161

6262
pub enum SyntaxTree {}

crates/rust-analyzer/src/main_loop.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@ impl GlobalState {
149149
);
150150
}
151151

152-
self.fetch_workspaces_queue.request_op("startup".to_string());
153-
if let Some(cause) = self.fetch_workspaces_queue.should_start_op() {
152+
self.fetch_workspaces_queue.request_op("startup".to_string(), ());
153+
if let Some((cause, ())) = self.fetch_workspaces_queue.should_start_op() {
154154
self.fetch_workspaces(cause);
155155
}
156156

@@ -248,7 +248,7 @@ impl GlobalState {
248248
self.prime_caches_queue.op_completed(());
249249
if cancelled {
250250
self.prime_caches_queue
251-
.request_op("restart after cancellation".to_string());
251+
.request_op("restart after cancellation".to_string(), ());
252252
}
253253
}
254254
};
@@ -280,15 +280,16 @@ impl GlobalState {
280280
if self.is_quiescent() {
281281
let became_quiescent = !(was_quiescent
282282
|| self.fetch_workspaces_queue.op_requested()
283-
|| self.fetch_build_data_queue.op_requested());
283+
|| self.fetch_build_data_queue.op_requested()
284+
|| self.fetch_proc_macros_queue.op_requested());
284285

285286
if became_quiescent {
286287
if self.config.check_on_save() {
287288
// Project has loaded properly, kick off initial flycheck
288289
self.flycheck.iter().for_each(FlycheckHandle::restart);
289290
}
290291
if self.config.prefill_caches() {
291-
self.prime_caches_queue.request_op("became quiescent".to_string());
292+
self.prime_caches_queue.request_op("became quiescent".to_string(), ());
292293
}
293294
}
294295

@@ -358,18 +359,20 @@ impl GlobalState {
358359
}
359360

360361
if self.config.cargo_autoreload() {
361-
if let Some(cause) = self.fetch_workspaces_queue.should_start_op() {
362+
if let Some((cause, ())) = self.fetch_workspaces_queue.should_start_op() {
362363
self.fetch_workspaces(cause);
363364
}
364365
}
365366

366367
if !self.fetch_workspaces_queue.op_in_progress() {
367-
if let Some(cause) = self.fetch_build_data_queue.should_start_op() {
368+
if let Some((cause, ())) = self.fetch_build_data_queue.should_start_op() {
368369
self.fetch_build_data(cause);
370+
} else if let Some((cause, paths)) = self.fetch_proc_macros_queue.should_start_op() {
371+
self.fetch_proc_macros(cause, paths);
369372
}
370373
}
371374

372-
if let Some(cause) = self.prime_caches_queue.should_start_op() {
375+
if let Some((cause, ())) = self.prime_caches_queue.should_start_op() {
373376
tracing::debug!(%cause, "will prime caches");
374377
let num_worker_threads = self.config.prime_caches_num_threads();
375378

@@ -463,7 +466,8 @@ impl GlobalState {
463466
let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces);
464467

465468
if self.config.run_build_scripts() && workspaces_updated {
466-
self.fetch_build_data_queue.request_op(format!("workspace updated"));
469+
self.fetch_build_data_queue
470+
.request_op(format!("workspace updated"), ());
467471
}
468472

469473
(Progress::End, None)
@@ -497,6 +501,7 @@ impl GlobalState {
497501
ProcMacroProgress::Begin => (Some(Progress::Begin), None),
498502
ProcMacroProgress::Report(msg) => (Some(Progress::Report), Some(msg)),
499503
ProcMacroProgress::End(proc_macro_load_result) => {
504+
self.fetch_proc_macros_queue.op_completed(true);
500505
self.set_proc_macros(proc_macro_load_result);
501506

502507
(Some(Progress::End), None)
@@ -649,7 +654,7 @@ impl GlobalState {
649654

650655
dispatcher
651656
.on_sync_mut::<lsp_ext::ReloadWorkspace>(handlers::handle_workspace_reload)
652-
.on_sync_mut::<lsp_ext::ReloadProcMacros>(handlers::handle_proc_macros_reload)
657+
.on_sync_mut::<lsp_ext::RebuildProcMacros>(handlers::handle_proc_macros_rebuild)
653658
.on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage)
654659
.on_sync_mut::<lsp_ext::ShuffleCrateGraph>(handlers::handle_shuffle_crate_graph)
655660
.on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)
@@ -904,7 +909,7 @@ impl GlobalState {
904909
if let Some(abs_path) = vfs_path.as_path() {
905910
if reload::should_refresh_for_change(abs_path, ChangeKind::Modify) {
906911
this.fetch_workspaces_queue
907-
.request_op(format!("DidSaveTextDocument {}", abs_path.display()));
912+
.request_op(format!("DidSaveTextDocument {}", abs_path.display()), ());
908913
}
909914
}
910915

@@ -980,7 +985,7 @@ impl GlobalState {
980985
config.workspace_roots.extend(added);
981986
if !config.has_linked_projects() && config.detached_files().is_empty() {
982987
config.rediscover_workspaces();
983-
this.fetch_workspaces_queue.request_op("client workspaces changed".to_string())
988+
this.fetch_workspaces_queue.request_op("client workspaces changed".to_string(), ())
984989
}
985990

986991
Ok(())

crates/rust-analyzer/src/op_queue.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,23 @@
33
44
pub(crate) type Cause = String;
55

6-
pub(crate) struct OpQueue<Output> {
7-
op_requested: Option<Cause>,
6+
pub(crate) struct OpQueue<Args = (), Output = ()> {
7+
op_requested: Option<(Cause, Args)>,
88
op_in_progress: bool,
99
last_op_result: Output,
1010
}
1111

12-
impl<Output: Default> Default for OpQueue<Output> {
12+
impl<Args, Output: Default> Default for OpQueue<Args, Output> {
1313
fn default() -> Self {
1414
Self { op_requested: None, op_in_progress: false, last_op_result: Default::default() }
1515
}
1616
}
1717

18-
impl<Output> OpQueue<Output> {
19-
pub(crate) fn request_op(&mut self, reason: Cause) {
20-
self.op_requested = Some(reason);
18+
impl<Args, Output> OpQueue<Args, Output> {
19+
pub(crate) fn request_op(&mut self, reason: Cause, args: Args) {
20+
self.op_requested = Some((reason, args));
2121
}
22-
pub(crate) fn should_start_op(&mut self) -> Option<Cause> {
22+
pub(crate) fn should_start_op(&mut self) -> Option<(Cause, Args)> {
2323
if self.op_in_progress {
2424
return None;
2525
}

0 commit comments

Comments
 (0)