Skip to content

Commit 41d85cc

Browse files
committed
Simplify filtering.
1 parent 25218d2 commit 41d85cc

File tree

1 file changed

+78
-120
lines changed

1 file changed

+78
-120
lines changed

src/cargo/core/compiler/unit_dependencies.rs

Lines changed: 78 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -262,22 +262,15 @@ fn compute_deps(
262262
return compute_deps_doc(unit, state, unit_for);
263263
}
264264

265-
let id = unit.pkg.package_id();
266-
267-
let filtered_deps = state.deps(unit, unit_for);
268-
269265
let mut ret = Vec::new();
270266
let mut dev_deps = Vec::new();
271-
for (dep_pkg_id, deps) in filtered_deps {
272-
let dep_pkg = state.get(dep_pkg_id);
273-
let (could_have_non_artifact_lib, has_artifact_lib) =
274-
calc_artifact_deps(unit, unit_for, dep_pkg_id, deps, state, &mut ret)?;
275-
276-
let lib = package_lib(dep_pkg, could_have_non_artifact_lib, has_artifact_lib);
277-
let dep_lib = match lib {
278-
Some(t) => t,
267+
for (dep_pkg_id, deps) in state.deps(unit, unit_for) {
268+
let dep_lib = match calc_artifact_deps(unit, unit_for, dep_pkg_id, &deps, state, &mut ret)?
269+
{
270+
Some(lib) => lib,
279271
None => continue,
280272
};
273+
let dep_pkg = state.get(dep_pkg_id);
281274
let mode = check_or_build_mode(unit.mode, dep_lib);
282275
let dep_unit_for = unit_for.with_dependency(unit, dep_lib, unit_for.root_compile_kind());
283276

@@ -357,6 +350,7 @@ fn compute_deps(
357350
&& unit.mode.is_any_test()
358351
&& (unit.target.is_test() || unit.target.is_bench())
359352
{
353+
let id = unit.pkg.package_id();
360354
ret.extend(
361355
unit.pkg
362356
.targets()
@@ -396,49 +390,28 @@ fn compute_deps(
396390
Ok(ret)
397391
}
398392

399-
/// Try to find a target in `dep_pkg` which is a library.
400-
///
401-
/// `has_artifact` is true if `dep_pkg` has any artifact, and `artifact_lib` is true
402-
/// if any of them wants a library to be available too.
403-
fn package_lib(
404-
dep_pkg: &Package,
405-
could_have_non_artifact_lib: bool,
406-
artifact_lib: bool,
407-
) -> Option<&Target> {
408-
dep_pkg
409-
.targets()
410-
.iter()
411-
.find(|t| t.is_lib() && (could_have_non_artifact_lib || artifact_lib))
412-
}
413-
414393
/// Find artifacts for all `deps` of `unit` and add units that build these artifacts
415394
/// to `ret`.
416-
fn calc_artifact_deps(
395+
fn calc_artifact_deps<'a>(
417396
unit: &Unit,
418397
unit_for: UnitFor,
419398
dep_id: PackageId,
420-
deps: &HashSet<Dependency>,
421-
state: &State<'_, '_>,
399+
deps: &[&Dependency],
400+
state: &State<'a, '_>,
422401
ret: &mut Vec<UnitDep>,
423-
) -> CargoResult<(bool, bool)> {
402+
) -> CargoResult<Option<&'a Target>> {
424403
let mut has_artifact_lib = false;
425-
let mut num_artifacts = 0;
404+
let mut maybe_non_artifact_lib = false;
426405
let artifact_pkg = state.get(dep_id);
427-
let mut deps_past_filter = 0;
428-
for (dep, artifact) in deps
429-
.iter()
430-
.filter(|dep| {
431-
if non_custom_and_non_transitive_deps(unit, dep) {
432-
deps_past_filter += 1;
433-
true
434-
} else {
435-
false
406+
for dep in deps {
407+
let artifact = match dep.artifact() {
408+
Some(a) => a,
409+
None => {
410+
maybe_non_artifact_lib = true;
411+
continue;
436412
}
437-
})
438-
.filter_map(|dep| dep.artifact().map(|a| (dep, a)))
439-
{
413+
};
440414
has_artifact_lib |= artifact.is_lib();
441-
num_artifacts += 1;
442415
// Custom build scripts (build/compile) never get artifact dependencies,
443416
// but the run-build-script step does (where it is handled).
444417
if !unit.target.is_custom_build() {
@@ -462,8 +435,11 @@ fn calc_artifact_deps(
462435
)?);
463436
}
464437
}
465-
let could_be_non_artifact_lib = deps_past_filter != num_artifacts;
466-
Ok((could_be_non_artifact_lib, has_artifact_lib))
438+
if has_artifact_lib || maybe_non_artifact_lib {
439+
Ok(artifact_pkg.targets().iter().find(|t| t.is_lib()))
440+
} else {
441+
Ok(None)
442+
}
467443
}
468444

469445
/// Returns the dependencies needed to run a build script.
@@ -519,10 +495,7 @@ fn compute_deps_custom_build(
519495
//
520496
// This is essentially the same as `calc_artifact_deps`, but there are some
521497
// subtle differences that require this to be implemented differently.
522-
let artifact_build_deps = state.deps_filtered(unit, script_unit_for, &|_unit, dep| {
523-
dep.kind() == DepKind::Build && dep.artifact().is_some()
524-
});
525-
498+
//
526499
// Produce units that build all required artifact kinds (like binaries,
527500
// static libraries, etc) with the correct compile target.
528501
//
@@ -532,10 +505,13 @@ fn compute_deps_custom_build(
532505
// `root_unit_compile_target` necessary.
533506
let root_unit_compile_target = unit_for.root_compile_kind();
534507
let unit_for = UnitFor::new_host(/*host_features*/ true, root_unit_compile_target);
535-
for (dep_pkg_id, deps) in artifact_build_deps {
536-
let artifact_pkg = state.get(dep_pkg_id);
537-
for build_dep in deps.iter().filter(|d| d.is_build()) {
538-
let artifact = build_dep.artifact().expect("artifact dep");
508+
for (dep_pkg_id, deps) in state.deps(unit, script_unit_for) {
509+
for dep in deps {
510+
if dep.kind() != DepKind::Build || dep.artifact().is_none() {
511+
continue;
512+
}
513+
let artifact_pkg = state.get(dep_pkg_id);
514+
let artifact = dep.artifact().expect("artifact dep");
539515
let resolved_artifact_compile_kind = artifact
540516
.target()
541517
.map(|target| target.to_resolved_compile_kind(root_unit_compile_target));
@@ -548,7 +524,7 @@ fn compute_deps_custom_build(
548524
state,
549525
resolved_artifact_compile_kind.unwrap_or(CompileKind::Host),
550526
artifact_pkg,
551-
build_dep,
527+
dep,
552528
)?);
553529
}
554530
}
@@ -663,22 +639,16 @@ fn compute_deps_doc(
663639
state: &mut State<'_, '_>,
664640
unit_for: UnitFor,
665641
) -> CargoResult<Vec<UnitDep>> {
666-
let deps = state.deps(unit, unit_for);
667-
668642
// To document a library, we depend on dependencies actually being
669643
// built. If we're documenting *all* libraries, then we also depend on
670644
// the documentation of the library being built.
671645
let mut ret = Vec::new();
672-
for (id, deps) in deps {
673-
let (could_have_non_artifact_lib, has_artifact_lib) =
674-
calc_artifact_deps(unit, unit_for, id, deps, state, &mut ret)?;
675-
676-
let dep_pkg = state.get(id);
677-
let lib = package_lib(dep_pkg, could_have_non_artifact_lib, has_artifact_lib);
678-
let dep_lib = match lib {
646+
for (id, deps) in state.deps(unit, unit_for) {
647+
let dep_lib = match calc_artifact_deps(unit, unit_for, id, &deps, state, &mut ret)? {
679648
Some(lib) => lib,
680649
None => continue,
681650
};
651+
let dep_pkg = state.get(id);
682652
// Rustdoc only needs rmeta files for regular dependencies.
683653
// However, for plugins/proc macros, deps should be built like normal.
684654
let mode = check_or_build_mode(unit.mode, dep_lib);
@@ -1098,73 +1068,61 @@ impl<'a, 'cfg> State<'a, 'cfg> {
10981068
.unwrap_or_else(|_| panic!("expected {} to be downloaded", id))
10991069
}
11001070

1101-
/// Returns a set of dependencies for the given unit, with a default filter.
1102-
fn deps(&self, unit: &Unit, unit_for: UnitFor) -> Vec<(PackageId, &HashSet<Dependency>)> {
1103-
self.deps_filtered(unit, unit_for, &non_custom_and_non_transitive_deps)
1104-
}
1105-
11061071
/// Returns a filtered set of dependencies for the given unit.
1107-
fn deps_filtered(
1108-
&self,
1109-
unit: &Unit,
1110-
unit_for: UnitFor,
1111-
filter: &dyn Fn(&Unit, &Dependency) -> bool,
1112-
) -> Vec<(PackageId, &HashSet<Dependency>)> {
1072+
fn deps(&self, unit: &Unit, unit_for: UnitFor) -> Vec<(PackageId, Vec<&Dependency>)> {
11131073
let pkg_id = unit.pkg.package_id();
11141074
let kind = unit.kind;
11151075
self.resolve()
11161076
.deps(pkg_id)
1117-
.filter(|&(_id, deps)| {
1077+
.filter_map(|(id, deps)| {
11181078
assert!(!deps.is_empty());
1119-
deps.iter().any(|dep| {
1120-
if !filter(unit, dep) {
1121-
return false;
1122-
}
1079+
let deps: Vec<_> = deps
1080+
.iter()
1081+
.filter(|dep| {
1082+
// If this target is a build command, then we only want build
1083+
// dependencies, otherwise we want everything *other than* build
1084+
// dependencies.
1085+
if unit.target.is_custom_build() != dep.is_build() {
1086+
return false;
1087+
}
11231088

1124-
// If this dependency is only available for certain platforms,
1125-
// make sure we're only enabling it for that platform.
1126-
if !self.target_data.dep_platform_activated(dep, kind) {
1127-
return false;
1128-
}
1089+
// If this dependency is **not** a transitive dependency, then it
1090+
// only applies to test/example targets.
1091+
if !dep.is_transitive()
1092+
&& !unit.target.is_test()
1093+
&& !unit.target.is_example()
1094+
&& !unit.mode.is_doc_scrape()
1095+
&& !unit.mode.is_any_test()
1096+
{
1097+
return false;
1098+
}
11291099

1130-
// If this is an optional dependency, and the new feature resolver
1131-
// did not enable it, don't include it.
1132-
if dep.is_optional() {
1133-
let features_for = unit_for.map_to_features_for(dep.artifact());
1134-
if !self.is_dep_activated(pkg_id, features_for, dep.name_in_toml()) {
1100+
// If this dependency is only available for certain platforms,
1101+
// make sure we're only enabling it for that platform.
1102+
if !self.target_data.dep_platform_activated(dep, kind) {
11351103
return false;
11361104
}
1137-
}
11381105

1139-
// If we've gotten past all that, then this dependency is
1140-
// actually used!
1141-
true
1142-
})
1106+
// If this is an optional dependency, and the new feature resolver
1107+
// did not enable it, don't include it.
1108+
if dep.is_optional() {
1109+
let features_for = unit_for.map_to_features_for(dep.artifact());
1110+
if !self.is_dep_activated(pkg_id, features_for, dep.name_in_toml()) {
1111+
return false;
1112+
}
1113+
}
1114+
1115+
// If we've gotten past all that, then this dependency is
1116+
// actually used!
1117+
true
1118+
})
1119+
.collect();
1120+
if deps.is_empty() {
1121+
None
1122+
} else {
1123+
Some((id, deps))
1124+
}
11431125
})
11441126
.collect()
11451127
}
11461128
}
1147-
1148-
fn non_custom_and_non_transitive_deps(unit: &Unit, dep: &Dependency) -> bool {
1149-
// If this target is a build command, then we only want build
1150-
// dependencies, otherwise we want everything *other than* build
1151-
// dependencies.
1152-
if unit.target.is_custom_build() != dep.is_build() {
1153-
return false;
1154-
}
1155-
1156-
// If this dependency is **not** a transitive dependency, then it
1157-
// only applies to test/example targets.
1158-
if !dep.is_transitive()
1159-
&& !unit.target.is_test()
1160-
&& !unit.target.is_example()
1161-
&& !unit.mode.is_doc_scrape()
1162-
&& !unit.mode.is_any_test()
1163-
{
1164-
return false;
1165-
}
1166-
1167-
// If we've gotten past all that, then this dependency is
1168-
// actually used!
1169-
true
1170-
}

0 commit comments

Comments
 (0)