Skip to content

Commit d11c5b8

Browse files
authoredMar 7, 2025
Merge pull request rust-lang#19308 from Veykril/push-rnrxutwlvmly
Move loaded project MSRV back to 1.78, show notification for the warning
2 parents 02c9b7c + 5c6a124 commit d11c5b8

File tree

8 files changed

+1174
-23
lines changed

8 files changed

+1174
-23
lines changed
 

‎src/tools/rust-analyzer/crates/project-model/src/project_json.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ impl ProjectJson {
8686
/// * `manifest` - The path to the `rust-project.json`.
8787
/// * `base` - The path to the workspace root (i.e. the folder containing `rust-project.json`)
8888
/// * `data` - The parsed contents of `rust-project.json`, or project json that's passed via
89-
/// configuration.
89+
/// configuration.
9090
pub fn new(
9191
manifest: Option<ManifestPath>,
9292
base: &AbsPath,

‎src/tools/rust-analyzer/crates/project-model/src/sysroot.rs

+137
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub struct Sysroot {
3030
pub enum RustLibSrcWorkspace {
3131
Workspace(CargoWorkspace),
3232
Json(ProjectJson),
33+
Stitched(stitched::Stitched),
3334
Empty,
3435
}
3536

@@ -60,6 +61,7 @@ impl Sysroot {
6061
match &self.workspace {
6162
RustLibSrcWorkspace::Workspace(ws) => ws.packages().next().is_none(),
6263
RustLibSrcWorkspace::Json(project_json) => project_json.n_crates() == 0,
64+
RustLibSrcWorkspace::Stitched(stitched) => stitched.crates.is_empty(),
6365
RustLibSrcWorkspace::Empty => true,
6466
}
6567
}
@@ -72,6 +74,7 @@ impl Sysroot {
7274
match &self.workspace {
7375
RustLibSrcWorkspace::Workspace(ws) => ws.packages().count(),
7476
RustLibSrcWorkspace::Json(project_json) => project_json.n_crates(),
77+
RustLibSrcWorkspace::Stitched(stitched) => stitched.crates.len(),
7578
RustLibSrcWorkspace::Empty => 0,
7679
}
7780
}
@@ -197,6 +200,51 @@ impl Sysroot {
197200
return Some(loaded);
198201
}
199202
}
203+
tracing::debug!("Stitching sysroot library: {src_root}");
204+
205+
let mut stitched = stitched::Stitched { crates: Default::default() };
206+
207+
for path in stitched::SYSROOT_CRATES.trim().lines() {
208+
let name = path.split('/').next_back().unwrap();
209+
let root = [format!("{path}/src/lib.rs"), format!("lib{path}/lib.rs")]
210+
.into_iter()
211+
.map(|it| src_root.join(it))
212+
.filter_map(|it| ManifestPath::try_from(it).ok())
213+
.find(|it| fs::metadata(it).is_ok());
214+
215+
if let Some(root) = root {
216+
stitched.crates.alloc(stitched::RustLibSrcCrateData {
217+
name: name.into(),
218+
root,
219+
deps: Vec::new(),
220+
});
221+
}
222+
}
223+
224+
if let Some(std) = stitched.by_name("std") {
225+
for dep in stitched::STD_DEPS.trim().lines() {
226+
if let Some(dep) = stitched.by_name(dep) {
227+
stitched.crates[std].deps.push(dep)
228+
}
229+
}
230+
}
231+
232+
if let Some(alloc) = stitched.by_name("alloc") {
233+
for dep in stitched::ALLOC_DEPS.trim().lines() {
234+
if let Some(dep) = stitched.by_name(dep) {
235+
stitched.crates[alloc].deps.push(dep)
236+
}
237+
}
238+
}
239+
240+
if let Some(proc_macro) = stitched.by_name("proc_macro") {
241+
for dep in stitched::PROC_MACRO_DEPS.trim().lines() {
242+
if let Some(dep) = stitched.by_name(dep) {
243+
stitched.crates[proc_macro].deps.push(dep)
244+
}
245+
}
246+
}
247+
return Some(RustLibSrcWorkspace::Stitched(stitched));
200248
} else if let RustSourceWorkspaceConfig::Json(project_json) = sysroot_source_config {
201249
return Some(RustLibSrcWorkspace::Json(project_json.clone()));
202250
}
@@ -216,6 +264,7 @@ impl Sysroot {
216264
.crates()
217265
.filter_map(|(_, krate)| krate.display_name.clone())
218266
.any(|name| name.canonical_name().as_str() == "core"),
267+
RustLibSrcWorkspace::Stitched(stitched) => stitched.by_name("core").is_some(),
219268
RustLibSrcWorkspace::Empty => true,
220269
};
221270
if !has_core {
@@ -391,3 +440,91 @@ fn get_rust_lib_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
391440
None
392441
}
393442
}
443+
444+
// FIXME: Remove this, that will bump our project MSRV to 1.82
445+
pub(crate) mod stitched {
446+
use std::ops;
447+
448+
use base_db::CrateName;
449+
use la_arena::{Arena, Idx};
450+
451+
use crate::ManifestPath;
452+
453+
#[derive(Debug, Clone, Eq, PartialEq)]
454+
pub struct Stitched {
455+
pub(super) crates: Arena<RustLibSrcCrateData>,
456+
}
457+
458+
impl ops::Index<RustLibSrcCrate> for Stitched {
459+
type Output = RustLibSrcCrateData;
460+
fn index(&self, index: RustLibSrcCrate) -> &RustLibSrcCrateData {
461+
&self.crates[index]
462+
}
463+
}
464+
465+
impl Stitched {
466+
pub(crate) fn public_deps(
467+
&self,
468+
) -> impl Iterator<Item = (CrateName, RustLibSrcCrate, bool)> + '_ {
469+
// core is added as a dependency before std in order to
470+
// mimic rustcs dependency order
471+
[("core", true), ("alloc", false), ("std", true), ("test", false)]
472+
.into_iter()
473+
.filter_map(move |(name, prelude)| {
474+
Some((CrateName::new(name).unwrap(), self.by_name(name)?, prelude))
475+
})
476+
}
477+
478+
pub(crate) fn proc_macro(&self) -> Option<RustLibSrcCrate> {
479+
self.by_name("proc_macro")
480+
}
481+
482+
pub(crate) fn crates(&self) -> impl ExactSizeIterator<Item = RustLibSrcCrate> + '_ {
483+
self.crates.iter().map(|(id, _data)| id)
484+
}
485+
486+
pub(super) fn by_name(&self, name: &str) -> Option<RustLibSrcCrate> {
487+
let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?;
488+
Some(id)
489+
}
490+
}
491+
492+
pub(crate) type RustLibSrcCrate = Idx<RustLibSrcCrateData>;
493+
494+
#[derive(Debug, Clone, Eq, PartialEq)]
495+
pub(crate) struct RustLibSrcCrateData {
496+
pub(crate) name: String,
497+
pub(crate) root: ManifestPath,
498+
pub(crate) deps: Vec<RustLibSrcCrate>,
499+
}
500+
501+
pub(super) const SYSROOT_CRATES: &str = "
502+
alloc
503+
backtrace
504+
core
505+
panic_abort
506+
panic_unwind
507+
proc_macro
508+
profiler_builtins
509+
std
510+
stdarch/crates/std_detect
511+
test
512+
unwind";
513+
514+
pub(super) const ALLOC_DEPS: &str = "core";
515+
516+
pub(super) const STD_DEPS: &str = "
517+
alloc
518+
panic_unwind
519+
panic_abort
520+
core
521+
profiler_builtins
522+
unwind
523+
std_detect
524+
test";
525+
526+
// core is required for our builtin derives to work in the proc_macro lib currently
527+
pub(super) const PROC_MACRO_DEPS: &str = "
528+
std
529+
core";
530+
}

