Skip to content

Commit 0e760a6

Browse files
bors[bot]matklad
andauthored
Merge #7319
7319: Avoid blocking the main loop when editing Cargo.toml r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
2 parents e1190ba + add87f5 commit 0e760a6

File tree

5 files changed

+100
-71
lines changed

5 files changed

+100
-71
lines changed

crates/project_model/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod cfg_flag;
55
mod project_json;
66
mod sysroot;
77
mod workspace;
8+
mod rustc_cfg;
89

910
use std::{
1011
fs::{read_dir, ReadDir},

crates/project_model/src/rustc_cfg.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//! Runs `rustc --print cfg` to get built-in cfg flags.
2+
3+
use std::process::Command;
4+
5+
use crate::{cfg_flag::CfgFlag, utf8_stdout};
6+
7+
pub(crate) fn get(target: Option<&str>) -> Vec<CfgFlag> {
8+
let _p = profile::span("rustc_cfg::get");
9+
let mut res = Vec::new();
10+
11+
// Some nightly-only cfgs, which are required for stdlib
12+
res.push(CfgFlag::Atom("target_thread_local".into()));
13+
for &ty in ["8", "16", "32", "64", "cas", "ptr"].iter() {
14+
for &key in ["target_has_atomic", "target_has_atomic_load_store"].iter() {
15+
res.push(CfgFlag::KeyValue { key: key.to_string(), value: ty.into() });
16+
}
17+
}
18+
19+
let rustc_cfgs = {
20+
let mut cmd = Command::new(toolchain::rustc());
21+
cmd.args(&["--print", "cfg", "-O"]);
22+
if let Some(target) = target {
23+
cmd.args(&["--target", target]);
24+
}
25+
utf8_stdout(cmd)
26+
};
27+
28+
match rustc_cfgs {
29+
Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())),
30+
Err(e) => log::error!("failed to get rustc cfgs: {:#}", e),
31+
}
32+
33+
res
34+
}

crates/project_model/src/workspace.rs

Lines changed: 58 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use proc_macro_api::ProcMacroClient;
1616
use rustc_hash::{FxHashMap, FxHashSet};
1717

1818
use crate::{
19-
cargo_workspace, cfg_flag::CfgFlag, sysroot::SysrootCrate, utf8_stdout, CargoConfig,
19+
cargo_workspace, cfg_flag::CfgFlag, rustc_cfg, sysroot::SysrootCrate, utf8_stdout, CargoConfig,
2020
CargoWorkspace, ProjectJson, ProjectManifest, Sysroot, TargetKind,
2121
};
2222

@@ -34,29 +34,41 @@ pub struct PackageRoot {
3434
#[derive(Clone, Eq, PartialEq)]
3535
pub enum ProjectWorkspace {
3636
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
37-
Cargo { cargo: CargoWorkspace, sysroot: Sysroot, rustc: Option<CargoWorkspace> },
37+
Cargo {
38+
cargo: CargoWorkspace,
39+
sysroot: Sysroot,
40+
rustc: Option<CargoWorkspace>,
41+
/// Holds cfg flags for the current target. We get those by running
42+
/// `rustc --print cfg`.
43+
///
44+
/// FIXME: make this a per-crate map, as, eg, build.rs might have a
45+
/// different target.
46+
rustc_cfg: Vec<CfgFlag>,
47+
},
3848
/// Project workspace was manually specified using a `rust-project.json` file.
39-
Json { project: ProjectJson, sysroot: Option<Sysroot> },
49+
Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
4050
}
4151

4252
impl fmt::Debug for ProjectWorkspace {
4353
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4454
match self {
45-
ProjectWorkspace::Cargo { cargo, sysroot, rustc } => f
55+
ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => f
4656
.debug_struct("Cargo")
4757
.field("n_packages", &cargo.packages().len())
4858
.field("n_sysroot_crates", &sysroot.crates().len())
4959
.field(
5060
"n_rustc_compiler_crates",
5161
&rustc.as_ref().map_or(0, |rc| rc.packages().len()),
5262
)
63+
.field("rustc_cfg", rustc_cfg)
5364
.finish(),
54-
ProjectWorkspace::Json { project, sysroot } => {
65+
ProjectWorkspace::Json { project, sysroot, rustc_cfg } => {
5566
let mut debug_struct = f.debug_struct("Json");
5667
debug_struct.field("n_crates", &project.n_crates());
5768
if let Some(sysroot) = sysroot {
5869
debug_struct.field("n_sysroot_crates", &sysroot.crates().len());
5970
}
71+
debug_struct.field("rustc_cfg", rustc_cfg);
6072
debug_struct.finish()
6173
}
6274
}
@@ -79,7 +91,7 @@ impl ProjectWorkspace {
7991
})?;
8092
let project_location = project_json.parent().unwrap().to_path_buf();
8193
let project_json = ProjectJson::new(&project_location, data);
82-
ProjectWorkspace::load_inline(project_json)?
94+
ProjectWorkspace::load_inline(project_json, config.target.as_deref())?
8395
}
8496
ProjectManifest::CargoToml(cargo_toml) => {
8597
let cargo_version = utf8_stdout({
@@ -117,29 +129,32 @@ impl ProjectWorkspace {
117129
} else {
118130
None
119131
};
120-
121-
ProjectWorkspace::Cargo { cargo, sysroot, rustc }
132+
let rustc_cfg = rustc_cfg::get(config.target.as_deref());
133+
ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg }
122134
}
123135
};
124136

125137
Ok(res)
126138
}
127139

