@@ -23,7 +23,7 @@ use crate::{
2323 project_json:: Crate ,
2424 rustc_cfg:: { self , RustcCfgConfig } ,
2525 sysroot:: SysrootCrate ,
26- target_data_layout, utf8_stdout, CargoConfig , CargoWorkspace , InvocationStrategy , ManifestPath ,
26+ target_data_layout, utf8_stdout, CargoConfig , CargoWorkspace , InvocationStrategy ,
2727 Package , ProjectJson , ProjectManifest , Sysroot , TargetData , TargetKind , WorkspaceBuildScripts ,
2828} ;
2929
@@ -53,14 +53,33 @@ 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 loading failed or a the
67+ fn loaded ( & self ) -> Option < & ( CargoWorkspace , WorkspaceBuildScripts ) > {
68+ match self {
69+ Self :: Opening => None ,
70+ Self :: Loaded ( res) => res. as_ref ( ) . ok ( ) ,
71+ }
72+ }
73+ }
74+
5675#[ derive( Clone ) ]
5776pub enum ProjectWorkspace {
5877 /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
5978 Cargo {
6079 cargo : CargoWorkspace ,
6180 build_scripts : WorkspaceBuildScripts ,
6281 sysroot : Result < Sysroot , Option < String > > ,
63- rustc : Result < ( CargoWorkspace , WorkspaceBuildScripts ) , Option < String > > ,
82+ rustc : RustcWorkspace ,
6483 /// Holds cfg flags for the current target. We get those by running
6584 /// `rustc --print cfg`.
6685 ///
@@ -119,7 +138,7 @@ impl fmt::Debug for ProjectWorkspace {
119138 . field ( "sysroot" , & sysroot. is_ok ( ) )
120139 . field (
121140 "n_rustc_compiler_crates" ,
122- & rustc. as_ref ( ) . map_or ( 0 , |( rc, _) | rc. packages ( ) . len ( ) ) ,
141+ & rustc. loaded ( ) . map_or ( 0 , |( rc, _) | rc. packages ( ) . len ( ) ) ,
123142 )
124143 . field ( "n_rustc_cfg" , & rustc_cfg. len ( ) )
125144 . field ( "n_cfg_overrides" , & cfg_overrides. len ( ) )
@@ -151,15 +170,17 @@ impl ProjectWorkspace {
151170 manifest : ProjectManifest ,
152171 config : & CargoConfig ,
153172 progress : & dyn Fn ( String ) ,
173+ opening_rustc_workspace : bool ,
154174 ) -> anyhow:: Result < ProjectWorkspace > {
155- ProjectWorkspace :: load_inner ( & manifest, config, progress)
175+ ProjectWorkspace :: load_inner ( & manifest, config, progress, opening_rustc_workspace )
156176 . with_context ( || format ! ( "Failed to load the project at {manifest}" ) )
157177 }
158178
159179 fn load_inner (
160180 manifest : & ProjectManifest ,
161181 config : & CargoConfig ,
162182 progress : & dyn Fn ( String ) ,
183+ opening_rustc_workspace : bool ,
163184 ) -> anyhow:: Result < ProjectWorkspace > {
164185 let version = |current_dir, cmd_path, prefix : & str | {
165186 let cargo_version = utf8_stdout ( {
@@ -236,48 +257,54 @@ impl ProjectWorkspace {
236257 tracing:: info!( workspace = %cargo_toml, src_root = %sysroot. src_root( ) , root = %sysroot. root( ) , "Using sysroot" ) ;
237258 }
238259
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) )
260+ let rustc = if opening_rustc_workspace {
261+ RustcWorkspace :: Opening
262+ } else {
263+ let rustc_dir = match & config. rustc_source {
264+ // `config.rustc_source == Some(Path(...))` while `!opening_rustc_workspace` should only occur if
265+ // `ManifestPath::try_from(rustc_dir)` failed in `fetch_workspaces`, so no need to attempt it here
266+ // again.
267+ Some ( RustLibSource :: Path ( path) ) => Err ( Some ( format ! ( "rustc source path is not absolute: {path}" ) ) ) ,
268+ Some ( RustLibSource :: Discover ) => {
269+ sysroot. as_ref ( ) . ok ( ) . and_then ( Sysroot :: discover_rustc_src) . ok_or_else (
270+ || Some ( format ! ( "Failed to discover rustc source for sysroot." ) ) ,
271+ )
269272 }
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- ) ) )
273+ None => Err ( None ) ,
274+ } ;
275+
276+ RustcWorkspace :: Loaded ( rustc_dir. and_then ( |rustc_dir| {
277+ tracing:: info!( workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source" ) ;
278+ match CargoWorkspace :: fetch_metadata (
279+ & rustc_dir,
280+ cargo_toml. parent ( ) ,
281+ & CargoConfig {
282+ features : crate :: CargoFeatures :: default ( ) ,
283+ ..config. clone ( )
284+ } ,
285+ progress,
286+ ) {
287+ Ok ( meta) => {
288+ let workspace = CargoWorkspace :: new ( meta) ;
289+ let buildscripts = WorkspaceBuildScripts :: rustc_crates (
290+ & workspace,
291+ cargo_toml. parent ( ) ,
292+ & config. extra_env ,
293+ ) ;
294+ Ok ( ( workspace, buildscripts) )
295+ }
296+ Err ( e) => {
297+ tracing:: error!(
298+ %e,
299+ "Failed to read Cargo metadata from rustc source at {rustc_dir}" ,
300+ ) ;
301+ Err ( Some ( format ! (
302+ "Failed to read Cargo metadata from rustc source at {rustc_dir}: {e}"
303+ ) ) )
304+ }
278305 }
279- }
280- } ) ;
306+ } ) )
307+ } ;
281308
282309 let rustc_cfg = rustc_cfg:: get (
283310 config. target . as_deref ( ) ,
@@ -564,7 +591,7 @@ impl ProjectWorkspace {
564591 PackageRoot { is_local, include, exclude }
565592 } )
566593 . chain ( mk_sysroot ( sysroot. as_ref ( ) , Some ( cargo. workspace_root ( ) ) ) )
567- . chain ( rustc. iter ( ) . flat_map ( |( rustc, _) | {
594+ . chain ( rustc. loaded ( ) . iter ( ) . flat_map ( |( rustc, _) | {
568595 rustc. packages ( ) . map ( move |krate| PackageRoot {
569596 is_local : false ,
570597 include : vec ! [ rustc[ krate] . manifest. parent( ) . to_path_buf( ) ] ,
@@ -592,7 +619,7 @@ impl ProjectWorkspace {
592619 sysroot_package_len + project. n_crates ( )
593620 }
594621 ProjectWorkspace :: Cargo { cargo, sysroot, rustc, .. } => {
595- let rustc_package_len = rustc. as_ref ( ) . map_or ( 0 , |( it, _) | it. packages ( ) . len ( ) ) ;
622+ let rustc_package_len = rustc. loaded ( ) . map_or ( 0 , |( it, _) | it. packages ( ) . len ( ) ) ;
596623 let sysroot_package_len = sysroot. as_ref ( ) . map_or ( 0 , |it| it. crates ( ) . len ( ) ) ;
597624 cargo. packages ( ) . len ( ) + sysroot_package_len + rustc_package_len
598625 }
@@ -607,6 +634,7 @@ impl ProjectWorkspace {
607634 & self ,
608635 load : & mut dyn FnMut ( & AbsPath ) -> Option < FileId > ,
609636 extra_env : & FxHashMap < String , String > ,
637+ opened_rustc_workspace : Option < ( & CargoWorkspace , & WorkspaceBuildScripts ) > ,
610638 ) -> ( CrateGraph , ProcMacroPaths ) {
611639 let _p = profile:: span ( "ProjectWorkspace::to_crate_graph" ) ;
612640
@@ -633,7 +661,10 @@ impl ProjectWorkspace {
633661 target_layout,
634662 } => cargo_to_crate_graph (
635663 load,
636- rustc. as_ref ( ) . ok ( ) ,
664+ match rustc {
665+ RustcWorkspace :: Opening => opened_rustc_workspace,
666+ RustcWorkspace :: Loaded ( res) => res. as_ref ( ) . ok ( ) . map ( |( a, b) | ( a, b) ) ,
667+ } ,
637668 cargo,
638669 sysroot. as_ref ( ) . ok ( ) ,
639670 rustc_cfg. clone ( ) ,
@@ -844,7 +875,7 @@ fn project_json_to_crate_graph(
844875
845876fn cargo_to_crate_graph (
846877 load : & mut dyn FnMut ( & AbsPath ) -> Option < FileId > ,
847- rustc : Option < & ( CargoWorkspace , WorkspaceBuildScripts ) > ,
878+ rustc : Option < ( & CargoWorkspace , & WorkspaceBuildScripts ) > ,
848879 cargo : & CargoWorkspace ,
849880 sysroot : Option < & Sysroot > ,
850881 rustc_cfg : Vec < CfgFlag > ,
@@ -1030,13 +1061,7 @@ fn cargo_to_crate_graph(
10301061 & pkg_crates,
10311062 & cfg_options,
10321063 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- } ,
1064+ rustc_build_scripts,
10401065 target_layout,
10411066 channel,
10421067 ) ;
0 commit comments