‎src/tools/rust-analyzer/crates/project-model/src/workspace.rs

+56
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,7 @@ impl ProjectWorkspace {
692692
exclude: krate.exclude.clone(),
693693
})
694694
.collect(),
695+
RustLibSrcWorkspace::Stitched(_) => vec![],
695696
RustLibSrcWorkspace::Empty => vec![],
696697
};
697698

@@ -1630,7 +1631,62 @@ fn sysroot_to_crate_graph(
16301631

16311632
extend_crate_graph_with_sysroot(crate_graph, cg, pm)
16321633
}
1634+
RustLibSrcWorkspace::Stitched(stitched) => {
1635+
let cfg_options = Arc::new({
1636+
let mut cfg_options = CfgOptions::default();
1637+
cfg_options.extend(rustc_cfg);
1638+
cfg_options.insert_atom(sym::debug_assertions.clone());
1639+
cfg_options.insert_atom(sym::miri.clone());
1640+
cfg_options
1641+
});
1642+
let sysroot_crates: FxHashMap<crate::sysroot::stitched::RustLibSrcCrate, CrateId> =
1643+
stitched
1644+
.crates()
1645+
.filter_map(|krate| {
1646+
let file_id = load(&stitched[krate].root)?;
1647+
1648+
let display_name =
1649+
CrateDisplayName::from_canonical_name(&stitched[krate].name);
1650+
let crate_id = crate_graph.add_crate_root(
1651+
file_id,
1652+
Edition::CURRENT_FIXME,
1653+
Some(display_name),
1654+
None,
1655+
cfg_options.clone(),
1656+
None,
1657+
Env::default(),
1658+
CrateOrigin::Lang(LangCrateOrigin::from(&*stitched[krate].name)),
1659+
false,
1660+
None,
1661+
);
1662+
Some((krate, crate_id))
1663+
})
1664+
.collect();
1665+
1666+
for from in stitched.crates() {
1667+
for &to in stitched[from].deps.iter() {
1668+
let name = CrateName::new(&stitched[to].name).unwrap();
1669+
if let (Some(&from), Some(&to)) =
1670+
(sysroot_crates.get(&from), sysroot_crates.get(&to))
1671+
{
1672+
add_dep(crate_graph, from, name, to);
1673+
}
1674+
}
1675+
}
16331676

1677+
let public_deps = SysrootPublicDeps {
1678+
deps: stitched
1679+
.public_deps()
1680+
.filter_map(|(name, idx, prelude)| {
1681+
Some((name, *sysroot_crates.get(&idx)?, prelude))
1682+
})
1683+
.collect::<Vec<_>>(),
1684+
};
1685+
1686+
let libproc_macro =
1687+
stitched.proc_macro().and_then(|it| sysroot_crates.get(&it).copied());
1688+
(public_deps, libproc_macro)
1689+
}
16341690
RustLibSrcWorkspace::Empty => (SysrootPublicDeps { deps: vec![] }, None),
16351691
}
16361692
}