128-
pub fn load_inline(project_json: ProjectJson) -> Result<ProjectWorkspace> {
140+
pub fn load_inline(
141+
project_json: ProjectJson,
142+
target: Option<&str>,
143+
) -> Result<ProjectWorkspace> {
129144
let sysroot = match &project_json.sysroot_src {
130145
Some(path) => Some(Sysroot::load(path)?),
131146
None => None,
132147
};
133-
134-
Ok(ProjectWorkspace::Json { project: project_json, sysroot })
148+
let rustc_cfg = rustc_cfg::get(target);
149+
Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
135150
}
136151

137152
/// Returns the roots for the current `ProjectWorkspace`
138153
/// The return type contains the path and whether or not
139154
/// the root is a member of the current workspace
140155
pub fn to_roots(&self) -> Vec<PackageRoot> {
141156
match self {
142-
ProjectWorkspace::Json { project, sysroot } => project
157+
ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project
143158
.crates()
144159
.map(|(_, krate)| PackageRoot {
145160
is_member: krate.is_workspace_member,
@@ -156,7 +171,7 @@ impl ProjectWorkspace {
156171
})
157172
}))
158173
.collect::<Vec<_>>(),
159-
ProjectWorkspace::Cargo { cargo, sysroot, rustc } => cargo
174+
ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _ } => cargo
160175
.packages()
161176
.map(|pkg| {
162177
let is_member = cargo[pkg].is_member;
@@ -194,7 +209,7 @@ impl ProjectWorkspace {
194209
pub fn n_packages(&self) -> usize {
195210
match self {
196211
ProjectWorkspace::Json { project, .. } => project.n_crates(),
197-
ProjectWorkspace::Cargo { cargo, sysroot, rustc } => {
212+
ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => {
198213
let rustc_package_len = rustc.as_ref().map_or(0, |rc| rc.packages().len());
199214
cargo.packages().len() + sysroot.crates().len() + rustc_package_len
200215
}
@@ -203,7 +218,6 @@ impl ProjectWorkspace {
203218

204219
pub fn to_crate_graph(
205220
&self,
206-
target: Option<&str>,
207221
proc_macro_client: Option<&ProcMacroClient>,
208222
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
209223
) -> CrateGraph {
@@ -214,12 +228,21 @@ impl ProjectWorkspace {
214228
};
215229

216230
let mut crate_graph = match self {
217-
ProjectWorkspace::Json { project, sysroot } => {
218-
project_json_to_crate_graph(target, &proc_macro_loader, load, project, sysroot)
219-
}
220-
ProjectWorkspace::Cargo { cargo, sysroot, rustc } => {
221-
cargo_to_crate_graph(target, &proc_macro_loader, load, cargo, sysroot, rustc)
222-
}
231+
ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph(
232+
rustc_cfg.clone(),
233+
&proc_macro_loader,
234+
load,
235+
project,
236+
sysroot,
237+
),
238+
ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => cargo_to_crate_graph(
239+
rustc_cfg.clone(),
240+
&proc_macro_loader,
241+
load,
242+
cargo,
243+
sysroot,
244+
rustc,
245+
),
223246
};
224247
if crate_graph.patch_cfg_if() {
225248
log::debug!("Patched std to depend on cfg-if")
@@ -231,7 +254,7 @@ impl ProjectWorkspace {
231254
}
232255

233256
fn project_json_to_crate_graph(
234-
target: Option<&str>,
257+
rustc_cfg: Vec<CfgFlag>,
235258
proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
236259
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
237260
project: &ProjectJson,
@@ -240,9 +263,9 @@ fn project_json_to_crate_graph(
240263
let mut crate_graph = CrateGraph::default();
241264
let sysroot_deps = sysroot
242265
.as_ref()
243-
.map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load));
266+
.map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load));
244267

245-
let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default();
268+
let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default();
246269
let crates: FxHashMap<CrateId, CrateId> = project
247270
.crates()
248271
.filter_map(|(crate_id, krate)| {
@@ -254,9 +277,12 @@ fn project_json_to_crate_graph(
254277
let env = krate.env.clone().into_iter().collect();
255278
let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| proc_macro_loader(&it));
256279

257-
let target = krate.target.as_deref().or(target);
258-
let target_cfgs =
259-
cfg_cache.entry(target).or_insert_with(|| get_rustc_cfg_options(target));
280+
let target_cfgs = match krate.target.as_deref() {
281+
Some(target) => {
282+
cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(Some(target)))
283+
}
284+
None => &rustc_cfg,
285+
};
260286

261287
let mut cfg_options = CfgOptions::default();
262288
cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned());
@@ -293,7 +319,7 @@ fn project_json_to_crate_graph(
293319
}
294320

295321
fn cargo_to_crate_graph(
296-
target: Option<&str>,
322+
rustc_cfg: Vec<CfgFlag>,
297323
proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
298324
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
299325
cargo: &CargoWorkspace,
@@ -303,10 +329,10 @@ fn cargo_to_crate_graph(
303329
let _p = profile::span("cargo_to_crate_graph");
304330
let mut crate_graph = CrateGraph::default();
305331
let (public_deps, libproc_macro) =
306-
sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load);
332+
sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load);
307333

308334
let mut cfg_options = CfgOptions::default();
309-
cfg_options.extend(get_rustc_cfg_options(target));
335+
cfg_options.extend(rustc_cfg);
310336

311337
let mut pkg_to_lib_crate = FxHashMap::default();
312338

@@ -492,12 +518,12 @@ fn add_target_crate_root(
492518
fn sysroot_to_crate_graph(
493519
crate_graph: &mut CrateGraph,
494520
sysroot: &Sysroot,
495-
target: Option<&str>,
521+
rustc_cfg: Vec<CfgFlag>,
496522
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
497523
) -> (Vec<(CrateName, CrateId)>, Option<CrateId>) {
498524
let _p = profile::span("sysroot_to_crate_graph");
499525
let mut cfg_options = CfgOptions::default();
500-
cfg_options.extend(get_rustc_cfg_options(target));
526+
cfg_options.extend(rustc_cfg);
501527
let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot
502528
.crates()
503529
.filter_map(|krate| {
@@ -536,35 +562,6 @@ fn sysroot_to_crate_graph(
536562
(public_deps, libproc_macro)
537563
}
538564

539-
fn get_rustc_cfg_options(target: Option<&str>) -> Vec<CfgFlag> {
540-
let _p = profile::span("get_rustc_cfg_options");
541-
let mut res = Vec::new();
542-
543-
// Some nightly-only cfgs, which are required for stdlib
544-
res.push(CfgFlag::Atom("target_thread_local".into()));
545-
for &ty in ["8", "16", "32", "64", "cas", "ptr"].iter() {
546-
for &key in ["target_has_atomic", "target_has_atomic_load_store"].iter() {
547-
res.push(CfgFlag::KeyValue { key: key.to_string(), value: ty.into() });
548-
}
549-
}
550-
551-
let rustc_cfgs = {
552-
let mut cmd = Command::new(toolchain::rustc());
553-
cmd.args(&["--print", "cfg", "-O"]);
554-
if let Some(target) = target {
555-
cmd.args(&["--target", target]);
556-
}
557-
utf8_stdout(cmd)
558-
};
559-
560-
match rustc_cfgs {
561-
Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())),
562-
Err(e) => log::error!("failed to get rustc cfgs: {:#}", e),
563-
}
564-
565-
res
566-
}
567-
568565
fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
569566
if let Err(err) = graph.add_dep(from, name, to) {
570567
log::error!("{}", err)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub fn load_cargo(
3939
None
4040
};
4141

42-
let crate_graph = ws.to_crate_graph(None, proc_macro_client.as_ref(), &mut |path: &AbsPath| {
42+
let crate_graph = ws.to_crate_graph(proc_macro_client.as_ref(), &mut |path: &AbsPath| {
4343
let contents = loader.load_sync(path);
4444
let path = vfs::VfsPath::from(path.to_path_buf());
4545
vfs.set_file_contents(path.clone(), contents);

crates/rust-analyzer/src/reload.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,10 @@ impl GlobalState {
135135
)
136136
}
137137
LinkedProject::InlineJsonProject(it) => {
138-
project_model::ProjectWorkspace::load_inline(it.clone())
138+
project_model::ProjectWorkspace::load_inline(
139+
it.clone(),
140+
cargo_config.target.as_deref(),
141+
)
139142
}
140143
})
141144
.collect::<Vec<_>>();
@@ -253,11 +256,7 @@ impl GlobalState {
253256
res
254257
};
255258
for ws in workspaces.iter() {
256-
crate_graph.extend(ws.to_crate_graph(
257-
self.config.cargo().target.as_deref(),
258-
self.proc_macro_client.as_ref(),
259-
&mut load,
260-
));
259+
crate_graph.extend(ws.to_crate_graph(self.proc_macro_client.as_ref(), &mut load));
261260
}
262261

263262
crate_graph
@@ -289,9 +288,7 @@ impl GlobalState {
289288
.iter()
290289
.enumerate()
291290
.filter_map(|(id, w)| match w {
292-
ProjectWorkspace::Cargo { cargo, sysroot: _, rustc: _ } => {
293-
Some((id, cargo.workspace_root()))
294-
}
291+
ProjectWorkspace::Cargo { cargo, .. } => Some((id, cargo.workspace_root())),
295292
ProjectWorkspace::Json { project, .. } => {
296293
// Enable flychecks for json projects if a custom flycheck command was supplied
297294
// in the workspace configuration.

0 commit comments

Comments
 (0)