@@ -1004,69 +1004,57 @@ fn find_candidate(
1004
1004
}
1005
1005
1006
1006
fn check_cycles ( resolve : & Resolve ) -> CargoResult < ( ) > {
1007
- // Create a simple graph representation alternative of `resolve` which has
1008
- // only the edges we care about. Note that `BTree*` is used to produce
1009
- // deterministic error messages here. Also note that the main reason for
1010
- // this copy of the resolve graph is to avoid edges between a crate and its
1011
- // dev-dependency since that doesn't count for cycles.
1012
- let mut graph = BTreeMap :: new ( ) ;
1013
- for id in resolve. iter ( ) {
1014
- let map = graph. entry ( id) . or_insert_with ( BTreeMap :: new) ;
1015
- for ( dep_id, listings) in resolve. deps_not_replaced ( id) {
1016
- let transitive_dep = listings. iter ( ) . find ( |d| d. is_transitive ( ) ) ;
1017
-
1018
- if let Some ( transitive_dep) = transitive_dep. cloned ( ) {
1019
- map. insert ( dep_id, transitive_dep. clone ( ) ) ;
1020
- resolve
1021
- . replacement ( dep_id)
1022
- . map ( |p| map. insert ( p, transitive_dep) ) ;
1023
- }
1024
- }
1025
- }
1026
-
1027
- // After we have the `graph` that we care about, perform a simple cycle
1028
- // check by visiting all nodes. We visit each node at most once and we keep
1007
+ // Perform a simple cycle check by visiting all nodes.
1008
+ // We visit each node at most once and we keep
1029
1009
// track of the path through the graph as we walk it. If we walk onto the
1030
1010
// same node twice that's a cycle.
1031
- let mut checked = HashSet :: new ( ) ;
1032
- let mut path = Vec :: new ( ) ;
1033
- let mut visited = HashSet :: new ( ) ;
1034
- for pkg in graph . keys ( ) {
1035
- if !checked. contains ( pkg) {
1036
- visit ( & graph , * pkg, & mut visited, & mut path, & mut checked) ?
1011
+ let mut checked = HashSet :: with_capacity ( resolve . len ( ) ) ;
1012
+ let mut path = Vec :: with_capacity ( 4 ) ;
1013
+ let mut visited = HashSet :: with_capacity ( 4 ) ;
1014
+ for pkg in resolve . iter ( ) {
1015
+ if !checked. contains ( & pkg) {
1016
+ visit ( & resolve , pkg, & mut visited, & mut path, & mut checked) ?
1037
1017
}
1038
1018
}
1039
1019
return Ok ( ( ) ) ;
1040
1020
1041
1021
fn visit (
1042
- graph : & BTreeMap < PackageId , BTreeMap < PackageId , Dependency > > ,
1022
+ resolve : & Resolve ,
1043
1023
id : PackageId ,
1044
1024
visited : & mut HashSet < PackageId > ,
1045
1025
path : & mut Vec < PackageId > ,
1046
1026
checked : & mut HashSet < PackageId > ,
1047
1027
) -> CargoResult < ( ) > {
1048
- path. push ( id) ;
1049
1028
if !visited. insert ( id) {
1050
- let iter = path. iter ( ) . rev ( ) . skip ( 1 ) . scan ( id, |child, parent| {
1051
- let dep = graph. get ( parent) . and_then ( |adjacent| adjacent. get ( child) ) ;
1029
+ // We found a cycle and need to construct an error. Performance is no longer top priority.
1030
+ let iter = path. iter ( ) . rev ( ) . scan ( id, |child, parent| {
1031
+ let dep = resolve. transitive_deps_not_replaced ( * parent) . find_map (
1032
+ |( dep_id, transitive_dep) | {
1033
+ ( * child == dep_id || Some ( * child) == resolve. replacement ( dep_id) )
1034
+ . then_some ( transitive_dep)
1035
+ } ,
1036
+ ) ;
1052
1037
* child = * parent;
1053
1038
Some ( ( parent, dep) )
1054
1039
} ) ;
1055
1040
let iter = std:: iter:: once ( ( & id, None ) ) . chain ( iter) ;
1041
+ let describe_path = errors:: describe_path ( iter) ;
1056
1042
anyhow:: bail!(
1057
- "cyclic package dependency: package `{}` depends on itself. Cycle:\n {}" ,
1058
- id,
1059
- errors:: describe_path( iter) ,
1043
+ "cyclic package dependency: package `{id}` depends on itself. Cycle:\n {describe_path}"
1060
1044
) ;
1061
1045
}
1062
1046
1063
1047
if checked. insert ( id) {
1064
- for dep in graph[ & id] . keys ( ) {
1065
- visit ( graph, * dep, visited, path, checked) ?;
1048
+ path. push ( id) ;
1049
+ for ( dep_id, _transitive_dep) in resolve. transitive_deps_not_replaced ( id) {
1050
+ visit ( resolve, dep_id, visited, path, checked) ?;
1051
+ if let Some ( replace_id) = resolve. replacement ( dep_id) {
1052
+ visit ( resolve, replace_id, visited, path, checked) ?;
1053
+ }
1066
1054
}
1055
+ path. pop ( ) ;
1067
1056
}
1068
1057
1069
- path. pop ( ) ;
1070
1058
visited. remove ( & id) ;
1071
1059
Ok ( ( ) )
1072
1060
}
0 commit comments