‎src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt

+497-4
Large diffs are not rendered by default.

‎src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt

+453-1
Large diffs are not rendered by default.

‎src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs

+19
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,25 @@ impl GlobalState {
637637
}
638638
});
639639
}
640+
641+
pub(crate) fn check_workspaces_msrv(&self) -> impl Iterator<Item = String> + '_ {
642+
self.workspaces.iter().filter_map(|ws| {
643+
if let Some(toolchain) = &ws.toolchain {
644+
if *toolchain < crate::MINIMUM_SUPPORTED_TOOLCHAIN_VERSION {
645+
return Some(format!(
646+
"Workspace `{}` is using an outdated toolchain version `{}` but \
647+
rust-analyzer only supports `{}` and higher.\n\
648+
Consider using the rust-analyzer rustup component for your toolchain or
649+
upgrade your toolchain to a supported version.\n\n",
650+
ws.manifest_or_root(),
651+
toolchain,
652+
crate::MINIMUM_SUPPORTED_TOOLCHAIN_VERSION,
653+
));
654+
}
655+
}
656+
None
657+
})
658+
}
640659
}
641660

642661
impl Drop for GlobalState {

‎src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
/// Any toolchain less than this version will likely not work with rust-analyzer built from this revision.
1313
pub const MINIMUM_SUPPORTED_TOOLCHAIN_VERSION: semver::Version = semver::Version {
1414
major: 1,
15-
minor: 82,
15+
minor: 78,
1616
patch: 0,
1717
pre: semver::Prerelease::EMPTY,
1818
build: semver::BuildMetadata::EMPTY,

‎src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs

+10-16
Original file line numberDiff line numberDiff line change
@@ -178,26 +178,15 @@ impl GlobalState {
178178
}
179179

180180
if !self.workspaces.is_empty() {
181+
self.check_workspaces_msrv().for_each(|e| {
182+
status.health |= lsp_ext::Health::Warning;
183+
format_to!(message, "{e}");
184+
});
185+
181186
let proc_macro_clients =
182187
self.proc_macro_clients.iter().map(Some).chain(iter::repeat_with(|| None));
183188

184189
for (ws, proc_macro_client) in self.workspaces.iter().zip(proc_macro_clients) {
185-
if let Some(toolchain) = &ws.toolchain {
186-
if *toolchain < crate::MINIMUM_SUPPORTED_TOOLCHAIN_VERSION {
187-
status.health |= lsp_ext::Health::Warning;
188-
format_to!(
189-
message,
190-
"Workspace `{}` is using an outdated toolchain version `{}` but \
191-
rust-analyzer only supports `{}` and higher.\n\
192-
Consider using the rust-analyzer rustup component for your toolchain or
193-
upgrade your toolchain to a supported version.\n\n",
194-
ws.manifest_or_root(),
195-
toolchain,
196-
crate::MINIMUM_SUPPORTED_TOOLCHAIN_VERSION,
197-
);
198-
}
199-
}
200-
201190
if let ProjectWorkspaceKind::Cargo { error: Some(error), .. }
202191
| ProjectWorkspaceKind::DetachedFile {
203192
cargo: Some((_, _, Some(error))), ..
@@ -529,6 +518,11 @@ impl GlobalState {
529518
// we don't care about build-script results, they are stale.
530519
// FIXME: can we abort the build scripts here if they are already running?
531520
self.workspaces = Arc::new(workspaces);
521+
self.check_workspaces_msrv().for_each(|message| {
522+
self.send_notification::<lsp_types::notification::ShowMessage>(
523+
lsp_types::ShowMessageParams { typ: lsp_types::MessageType::WARNING, message },
524+
);
525+
});
532526

533527
if self.config.run_build_scripts(None) {
534528
self.build_deps_changed = false;

0 commit comments

Comments
 (0)
Please sign in to comment.