@@ -17,8 +17,9 @@ use std::{iter, mem};
17
17
18
18
use flycheck:: { FlycheckConfig , FlycheckHandle } ;
19
19
use hir:: { db:: DefDatabase , Change , ProcMacros } ;
20
+ use ide:: CrateId ;
20
21
use ide_db:: {
21
- base_db:: { salsa:: Durability , CrateGraph , ProcMacroPaths } ,
22
+ base_db:: { salsa:: Durability , CrateGraph , CrateOrigin , ProcMacroPaths , Version } ,
22
23
FxHashMap ,
23
24
} ;
24
25
use itertools:: Itertools ;
@@ -28,7 +29,7 @@ use project_model::{ProjectWorkspace, WorkspaceBuildScripts};
28
29
use rustc_hash:: FxHashSet ;
29
30
use stdx:: { format_to, thread:: ThreadIntent } ;
30
31
use triomphe:: Arc ;
31
- use vfs:: { AbsPath , ChangeKind } ;
32
+ use vfs:: { AbsPath , AbsPathBuf , ChangeKind } ;
32
33
33
34
use crate :: {
34
35
config:: { Config , FilesWatcher , LinkedProject } ,
@@ -532,7 +533,7 @@ impl GlobalState {
532
533
// deleted or created we trigger a reconstruction of the crate graph
533
534
let mut crate_graph_file_dependencies = FxHashSet :: default ( ) ;
534
535
535
- let mut load = |path : & AbsPath | {
536
+ let load = |path : & AbsPath | {
536
537
let _p = tracing:: span!( tracing:: Level :: DEBUG , "switch_workspaces::load" ) . entered ( ) ;
537
538
let vfs_path = vfs:: VfsPath :: from ( path. to_path_buf ( ) ) ;
538
539
crate_graph_file_dependencies. insert ( vfs_path. clone ( ) ) ;
@@ -547,56 +548,8 @@ impl GlobalState {
547
548
}
548
549
} ;
549
550
550
- let mut crate_graph = CrateGraph :: default ( ) ;
551
- let mut proc_macro_paths = Vec :: default ( ) ;
552
- let mut layouts = Vec :: default ( ) ;
553
- let mut toolchains = Vec :: default ( ) ;
554
- let e = Err ( Arc :: from ( "missing layout" ) ) ;
555
- for ws in & * * self . workspaces {
556
- let ( other, mut crate_proc_macros) =
557
- ws. to_crate_graph ( & mut load, self . config . extra_env ( ) ) ;
558
- let num_layouts = layouts. len ( ) ;
559
- let num_toolchains = toolchains. len ( ) ;
560
- let ( toolchain, layout) = match ws {
561
- ProjectWorkspace :: Cargo { toolchain, target_layout, .. }
562
- | ProjectWorkspace :: Json { toolchain, target_layout, .. } => {
563
- ( toolchain. clone ( ) , target_layout. clone ( ) )
564
- }
565
- ProjectWorkspace :: DetachedFiles { .. } => {
566
- ( None , Err ( "detached files have no layout" . into ( ) ) )
567
- }
568
- } ;
569
-
570
- let mapping = crate_graph. extend (
571
- other,
572
- & mut crate_proc_macros,
573
- |( cg_id, _cg_data) , ( _o_id, _o_data) | {
574
- // if the newly created crate graph's layout is equal to the crate of the merged graph, then
575
- // we can merge the crates.
576
- layouts[ cg_id. into_raw ( ) . into_u32 ( ) as usize ] == layout
577
- && toolchains[ cg_id. into_raw ( ) . into_u32 ( ) as usize ] == toolchain
578
- } ,
579
- ) ;
580
- // Populate the side tables for the newly merged crates
581
- mapping. values ( ) . for_each ( |val| {
582
- let idx = val. into_raw ( ) . into_u32 ( ) as usize ;
583
- // we only need to consider crates that were not merged and remapped, as the
584
- // ones that were remapped already have the correct layout and toolchain
585
- if idx >= num_layouts {
586
- if layouts. len ( ) <= idx {
587
- layouts. resize ( idx + 1 , e. clone ( ) ) ;
588
- }
589
- layouts[ idx] = layout. clone ( ) ;
590
- }
591
- if idx >= num_toolchains {
592
- if toolchains. len ( ) <= idx {
593
- toolchains. resize ( idx + 1 , None ) ;
594
- }
595
- toolchains[ idx] = toolchain. clone ( ) ;
596
- }
597
- } ) ;
598
- proc_macro_paths. push ( crate_proc_macros) ;
599
- }
551
+ let ( crate_graph, proc_macro_paths, layouts, toolchains) =
552
+ ws_to_crate_graph ( & self . workspaces , self . config . extra_env ( ) , load) ;
600
553
601
554
let mut change = Change :: new ( ) ;
602
555
if self . config . expand_proc_macros ( ) {
@@ -609,6 +562,8 @@ impl GlobalState {
609
562
self . fetch_proc_macros_queue . request_op ( cause, proc_macro_paths) ;
610
563
}
611
564
change. set_crate_graph ( crate_graph) ;
565
+ change. set_target_data_layouts ( layouts) ;
566
+ change. set_toolchains ( toolchains) ;
612
567
self . analysis_host . apply_change ( change) ;
613
568
self . crate_graph_file_dependencies = crate_graph_file_dependencies;
614
569
}
@@ -719,6 +674,97 @@ impl GlobalState {
719
674
}
720
675
}
721
676
677
+ // FIXME: Move this into load-cargo?
678
+ pub fn ws_to_crate_graph (
679
+ workspaces : & [ ProjectWorkspace ] ,
680
+ extra_env : & FxHashMap < String , String > ,
681
+ mut load : impl FnMut ( & AbsPath ) -> Option < vfs:: FileId > ,
682
+ ) -> (
683
+ CrateGraph ,
684
+ Vec < FxHashMap < CrateId , Result < ( Option < String > , AbsPathBuf ) , String > > > ,
685
+ Vec < Result < Arc < str > , Arc < str > > > ,
686
+ Vec < Option < Version > > ,
687
+ ) {
688
+ let mut crate_graph = CrateGraph :: default ( ) ;
689
+ let mut proc_macro_paths = Vec :: default ( ) ;
690
+ let mut layouts = Vec :: default ( ) ;
691
+ let mut toolchains = Vec :: default ( ) ;
692
+ let e = Err ( Arc :: from ( "missing layout" ) ) ;
693
+ for ws in workspaces {
694
+ let ( other, mut crate_proc_macros) = ws. to_crate_graph ( & mut load, extra_env) ;
695
+ let num_layouts = layouts. len ( ) ;
696
+ let num_toolchains = toolchains. len ( ) ;
697
+ let ( toolchain, layout) = match ws {
698
+ ProjectWorkspace :: Cargo { toolchain, target_layout, .. }
699
+ | ProjectWorkspace :: Json { toolchain, target_layout, .. } => {
700
+ ( toolchain. clone ( ) , target_layout. clone ( ) )
701
+ }
702
+ ProjectWorkspace :: DetachedFiles { .. } => {
703
+ ( None , Err ( "detached files have no layout" . into ( ) ) )
704
+ }
705
+ } ;
706
+
707
+ let mapping = crate_graph. extend (
708
+ other,
709
+ & mut crate_proc_macros,
710
+ |( cg_id, _cg_data) , ( _o_id, _o_data) | {
711
+ // if the newly created crate graph's layout is equal to the crate of the merged graph, then
712
+ // we can merge the crates.
713
+ let id = cg_id. into_raw ( ) . into_u32 ( ) as usize ;
714
+ if layouts[ id] == layout && toolchains[ id] == toolchain {
715
+ let ( res, update) = match ( & _cg_data. origin , & _o_data. origin ) {
716
+ ( a, b)
717
+ if a == b && _cg_data. eq_ignoring_origin_and_deps ( _o_data, false ) =>
718
+ {
719
+ ( true , false )
720
+ }
721
+ ( a @ CrateOrigin :: Local { .. } , CrateOrigin :: Library { .. } )
722
+ | ( a @ CrateOrigin :: Library { .. } , CrateOrigin :: Local { .. } )
723
+ if _cg_data. eq_ignoring_origin_and_deps ( _o_data, true ) =>
724
+ {
725
+ // If the origins differ, check if the two crates are equal without
726
+ // considering the dev dependencies, if they are, they most likely are in
727
+ // different loaded workspaces which may cause issues. We keep the local
728
+ // version and discard the library one as the local version may have
729
+ // dev-dependencies that we want to keep resolving. See #15656 for more
730
+ // information.
731
+ ( true , !a. is_local ( ) )
732
+ }
733
+ ( _, _) => ( false , false ) ,
734
+ } ;
735
+ if res && update {
736
+ _cg_data. origin = _o_data. origin . clone ( ) ;
737
+ _cg_data. dependencies = _o_data. dependencies . clone ( ) ;
738
+ }
739
+ res
740
+ } else {
741
+ false
742
+ }
743
+ } ,
744
+ ) ;
745
+ // Populate the side tables for the newly merged crates
746
+ mapping. values ( ) . for_each ( |val| {
747
+ let idx = val. into_raw ( ) . into_u32 ( ) as usize ;
748
+ // we only need to consider crates that were not merged and remapped, as the
749
+ // ones that were remapped already have the correct layout and toolchain
750
+ if idx >= num_layouts {
751
+ if layouts. len ( ) <= idx {
752
+ layouts. resize ( idx + 1 , e. clone ( ) ) ;
753
+ }
754
+ layouts[ idx] = layout. clone ( ) ;
755
+ }
756
+ if idx >= num_toolchains {
757
+ if toolchains. len ( ) <= idx {
758
+ toolchains. resize ( idx + 1 , None ) ;
759
+ }
760
+ toolchains[ idx] = toolchain. clone ( ) ;
761
+ }
762
+ } ) ;
763
+ proc_macro_paths. push ( crate_proc_macros) ;
764
+ }
765
+ ( crate_graph, proc_macro_paths, layouts, toolchains)
766
+ }
767
+
722
768
pub ( crate ) fn should_refresh_for_change ( path : & AbsPath , change_kind : ChangeKind ) -> bool {
723
769
const IMPLICIT_TARGET_FILES : & [ & str ] = & [ "build.rs" , "src/main.rs" , "src/lib.rs" ] ;
724
770
const IMPLICIT_TARGET_DIRS : & [ & str ] = & [ "src/bin" , "examples" , "tests" , "benches" ] ;
0 commit comments