@@ -23,8 +23,8 @@ use crate::{
2323 project_json:: Crate ,
2424 rustc_cfg:: { self , RustcCfgConfig } ,
2525 sysroot:: SysrootCrate ,
26- target_data_layout, utf8_stdout, CargoConfig , CargoWorkspace , InvocationStrategy , ManifestPath ,
27- Package , ProjectJson , ProjectManifest , Sysroot , TargetData , TargetKind , WorkspaceBuildScripts ,
26+ target_data_layout, utf8_stdout, CargoConfig , CargoWorkspace , InvocationStrategy , Package ,
27+ ProjectJson , ProjectManifest , Sysroot , TargetData , TargetKind , WorkspaceBuildScripts ,
2828} ;
2929
3030/// A set of cfg-overrides per crate.
@@ -53,14 +53,34 @@ pub struct PackageRoot {
5353 pub exclude : Vec < AbsPathBuf > ,
5454}
5555
56+ #[ derive( Clone , PartialEq ) ]
57+ pub enum RustcWorkspace {
58+ /// A globally-configured rustc source location is being opened as a rust-analyzer workspace
59+ Opening ,
60+ /// The rustc source is loaded, e.g. from sysroot, but is not a rust-analyzer workspace
61+ Loaded ( Result < ( CargoWorkspace , WorkspaceBuildScripts ) , Option < String > > ) ,
62+ }
63+
64+ impl RustcWorkspace {
65+ /// Returns the loaded `CargoWorkspace` of the rustc source.
66+ /// Will be `None` if either the rustc source is opened as a rust-analyzer workspace
67+ /// or its loading failed.
68+ fn loaded ( & self ) -> Option < & ( CargoWorkspace , WorkspaceBuildScripts ) > {
69+ match self {
70+ Self :: Opening => None ,
71+ Self :: Loaded ( res) => res. as_ref ( ) . ok ( ) ,
72+ }
73+ }
74+ }
75+
5676#[ derive( Clone ) ]
5777pub enum ProjectWorkspace {
5878 /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
5979 Cargo {
6080 cargo : CargoWorkspace ,
6181 build_scripts : WorkspaceBuildScripts ,
6282 sysroot : Result < Sysroot , Option < String > > ,
63- rustc : Result < ( CargoWorkspace , WorkspaceBuildScripts ) , Option < String > > ,
83+ rustc : RustcWorkspace ,
6484 /// Holds cfg flags for the current target. We get those by running
6585 /// `rustc --print cfg`.
6686 ///
@@ -119,7 +139,7 @@ impl fmt::Debug for ProjectWorkspace {
119139 . field ( "sysroot" , & sysroot. is_ok ( ) )
120140 . field (
121141 "n_rustc_compiler_crates" ,
122- & rustc. as_ref ( ) . map_or ( 0 , |( rc, _) | rc. packages ( ) . len ( ) ) ,
142+ & rustc. loaded ( ) . map_or ( 0 , |( rc, _) | rc. packages ( ) . len ( ) ) ,
123143 )
124144 . field ( "n_rustc_cfg" , & rustc_cfg. len ( ) )
125145 . field ( "n_cfg_overrides" , & cfg_overrides. len ( ) )
@@ -151,15 +171,17 @@ impl ProjectWorkspace {
151171 manifest : ProjectManifest ,
152172 config : & CargoConfig ,
153173 progress : & dyn Fn ( String ) ,
174+ opening_rustc_workspace : bool ,
154175 ) -> anyhow:: Result < ProjectWorkspace > {
155- ProjectWorkspace :: load_inner ( & manifest, config, progress)
176+ ProjectWorkspace :: load_inner ( & manifest, config, progress, opening_rustc_workspace )
156177 . with_context ( || format ! ( "Failed to load the project at {manifest}" ) )
157178 }
158179
159180 fn load_inner (
160181 manifest : & ProjectManifest ,
161182 config : & CargoConfig ,
162183 progress : & dyn Fn ( String ) ,
184+ opening_rustc_workspace : bool ,
163185 ) -> anyhow:: Result < ProjectWorkspace > {
164186 let version = |current_dir, cmd_path, prefix : & str | {
165187 let cargo_version = utf8_stdout ( {
@@ -236,48 +258,56 @@ impl ProjectWorkspace {
236258 tracing:: info!( workspace = %cargo_toml, src_root = %sysroot. src_root( ) , root = %sysroot. root( ) , "Using sysroot" ) ;
237259 }
238260
239- let rustc_dir = match & config. rustc_source {
240- Some ( RustLibSource :: Path ( path) ) => ManifestPath :: try_from ( path. clone ( ) )
241- . map_err ( |p| Some ( format ! ( "rustc source path is not absolute: {p}" ) ) ) ,
242- Some ( RustLibSource :: Discover ) => {
243- sysroot. as_ref ( ) . ok ( ) . and_then ( Sysroot :: discover_rustc_src) . ok_or_else (
244- || Some ( format ! ( "Failed to discover rustc source for sysroot." ) ) ,
245- )
246- }
247- None => Err ( None ) ,
248- } ;
249-
250- let rustc = rustc_dir. and_then ( |rustc_dir| {
251- tracing:: info!( workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source" ) ;
252- match CargoWorkspace :: fetch_metadata (
253- & rustc_dir,
254- cargo_toml. parent ( ) ,
255- & CargoConfig {
256- features : crate :: CargoFeatures :: default ( ) ,
257- ..config. clone ( )
258- } ,
259- progress,
260- ) {
261- Ok ( meta) => {
262- let workspace = CargoWorkspace :: new ( meta) ;
263- let buildscripts = WorkspaceBuildScripts :: rustc_crates (
264- & workspace,
265- cargo_toml. parent ( ) ,
266- & config. extra_env ,
267- ) ;
268- Ok ( ( workspace, buildscripts) )
261+ let rustc = if opening_rustc_workspace {
262+ RustcWorkspace :: Opening
263+ } else {
264+ let rustc_dir = match & config. rustc_source {
265+ // `config.rustc_source == Some(Path(...))` while `!opening_rustc_workspace` should only occur if
266+ // `ManifestPath::try_from(rustc_dir)` failed in `fetch_workspaces`, so no need to attempt it here
267+ // again.
268+ Some ( RustLibSource :: Path ( path) ) => {
269+ Err ( Some ( format ! ( "rustc source path is not absolute: {path}" ) ) )
269270 }
270- Err ( e) => {
271- tracing:: error!(
272- %e,
273- "Failed to read Cargo metadata from rustc source at {rustc_dir}" ,
274- ) ;
275- Err ( Some ( format ! (
276- "Failed to read Cargo metadata from rustc source at {rustc_dir}: {e}"
277- ) ) )
271+ Some ( RustLibSource :: Discover ) => {
272+ sysroot. as_ref ( ) . ok ( ) . and_then ( Sysroot :: discover_rustc_src) . ok_or_else (
273+ || Some ( format ! ( "Failed to discover rustc source for sysroot." ) ) ,
274+ )
278275 }
279- }
280- } ) ;
276+ None => Err ( None ) ,
277+ } ;
278+
279+ RustcWorkspace :: Loaded ( rustc_dir. and_then ( |rustc_dir| {
280+ tracing:: info!( workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source" ) ;
281+ match CargoWorkspace :: fetch_metadata (
282+ & rustc_dir,
283+ cargo_toml. parent ( ) ,
284+ & CargoConfig {
285+ features : crate :: CargoFeatures :: default ( ) ,
286+ ..config. clone ( )
287+ } ,
288+ progress,
289+ ) {
290+ Ok ( meta) => {
291+ let workspace = CargoWorkspace :: new ( meta) ;
292+ let buildscripts = WorkspaceBuildScripts :: rustc_crates (
293+ & workspace,
294+ cargo_toml. parent ( ) ,
295+ & config. extra_env ,
296+ ) ;
297+ Ok ( ( workspace, buildscripts) )
298+ }
299+ Err ( e) => {
300+ tracing:: error!(
301+ %e,
302+ "Failed to read Cargo metadata from rustc source at {rustc_dir}" ,
303+ ) ;
304+ Err ( Some ( format ! (
305+ "Failed to read Cargo metadata from rustc source at {rustc_dir}: {e}"
306+ ) ) )
307+ }
308+ }
309+ } ) )
310+ } ;
281311
282312 let rustc_cfg = rustc_cfg:: get (
283313 config. target . as_deref ( ) ,
@@ -564,7 +594,7 @@ impl ProjectWorkspace {
564594 PackageRoot { is_local, include, exclude }
565595 } )
566596 . chain ( mk_sysroot ( sysroot. as_ref ( ) , Some ( cargo. workspace_root ( ) ) ) )
567- . chain ( rustc. iter ( ) . flat_map ( |( rustc, _) | {
597+ . chain ( rustc. loaded ( ) . iter ( ) . flat_map ( |( rustc, _) | {
568598 rustc. packages ( ) . map ( move |krate| PackageRoot {
569599 is_local : false ,
570600 include : vec ! [ rustc[ krate] . manifest. parent( ) . to_path_buf( ) ] ,
@@ -592,7 +622,7 @@ impl ProjectWorkspace {
592622 sysroot_package_len + project. n_crates ( )
593623 }
594624 ProjectWorkspace :: Cargo { cargo, sysroot, rustc, .. } => {
595- let rustc_package_len = rustc. as_ref ( ) . map_or ( 0 , |( it, _) | it. packages ( ) . len ( ) ) ;
625+ let rustc_package_len = rustc. loaded ( ) . map_or ( 0 , |( it, _) | it. packages ( ) . len ( ) ) ;
596626 let sysroot_package_len = sysroot. as_ref ( ) . map_or ( 0 , |it| it. crates ( ) . len ( ) ) ;
597627 cargo. packages ( ) . len ( ) + sysroot_package_len + rustc_package_len
598628 }
@@ -607,6 +637,7 @@ impl ProjectWorkspace {
607637 & self ,
608638 load : & mut dyn FnMut ( & AbsPath ) -> Option < FileId > ,
609639 extra_env : & FxHashMap < String , String > ,
640+ opened_rustc_workspace : Option < ( & CargoWorkspace , & WorkspaceBuildScripts ) > ,
610641 ) -> ( CrateGraph , ProcMacroPaths ) {
611642 let _p = profile:: span ( "ProjectWorkspace::to_crate_graph" ) ;
612643
@@ -633,7 +664,10 @@ impl ProjectWorkspace {
633664 target_layout,
634665 } => cargo_to_crate_graph (
635666 load,
636- rustc. as_ref ( ) . ok ( ) ,
667+ match rustc {
668+ RustcWorkspace :: Opening => opened_rustc_workspace,
669+ RustcWorkspace :: Loaded ( res) => res. as_ref ( ) . ok ( ) . map ( |( a, b) | ( a, b) ) ,
670+ } ,
637671 cargo,
638672 sysroot. as_ref ( ) . ok ( ) ,
639673 rustc_cfg. clone ( ) ,
@@ -844,7 +878,7 @@ fn project_json_to_crate_graph(
844878
845879fn cargo_to_crate_graph (
846880 load : & mut dyn FnMut ( & AbsPath ) -> Option < FileId > ,
847- rustc : Option < & ( CargoWorkspace , WorkspaceBuildScripts ) > ,
881+ rustc : Option < ( & CargoWorkspace , & WorkspaceBuildScripts ) > ,
848882 cargo : & CargoWorkspace ,
849883 sysroot : Option < & Sysroot > ,
850884 rustc_cfg : Vec < CfgFlag > ,
@@ -1030,13 +1064,7 @@ fn cargo_to_crate_graph(
10301064 & pkg_crates,
10311065 & cfg_options,
10321066 override_cfg,
1033- if rustc_workspace. workspace_root ( ) == cargo. workspace_root ( ) {
1034- // the rustc workspace does not use the installed toolchain's proc-macro server
1035- // so we need to make sure we don't use the pre compiled proc-macros there either
1036- build_scripts
1037- } else {
1038- rustc_build_scripts
1039- } ,
1067+ rustc_build_scripts,
10401068 target_layout,
10411069 channel,
10421070 ) ;
0 commit comments