@@ -23,8 +23,8 @@ use crate::{
23
23
project_json:: Crate ,
24
24
rustc_cfg:: { self , RustcCfgConfig } ,
25
25
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 ,
28
28
} ;
29
29
30
30
/// A set of cfg-overrides per crate.
@@ -53,14 +53,34 @@ pub struct PackageRoot {
53
53
pub exclude : Vec < AbsPathBuf > ,
54
54
}
55
55
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
+
56
76
#[ derive( Clone ) ]
57
77
pub enum ProjectWorkspace {
58
78
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
59
79
Cargo {
60
80
cargo : CargoWorkspace ,
61
81
build_scripts : WorkspaceBuildScripts ,
62
82
sysroot : Result < Sysroot , Option < String > > ,
63
- rustc : Result < ( CargoWorkspace , WorkspaceBuildScripts ) , Option < String > > ,
83
+ rustc : RustcWorkspace ,
64
84
/// Holds cfg flags for the current target. We get those by running
65
85
/// `rustc --print cfg`.
66
86
///
@@ -119,7 +139,7 @@ impl fmt::Debug for ProjectWorkspace {
119
139
. field ( "sysroot" , & sysroot. is_ok ( ) )
120
140
. field (
121
141
"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 ( ) ) ,
123
143
)
124
144
. field ( "n_rustc_cfg" , & rustc_cfg. len ( ) )
125
145
. field ( "n_cfg_overrides" , & cfg_overrides. len ( ) )
@@ -151,15 +171,17 @@ impl ProjectWorkspace {
151
171
manifest : ProjectManifest ,
152
172
config : & CargoConfig ,
153
173
progress : & dyn Fn ( String ) ,
174
+ opening_rustc_workspace : bool ,
154
175
) -> anyhow:: Result < ProjectWorkspace > {
155
- ProjectWorkspace :: load_inner ( & manifest, config, progress)
176
+ ProjectWorkspace :: load_inner ( & manifest, config, progress, opening_rustc_workspace )
156
177
. with_context ( || format ! ( "Failed to load the project at {manifest}" ) )
157
178
}
158
179
159
180
fn load_inner (
160
181
manifest : & ProjectManifest ,
161
182
config : & CargoConfig ,
162
183
progress : & dyn Fn ( String ) ,
184
+ opening_rustc_workspace : bool ,
163
185
) -> anyhow:: Result < ProjectWorkspace > {
164
186
let version = |current_dir, cmd_path, prefix : & str | {
165
187
let cargo_version = utf8_stdout ( {
@@ -236,48 +258,56 @@ impl ProjectWorkspace {
236
258
tracing:: info!( workspace = %cargo_toml, src_root = %sysroot. src_root( ) , root = %sysroot. root( ) , "Using sysroot" ) ;
237
259
}
238
260
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}" ) ) )
269
270
}
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
+ )
278
275
}
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
+ } ;
281
311
282
312
let rustc_cfg = rustc_cfg:: get (
283
313
config. target . as_deref ( ) ,
@@ -564,7 +594,7 @@ impl ProjectWorkspace {
564
594
PackageRoot { is_local, include, exclude }
565
595
} )
566
596
. 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, _) | {
568
598
rustc. packages ( ) . map ( move |krate| PackageRoot {
569
599
is_local : false ,
570
600
include : vec ! [ rustc[ krate] . manifest. parent( ) . to_path_buf( ) ] ,
@@ -592,7 +622,7 @@ impl ProjectWorkspace {
592
622
sysroot_package_len + project. n_crates ( )
593
623
}
594
624
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 ( ) ) ;
596
626
let sysroot_package_len = sysroot. as_ref ( ) . map_or ( 0 , |it| it. crates ( ) . len ( ) ) ;
597
627
cargo. packages ( ) . len ( ) + sysroot_package_len + rustc_package_len
598
628
}
@@ -607,6 +637,7 @@ impl ProjectWorkspace {
607
637
& self ,
608
638
load : & mut dyn FnMut ( & AbsPath ) -> Option < FileId > ,
609
639
extra_env : & FxHashMap < String , String > ,
640
+ opened_rustc_workspace : Option < ( & CargoWorkspace , & WorkspaceBuildScripts ) > ,
610
641
) -> ( CrateGraph , ProcMacroPaths ) {
611
642
let _p = profile:: span ( "ProjectWorkspace::to_crate_graph" ) ;
612
643
@@ -633,7 +664,10 @@ impl ProjectWorkspace {
633
664
target_layout,
634
665
} => cargo_to_crate_graph (
635
666
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
+ } ,
637
671
cargo,
638
672
sysroot. as_ref ( ) . ok ( ) ,
639
673
rustc_cfg. clone ( ) ,
@@ -844,7 +878,7 @@ fn project_json_to_crate_graph(
844
878
845
879
fn cargo_to_crate_graph (
846
880
load : & mut dyn FnMut ( & AbsPath ) -> Option < FileId > ,
847
- rustc : Option < & ( CargoWorkspace , WorkspaceBuildScripts ) > ,
881
+ rustc : Option < ( & CargoWorkspace , & WorkspaceBuildScripts ) > ,
848
882
cargo : & CargoWorkspace ,
849
883
sysroot : Option < & Sysroot > ,
850
884
rustc_cfg : Vec < CfgFlag > ,
@@ -1030,13 +1064,7 @@ fn cargo_to_crate_graph(
1030
1064
& pkg_crates,
1031
1065
& cfg_options,
1032
1066
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,
1040
1068
target_layout,
1041
1069
channel,
1042
1070
) ;
0 commit comments