@@ -23,7 +23,7 @@ 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 ,
26
+ target_data_layout, utf8_stdout, CargoConfig , CargoWorkspace , InvocationStrategy ,
27
27
Package , ProjectJson , ProjectManifest , Sysroot , TargetData , TargetKind , WorkspaceBuildScripts ,
28
28
} ;
29
29
@@ -53,14 +53,33 @@ 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 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
+
56
75
#[ derive( Clone ) ]
57
76
pub enum ProjectWorkspace {
58
77
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
59
78
Cargo {
60
79
cargo : CargoWorkspace ,
61
80
build_scripts : WorkspaceBuildScripts ,
62
81
sysroot : Result < Sysroot , Option < String > > ,
63
- rustc : Result < ( CargoWorkspace , WorkspaceBuildScripts ) , Option < String > > ,
82
+ rustc : RustcWorkspace ,
64
83
/// Holds cfg flags for the current target. We get those by running
65
84
/// `rustc --print cfg`.
66
85
///
@@ -119,7 +138,7 @@ impl fmt::Debug for ProjectWorkspace {
119
138
. field ( "sysroot" , & sysroot. is_ok ( ) )
120
139
. field (
121
140
"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 ( ) ) ,
123
142
)
124
143
. field ( "n_rustc_cfg" , & rustc_cfg. len ( ) )
125
144
. field ( "n_cfg_overrides" , & cfg_overrides. len ( ) )
@@ -151,15 +170,17 @@ impl ProjectWorkspace {
151
170
manifest : ProjectManifest ,
152
171
config : & CargoConfig ,
153
172
progress : & dyn Fn ( String ) ,
173
+ opening_rustc_workspace : bool ,
154
174
) -> anyhow:: Result < ProjectWorkspace > {
155
- ProjectWorkspace :: load_inner ( & manifest, config, progress)
175
+ ProjectWorkspace :: load_inner ( & manifest, config, progress, opening_rustc_workspace )
156
176
. with_context ( || format ! ( "Failed to load the project at {manifest}" ) )
157
177
}
158
178
159
179
fn load_inner (
160
180
manifest : & ProjectManifest ,
161
181
config : & CargoConfig ,
162
182
progress : & dyn Fn ( String ) ,
183
+ opening_rustc_workspace : bool ,
163
184
) -> anyhow:: Result < ProjectWorkspace > {
164
185
let version = |current_dir, cmd_path, prefix : & str | {
165
186
let cargo_version = utf8_stdout ( {
@@ -236,48 +257,54 @@ impl ProjectWorkspace {
236
257
tracing:: info!( workspace = %cargo_toml, src_root = %sysroot. src_root( ) , root = %sysroot. root( ) , "Using sysroot" ) ;
237
258
}
238
259
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
+ )
269
272
}
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
+ }
278
305
}
279
- }
280
- } ) ;
306
+ } ) )
307
+ } ;
281
308
282
309
let rustc_cfg = rustc_cfg:: get (
283
310
config. target . as_deref ( ) ,
@@ -564,7 +591,7 @@ impl ProjectWorkspace {
564
591
PackageRoot { is_local, include, exclude }
565
592
} )
566
593
. 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, _) | {
568
595
rustc. packages ( ) . map ( move |krate| PackageRoot {
569
596
is_local : false ,
570
597
include : vec ! [ rustc[ krate] . manifest. parent( ) . to_path_buf( ) ] ,
@@ -592,7 +619,7 @@ impl ProjectWorkspace {
592
619
sysroot_package_len + project. n_crates ( )
593
620
}
594
621
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 ( ) ) ;
596
623
let sysroot_package_len = sysroot. as_ref ( ) . map_or ( 0 , |it| it. crates ( ) . len ( ) ) ;
597
624
cargo. packages ( ) . len ( ) + sysroot_package_len + rustc_package_len
598
625
}
@@ -607,6 +634,7 @@ impl ProjectWorkspace {
607
634
& self ,
608
635
load : & mut dyn FnMut ( & AbsPath ) -> Option < FileId > ,
609
636
extra_env : & FxHashMap < String , String > ,
637
+ opened_rustc_workspace : Option < ( & CargoWorkspace , & WorkspaceBuildScripts ) > ,
610
638
) -> ( CrateGraph , ProcMacroPaths ) {
611
639
let _p = profile:: span ( "ProjectWorkspace::to_crate_graph" ) ;
612
640
@@ -633,7 +661,10 @@ impl ProjectWorkspace {
633
661
target_layout,
634
662
} => cargo_to_crate_graph (
635
663
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
+ } ,
637
668
cargo,
638
669
sysroot. as_ref ( ) . ok ( ) ,
639
670
rustc_cfg. clone ( ) ,
@@ -844,7 +875,7 @@ fn project_json_to_crate_graph(
844
875
845
876
fn cargo_to_crate_graph (
846
877
load : & mut dyn FnMut ( & AbsPath ) -> Option < FileId > ,
847
- rustc : Option < & ( CargoWorkspace , WorkspaceBuildScripts ) > ,
878
+ rustc : Option < ( & CargoWorkspace , & WorkspaceBuildScripts ) > ,
848
879
cargo : & CargoWorkspace ,
849
880
sysroot : Option < & Sysroot > ,
850
881
rustc_cfg : Vec < CfgFlag > ,
@@ -1030,13 +1061,7 @@ fn cargo_to_crate_graph(
1030
1061
& pkg_crates,
1031
1062
& cfg_options,
1032
1063
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,
1040
1065
target_layout,
1041
1066
channel,
1042
1067
) ;
0 commit comments