From b23177b8753f50c2cecdc01bff2bcb71eaf55bef Mon Sep 17 00:00:00 2001 From: Yanick Witschi Date: Mon, 28 Feb 2022 17:52:42 +0100 Subject: [PATCH 1/8] Failing test case --- .../pooloptimizer/complex-prefer-lowest.test | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/complex-prefer-lowest.test diff --git a/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/complex-prefer-lowest.test b/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/complex-prefer-lowest.test new file mode 100644 index 000000000000..74240e145268 --- /dev/null +++ b/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/complex-prefer-lowest.test @@ -0,0 +1,55 @@ +--TEST-- +Test keeps package "package/b" in version 2.2.0 because for prefer-lowest either one might be relevant + +--REQUEST-- +{ + "require": { + "package/a": "^1.0" + }, + "preferLowest": true +} + + +--POOL-BEFORE-- +[ + { + "name": "package/a", + "version": "1.0.0", + "require": { + "package/b": "^1.0 || ^2.2" + } + }, + { + "name": "package/b", + "version": "1.0.0" + }, + { + "name": "package/b", + "version": "1.0.1" + }, + { + "name": "package/b", + "version": "2.2.0" + } +] + + +--POOL-AFTER-- +[ + { + "name": "package/a", + "version": "1.0.0", + "require": { + "package/b": "^1.0" + } + }, + { + "name": "package/b", + "version": "1.0.0" + }, + { + "name": "package/b", + "version": "2.2.0" + } +] + From fa0eae9a421a0f4d37a49d0b6af16923db3afd3c Mon Sep 17 00:00:00 2001 From: Yanick Witschi Date: Mon, 28 Feb 2022 18:16:12 +0100 Subject: [PATCH 2/8] Quickfix, needs more investigation --- .../DependencyResolver/PoolOptimizer.php | 53 ++++++++++++++++--- .../Fixtures/pooloptimizer/conflict.test | 4 ++ .../Fixtures/pooloptimizer/conflict2.test | 4 ++ 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/Composer/DependencyResolver/PoolOptimizer.php b/src/Composer/DependencyResolver/PoolOptimizer.php index ef17938b5c28..aa12659e1f5a 100644 --- a/src/Composer/DependencyResolver/PoolOptimizer.php +++ b/src/Composer/DependencyResolver/PoolOptimizer.php @@ -110,21 +110,18 @@ private function prepare(Request $request, Pool $pool) // Extract requested package requirements foreach ($request->getRequires() as $require => $constraint) { - $constraint = Intervals::compactConstraint($constraint); - $this->requireConstraintsPerPackage[$require][(string) $constraint] = $constraint; + $this->extractRequireConstraintsPerPackage($require, $constraint); } // First pass over all packages to extract information and mark package constraints irremovable foreach ($pool->getPackages() as $package) { // Extract package requirements foreach ($package->getRequires() as $link) { - $constraint = Intervals::compactConstraint($link->getConstraint()); - $this->requireConstraintsPerPackage[$link->getTarget()][(string) $constraint] = $constraint; + $this->extractRequireConstraintsPerPackage($link->getTarget(), $link->getConstraint()); } // Extract package conflicts foreach ($package->getConflicts() as $link) { - $constraint = Intervals::compactConstraint($link->getConstraint()); - $this->conflictConstraintsPerPackage[$link->getTarget()][(string) $constraint] = $constraint; + $this->extractConflictConstraintsPerPackage($link->getTarget(), $link->getConstraint()); } // Keep track of alias packages for every package so if either the alias or aliased is kept @@ -453,4 +450,48 @@ private function optimizeImpossiblePackagesAway(Request $request, Pool $pool) } } } + + /** + * @param string $package + * @param ConstraintInterface $constraint + */ + private function extractRequireConstraintsPerPackage($package, ConstraintInterface $constraint) + { + foreach ($this->flattenMultiConstraints($constraint) as $flattened) { + $this->requireConstraintsPerPackage[$package][(string) $flattened] = $flattened; + } + } + + /** + * @param string $package + * @param ConstraintInterface $constraint + */ + private function extractConflictConstraintsPerPackage($package, ConstraintInterface $constraint) + { + foreach ($this->flattenMultiConstraints($constraint) as $flattened) { + $this->conflictConstraintsPerPackage[$package][(string) $flattened] = $flattened; + } + } + + /** + * @param ConstraintInterface $constraint + * @return array + */ + private function flattenMultiConstraints(ConstraintInterface $constraint) + { + $flattened = array(); + $constraint = Intervals::compactConstraint($constraint); + + if ($constraint instanceof MultiConstraint) { + foreach ($constraint->getConstraints() as $sub) { + $flattened = array_merge($flattened, $this->flattenMultiConstraints($sub)); + } + + return $flattened; + } + + $flattened[] = $constraint; + + return $flattened; + } } diff --git a/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict.test b/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict.test index 30ed9e140942..d47534c31e6b 100644 --- a/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict.test +++ b/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict.test @@ -103,5 +103,9 @@ from the pool which might end up being part of the solution. { "name": "victim/pkg", "version": "1.1.2" + }, + { + "name": "victim/pkg", + "version": "1.2.0" } ] diff --git a/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict2.test b/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict2.test index a6a5209bbdfc..15ce3208188d 100644 --- a/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict2.test +++ b/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict2.test @@ -99,5 +99,9 @@ from the pool which might end up being part of the solution. { "name": "victim/pkg", "version": "1.1.2" + }, + { + "name": "victim/pkg", + "version": "1.2.0" } ] From 073e1158e6b32b8b5965a6309e4f4c0bd8f440de Mon Sep 17 00:00:00 2001 From: Yanick Witschi Date: Tue, 1 Mar 2022 00:12:04 +0100 Subject: [PATCH 3/8] Only disjunctive multi constraints are of interest --- .../DependencyResolver/PoolOptimizer.php | 36 ++++++++++++------- .../Fixtures/pooloptimizer/conflict.test | 4 --- .../Fixtures/pooloptimizer/conflict2.test | 4 --- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/Composer/DependencyResolver/PoolOptimizer.php b/src/Composer/DependencyResolver/PoolOptimizer.php index aa12659e1f5a..9aa6ab90c06e 100644 --- a/src/Composer/DependencyResolver/PoolOptimizer.php +++ b/src/Composer/DependencyResolver/PoolOptimizer.php @@ -452,46 +452,58 @@ private function optimizeImpossiblePackagesAway(Request $request, Pool $pool) } /** + * Disjunctive require constraints need to be considered in their own group. E.g. "^2.14 || ^3.3" needs to generate + * two require constraint groups in order for us to keep the best matching package for "^2.14" AND "^3.3" as otherwise, we'd + * only keep either one which can cause trouble (e.g. when using --prefer-lowest). + * * @param string $package * @param ConstraintInterface $constraint + * @return void */ private function extractRequireConstraintsPerPackage($package, ConstraintInterface $constraint) { - foreach ($this->flattenMultiConstraints($constraint) as $flattened) { - $this->requireConstraintsPerPackage[$package][(string) $flattened] = $flattened; + foreach ($this->expandDisjunctiveMultiConstraints($constraint) as $expanded) { + $this->requireConstraintsPerPackage[$package][(string) $expanded] = $expanded; } } /** + * Disjunctive conflict constraints need to be considered in their own group. E.g. "^2.14 || ^3.3" needs to generate + * two conflict constraint groups in order for us to keep the best matching package for "^2.14" AND "^3.3" as otherwise, we'd + * only keep either one which can cause trouble (e.g. when using --prefer-lowest). + * * @param string $package * @param ConstraintInterface $constraint + * @return void */ private function extractConflictConstraintsPerPackage($package, ConstraintInterface $constraint) { - foreach ($this->flattenMultiConstraints($constraint) as $flattened) { - $this->conflictConstraintsPerPackage[$package][(string) $flattened] = $flattened; + foreach ($this->expandDisjunctiveMultiConstraints($constraint) as $expanded) { + $this->conflictConstraintsPerPackage[$package][(string) $expanded] = $expanded; } } /** + * * @param ConstraintInterface $constraint - * @return array + * @return ConstraintInterface[] */ - private function flattenMultiConstraints(ConstraintInterface $constraint) + private function expandDisjunctiveMultiConstraints(ConstraintInterface $constraint) { - $flattened = array(); + $expanded = array(); $constraint = Intervals::compactConstraint($constraint); - if ($constraint instanceof MultiConstraint) { + if ($constraint instanceof MultiConstraint && $constraint->isDisjunctive()) { foreach ($constraint->getConstraints() as $sub) { - $flattened = array_merge($flattened, $this->flattenMultiConstraints($sub)); + $expanded = array_merge($expanded, $this->expandDisjunctiveMultiConstraints($sub)); } - return $flattened; + return $expanded; } - $flattened[] = $constraint; + // Regular constraints and conjunctive MultiConstraints + $expanded[] = $constraint; - return $flattened; + return $expanded; } } diff --git a/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict.test b/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict.test index d47534c31e6b..30ed9e140942 100644 --- a/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict.test +++ b/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict.test @@ -103,9 +103,5 @@ from the pool which might end up being part of the solution. { "name": "victim/pkg", "version": "1.1.2" - }, - { - "name": "victim/pkg", - "version": "1.2.0" } ] diff --git a/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict2.test b/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict2.test index 15ce3208188d..a6a5209bbdfc 100644 --- a/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict2.test +++ b/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/conflict2.test @@ -99,9 +99,5 @@ from the pool which might end up being part of the solution. { "name": "victim/pkg", "version": "1.1.2" - }, - { - "name": "victim/pkg", - "version": "1.2.0" } ] From 160e1f42c9b9de61228a5e5bedec11695cb0d091 Mon Sep 17 00:00:00 2001 From: Yanick Witschi Date: Wed, 2 Mar 2022 10:02:08 +0100 Subject: [PATCH 4/8] More test coverage --- .../DependencyResolver/PoolOptimizer.php | 7 +- .../pooloptimizer/basic-prefer-highest.test | 10 ++- .../DependencyResolver/PoolOptimizerTest.php | 76 +++++++++++++++++++ 3 files changed, 91 insertions(+), 2 deletions(-) diff --git a/src/Composer/DependencyResolver/PoolOptimizer.php b/src/Composer/DependencyResolver/PoolOptimizer.php index 9aa6ab90c06e..aab6d6e62fde 100644 --- a/src/Composer/DependencyResolver/PoolOptimizer.php +++ b/src/Composer/DependencyResolver/PoolOptimizer.php @@ -495,7 +495,12 @@ private function expandDisjunctiveMultiConstraints(ConstraintInterface $constrai if ($constraint instanceof MultiConstraint && $constraint->isDisjunctive()) { foreach ($constraint->getConstraints() as $sub) { - $expanded = array_merge($expanded, $this->expandDisjunctiveMultiConstraints($sub)); + // TODO: Do we need to call ourselves recursively? Is it even possible? + // Tried to write a testcase in PoolOptimizerTest::testNestedDisjunctiveMultiConstraints() but + // couldn't find an example where Intervals::compactConstraint() leaves a nested disjunctive MultiConstraint + // untouched. + // $expanded = array_merge($expanded, $this->expandDisjunctiveMultiConstraints($sub)); + $expanded[] = $sub; } return $expanded; diff --git a/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/basic-prefer-highest.test b/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/basic-prefer-highest.test index 91131b790204..904d6c3750fe 100644 --- a/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/basic-prefer-highest.test +++ b/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer/basic-prefer-highest.test @@ -15,7 +15,7 @@ Test filters irrelevant package "package/b" in version 1.0.0 "name": "package/a", "version": "1.0.0", "require": { - "package/b": "^1.0" + "package/b": ">=1.0 <1.1 || ^1.2" } }, { @@ -25,6 +25,10 @@ Test filters irrelevant package "package/b" in version 1.0.0 { "name": "package/b", "version": "1.0.1" + }, + { + "name": "package/b", + "version": "1.2.0" } ] @@ -41,6 +45,10 @@ Test filters irrelevant package "package/b" in version 1.0.0 { "name": "package/b", "version": "1.0.1" + }, + { + "name": "package/b", + "version": "1.2.0" } ] diff --git a/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php b/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php index 85d70d6f6414..6cba7c94f8be 100644 --- a/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php +++ b/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php @@ -19,14 +19,90 @@ use Composer\Json\JsonFile; use Composer\Package\AliasPackage; use Composer\Package\BasePackage; +use Composer\Package\Link; use Composer\Package\Loader\ArrayLoader; use Composer\Package\Version\VersionParser; use Composer\Pcre\Preg; use Composer\Repository\LockArrayRepository; +use Composer\Semver\Constraint\Constraint; +use Composer\Semver\Constraint\MatchAllConstraint; +use Composer\Semver\Constraint\MultiConstraint; use Composer\Test\TestCase; class PoolOptimizerTest extends TestCase { + public function testNestedDisjunctiveMultiConstraints() + { + $requirer = $this->loadPackage(array('name' => 'package/a', 'version' => '1.0.0')); + $requirer->setRequires(array( + 'package/b' => new Link('package/a', 'package/b', new MultiConstraint( // Not possible with the version parser but this represents (^2.5 || (~1.2.3 || ^4.0)) + array( + new MultiConstraint( // ^2.5 + array( + new Constraint('>=', '2.5.0.0-dev'), + new Constraint('<', '3.0.0.0-dev'), + ), + true // conjunctive + ), + new MultiConstraint( // ~1.2.3 || ^4.0 + array( + new MultiConstraint( // ~1.2.3 + array( + new Constraint('>=', '1.2.3.0-dev'), + new Constraint('<', '1.3.0.0-dev'), + ), + true // conjunctive + ), + new MultiConstraint( // ^4.0 + array( + new Constraint('>=', '4.0.0.0-dev'), + new Constraint('<', '5.0.0.0-dev'), + ), + true // conjunctive + ), + ), + false // disjunctive + ), + ), + false // disjunctive + ) + ) + )); + + + $packagesBefore = array( + $requirer, + $this->loadPackage(array('name' => 'package/b', 'version' => '1.2.3')), + $this->loadPackage(array('name' => 'package/b', 'version' => '1.2.4')), + $this->loadPackage(array('name' => 'package/b', 'version' => '2.5.0')), + $this->loadPackage(array('name' => 'package/b', 'version' => '2.5.1')), + $this->loadPackage(array('name' => 'package/b', 'version' => '4.0.0')), + $this->loadPackage(array('name' => 'package/b', 'version' => '4.0.1')), + ); + + $request = new Request(new LockArrayRepository()); + $request->requireName('package/a'); + + $pool = new Pool($packagesBefore); + $poolOptimizer = new PoolOptimizer(new DefaultPolicy(true, true)); // --prefer-lowest + $optimizedPool = $poolOptimizer->optimize($request, $pool); + + $this->assertSame(array( + 'package/a@1.0.0.0', + 'package/b@1.2.3.0', + 'package/b@2.5.0.0', + 'package/b@4.0.0.0', + ), $this->reducePackagesInfoForComparison($optimizedPool->getPackages())); + + + $this->assertSame(array( + '1.2.4.0' => '1.2.4', + '2.5.1.0' => '2.5.1', + '4.0.1.0' => '4.0.1', + ), $optimizedPool->getRemovedVersions('package/b', new MatchAllConstraint())); + } + + /** * @dataProvider provideIntegrationTests * @param mixed[] $requestData From 8263c961def13a1f0028b68407b1c707cc2b5303 Mon Sep 17 00:00:00 2001 From: Yanick Witschi Date: Wed, 2 Mar 2022 10:06:04 +0100 Subject: [PATCH 5/8] CS --- tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php b/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php index 6cba7c94f8be..1b5cf8204b7d 100644 --- a/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php +++ b/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php @@ -21,6 +21,7 @@ use Composer\Package\BasePackage; use Composer\Package\Link; use Composer\Package\Loader\ArrayLoader; +use Composer\Package\RootPackage; use Composer\Package\Version\VersionParser; use Composer\Pcre\Preg; use Composer\Repository\LockArrayRepository; @@ -33,7 +34,8 @@ class PoolOptimizerTest extends TestCase { public function testNestedDisjunctiveMultiConstraints() { - $requirer = $this->loadPackage(array('name' => 'package/a', 'version' => '1.0.0')); + $requirer = new RootPackage('package/a', '1.0.0', '1.0.0'); + $requirer->setRequires(array( 'package/b' => new Link('package/a', 'package/b', new MultiConstraint( // Not possible with the version parser but this represents (^2.5 || (~1.2.3 || ^4.0)) array( From abbe9c97c039a5f3968e4f4cae3980743d196f51 Mon Sep 17 00:00:00 2001 From: Yanick Witschi Date: Wed, 2 Mar 2022 10:08:19 +0100 Subject: [PATCH 6/8] CS --- tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php b/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php index 1b5cf8204b7d..43f801724012 100644 --- a/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php +++ b/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php @@ -34,7 +34,7 @@ class PoolOptimizerTest extends TestCase { public function testNestedDisjunctiveMultiConstraints() { - $requirer = new RootPackage('package/a', '1.0.0', '1.0.0'); + $requirer = new RootPackage('package/a', '1.0.0.0', '1.0.0'); $requirer->setRequires(array( 'package/b' => new Link('package/a', 'package/b', new MultiConstraint( // Not possible with the version parser but this represents (^2.5 || (~1.2.3 || ^4.0)) From 916945883d2ef70a8f661b17f8c4e5588e3bb505 Mon Sep 17 00:00:00 2001 From: Yanick Witschi Date: Wed, 2 Mar 2022 11:45:33 +0100 Subject: [PATCH 7/8] Added a note and removed useless test case --- .../DependencyResolver/PoolOptimizer.php | 7 +- .../DependencyResolver/PoolOptimizerTest.php | 78 ------------------- 2 files changed, 2 insertions(+), 83 deletions(-) diff --git a/src/Composer/DependencyResolver/PoolOptimizer.php b/src/Composer/DependencyResolver/PoolOptimizer.php index aab6d6e62fde..dade21a7bd0d 100644 --- a/src/Composer/DependencyResolver/PoolOptimizer.php +++ b/src/Composer/DependencyResolver/PoolOptimizer.php @@ -495,11 +495,8 @@ private function expandDisjunctiveMultiConstraints(ConstraintInterface $constrai if ($constraint instanceof MultiConstraint && $constraint->isDisjunctive()) { foreach ($constraint->getConstraints() as $sub) { - // TODO: Do we need to call ourselves recursively? Is it even possible? - // Tried to write a testcase in PoolOptimizerTest::testNestedDisjunctiveMultiConstraints() but - // couldn't find an example where Intervals::compactConstraint() leaves a nested disjunctive MultiConstraint - // untouched. - // $expanded = array_merge($expanded, $this->expandDisjunctiveMultiConstraints($sub)); + // No need to call ourselves recursively here because Intervals::compactConstraint() ensures that there + // are no nested disjunctive MultiConstraint instances possible $expanded[] = $sub; } diff --git a/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php b/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php index 43f801724012..85d70d6f6414 100644 --- a/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php +++ b/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php @@ -19,92 +19,14 @@ use Composer\Json\JsonFile; use Composer\Package\AliasPackage; use Composer\Package\BasePackage; -use Composer\Package\Link; use Composer\Package\Loader\ArrayLoader; -use Composer\Package\RootPackage; use Composer\Package\Version\VersionParser; use Composer\Pcre\Preg; use Composer\Repository\LockArrayRepository; -use Composer\Semver\Constraint\Constraint; -use Composer\Semver\Constraint\MatchAllConstraint; -use Composer\Semver\Constraint\MultiConstraint; use Composer\Test\TestCase; class PoolOptimizerTest extends TestCase { - public function testNestedDisjunctiveMultiConstraints() - { - $requirer = new RootPackage('package/a', '1.0.0.0', '1.0.0'); - - $requirer->setRequires(array( - 'package/b' => new Link('package/a', 'package/b', new MultiConstraint( // Not possible with the version parser but this represents (^2.5 || (~1.2.3 || ^4.0)) - array( - new MultiConstraint( // ^2.5 - array( - new Constraint('>=', '2.5.0.0-dev'), - new Constraint('<', '3.0.0.0-dev'), - ), - true // conjunctive - ), - new MultiConstraint( // ~1.2.3 || ^4.0 - array( - new MultiConstraint( // ~1.2.3 - array( - new Constraint('>=', '1.2.3.0-dev'), - new Constraint('<', '1.3.0.0-dev'), - ), - true // conjunctive - ), - new MultiConstraint( // ^4.0 - array( - new Constraint('>=', '4.0.0.0-dev'), - new Constraint('<', '5.0.0.0-dev'), - ), - true // conjunctive - ), - ), - false // disjunctive - ), - ), - false // disjunctive - ) - ) - )); - - - $packagesBefore = array( - $requirer, - $this->loadPackage(array('name' => 'package/b', 'version' => '1.2.3')), - $this->loadPackage(array('name' => 'package/b', 'version' => '1.2.4')), - $this->loadPackage(array('name' => 'package/b', 'version' => '2.5.0')), - $this->loadPackage(array('name' => 'package/b', 'version' => '2.5.1')), - $this->loadPackage(array('name' => 'package/b', 'version' => '4.0.0')), - $this->loadPackage(array('name' => 'package/b', 'version' => '4.0.1')), - ); - - $request = new Request(new LockArrayRepository()); - $request->requireName('package/a'); - - $pool = new Pool($packagesBefore); - $poolOptimizer = new PoolOptimizer(new DefaultPolicy(true, true)); // --prefer-lowest - $optimizedPool = $poolOptimizer->optimize($request, $pool); - - $this->assertSame(array( - 'package/a@1.0.0.0', - 'package/b@1.2.3.0', - 'package/b@2.5.0.0', - 'package/b@4.0.0.0', - ), $this->reducePackagesInfoForComparison($optimizedPool->getPackages())); - - - $this->assertSame(array( - '1.2.4.0' => '1.2.4', - '2.5.1.0' => '2.5.1', - '4.0.1.0' => '4.0.1', - ), $optimizedPool->getRemovedVersions('package/b', new MatchAllConstraint())); - } - - /** * @dataProvider provideIntegrationTests * @param mixed[] $requestData From 51c22aa0e7fa19aa9af9457e0758614a62540d00 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 12 Mar 2022 14:13:46 +0100 Subject: [PATCH 8/8] Simplify code --- src/Composer/DependencyResolver/PoolOptimizer.php | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/Composer/DependencyResolver/PoolOptimizer.php b/src/Composer/DependencyResolver/PoolOptimizer.php index dade21a7bd0d..939e54a8d85d 100644 --- a/src/Composer/DependencyResolver/PoolOptimizer.php +++ b/src/Composer/DependencyResolver/PoolOptimizer.php @@ -490,22 +490,15 @@ private function extractConflictConstraintsPerPackage($package, ConstraintInterf */ private function expandDisjunctiveMultiConstraints(ConstraintInterface $constraint) { - $expanded = array(); $constraint = Intervals::compactConstraint($constraint); if ($constraint instanceof MultiConstraint && $constraint->isDisjunctive()) { - foreach ($constraint->getConstraints() as $sub) { - // No need to call ourselves recursively here because Intervals::compactConstraint() ensures that there - // are no nested disjunctive MultiConstraint instances possible - $expanded[] = $sub; - } - - return $expanded; + // No need to call ourselves recursively here because Intervals::compactConstraint() ensures that there + // are no nested disjunctive MultiConstraint instances possible + return $constraint->getConstraints(); } // Regular constraints and conjunctive MultiConstraints - $expanded[] = $constraint; - - return $expanded; + return array($constraint); } }