Solver: Prevent infinite recursion in analyzeUnsolvableRule
In complex scenarios reasons for learned rules can themselves be learned rules caused by other learned rules which had the some of the same reasons. In this situation iterating over all problem rules requires keeping track of which rules have previously been analyzed to avoid and endless loop. Side effect is that the sorting of problems including learned rules changes slightly.pull/9312/head
parent
6e8e5f6ba6
commit
7b4cb9c370
|
@ -518,15 +518,19 @@ class Solver
|
|||
* @param Problem $problem
|
||||
* @param Rule $conflictRule
|
||||
*/
|
||||
private function analyzeUnsolvableRule(Problem $problem, Rule $conflictRule)
|
||||
private function analyzeUnsolvableRule(Problem $problem, Rule $conflictRule, &$ruleSeen)
|
||||
{
|
||||
$ruleSeen[spl_object_hash($conflictRule)] = true;
|
||||
|
||||
if ($conflictRule->getType() == RuleSet::TYPE_LEARNED) {
|
||||
$why = spl_object_hash($conflictRule);
|
||||
$learnedWhy = $this->learnedWhy[$why];
|
||||
$problemRules = $this->learnedPool[$learnedWhy];
|
||||
|
||||
foreach ($problemRules as $problemRule) {
|
||||
$this->analyzeUnsolvableRule($problem, $problemRule);
|
||||
if (!isset($ruleSeen[spl_object_hash($problemRule)])) {
|
||||
$this->analyzeUnsolvableRule($problem, $problemRule, $ruleSeen);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -550,7 +554,9 @@ class Solver
|
|||
$problem = new Problem();
|
||||
$problem->addRule($conflictRule);
|
||||
|
||||
$this->analyzeUnsolvableRule($problem, $conflictRule);
|
||||
$ruleSeen = array();
|
||||
|
||||
$this->analyzeUnsolvableRule($problem, $conflictRule, $ruleSeen);
|
||||
|
||||
$this->problems[] = $problem;
|
||||
|
||||
|
@ -576,7 +582,7 @@ class Solver
|
|||
$why = $decision[Decisions::DECISION_REASON];
|
||||
|
||||
$problem->addRule($why);
|
||||
$this->analyzeUnsolvableRule($problem, $why);
|
||||
$this->analyzeUnsolvableRule($problem, $why, $ruleSeen);
|
||||
|
||||
$literals = $why->getLiterals();
|
||||
|
||||
|
|
|
@ -116,13 +116,13 @@ Your requirements could not be resolved to an installable set of packages.
|
|||
|
||||
Problem 1
|
||||
- Conclusion: don't install friendsofphp/php-cs-fixer v2.10.5 (conflict analysis result)
|
||||
- Conclusion: don't install symfony/console v3.4.29 (conflict analysis result)
|
||||
- Conclusion: don't install symfony/console v2.8.8 (conflict analysis result)
|
||||
- Conclusion: don't install symfony/console v3.4.28 (conflict analysis result)
|
||||
- Root composer.json requires friendsofphp/php-cs-fixer * -> satisfiable by friendsofphp/php-cs-fixer[v2.10.4, v2.10.5].
|
||||
- illuminate/queue v5.2.0 requires illuminate/console 5.2.* -> satisfiable by illuminate/console[v5.2.25, v5.2.26].
|
||||
- illuminate/console v5.2.26 requires symfony/console 2.8.* -> satisfiable by symfony/console[v2.8.7, v2.8.8].
|
||||
- Conclusion: don't install symfony/console v2.8.7 (conflict analysis result)
|
||||
- Root composer.json requires friendsofphp/php-cs-fixer * -> satisfiable by friendsofphp/php-cs-fixer[v2.10.4, v2.10.5].
|
||||
- Conclusion: don't install symfony/console v3.4.28 (conflict analysis result)
|
||||
- Conclusion: don't install symfony/console v2.8.8 (conflict analysis result)
|
||||
- Conclusion: don't install symfony/console v3.4.29 (conflict analysis result)
|
||||
- Root composer.json requires illuminate/queue * -> satisfiable by illuminate/queue[v5.2.0].
|
||||
- friendsofphp/php-cs-fixer v2.10.4 requires symfony/console ^3.2 || ^4.0 -> satisfiable by symfony/console[v3.2.13, ..., v3.4.29].
|
||||
- You can only install one version of a package, so only one of these can be installed: symfony/console[v2.8.7, v2.8.8, v3.1.9, ..., v3.4.29].
|
||||
|
|
|
@ -0,0 +1,325 @@
|
|||
--TEST--
|
||||
|
||||
See Github issue #9012 ( https://github.com/composer/composer/issues/9012 and https://gist.github.com/Seldaek/4e2dbc2cea4b4fd7a8207bb310ec8e34).
|
||||
|
||||
Recursive analysis of the same learnt rules can lead to infinite recursion in solver.
|
||||
|
||||
--COMPOSER--
|
||||
{
|
||||
"require": {
|
||||
"php": ">=7.1.7",
|
||||
"laravel/framework": "^6.0",
|
||||
"nunomaduro/collision": "^4.0"
|
||||
},
|
||||
"config": {
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true,
|
||||
"optimize-autoloader": true,
|
||||
"process-timeout": 0
|
||||
},
|
||||
"repositories": {
|
||||
"laravel/framework": {
|
||||
"type": "package",
|
||||
"package": [
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v6.0.0",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "6.x-dev"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"symfony/console": "^4.3.4"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"nunomaduro/collision": {
|
||||
"type": "package",
|
||||
"package": [
|
||||
{
|
||||
"name": "nunomaduro/collision",
|
||||
"version": "v4.2.0",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"symfony/console": "^5.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"symfony/console": {
|
||||
"type": "package",
|
||||
"package": [
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.1.7",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.1.6",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.1.5",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.1.4",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.1.3",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.1.2",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.1.1",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.1.0",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.1.0-RC2",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.1.0-RC1",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.1.0-BETA1",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.0.11",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.0.10",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.0.9",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.0.8",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.0.7",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.0.6",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.0.5",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.0.4",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.0.3",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.0.2",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.0.1",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.0.0",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.15",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.14",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.13",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.12",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.11",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.10",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.9",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.8",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.7",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.6",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.5",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.4",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.3",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.2",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.1",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.0",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.0-RC1",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.0-BETA2",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.4.0-BETA1",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.3.11",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.3.10",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.3.9",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.3.8",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.3.7",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.3.6",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.3.5",
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.3.4",
|
||||
"type": "library"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
--RUN--
|
||||
update
|
||||
|
||||
--EXPECT--
|
||||
|
||||
--EXPECT-OUTPUT--
|
||||
|
||||
--EXPECT-EXIT-CODE--
|
||||
2
|
|
@ -37,9 +37,9 @@ Updating dependencies
|
|||
Your requirements could not be resolved to an installable set of packages.
|
||||
|
||||
Problem 1
|
||||
- Conclusion: don't install regular/pkg 1.0.3 (conflict analysis result)
|
||||
- Conclusion: don't install regular/pkg 1.0.2 (conflict analysis result)
|
||||
- Conclusion: don't install regular/pkg 1.0.1 (conflict analysis result)
|
||||
- Conclusion: don't install regular/pkg 1.0.2 (conflict analysis result)
|
||||
- Conclusion: don't install regular/pkg 1.0.3 (conflict analysis result)
|
||||
- Only one of these can be installed: regular/pkg[1.0.0, 1.0.1, 1.0.2, 1.0.3], replacer/pkg[2.0.0, 2.0.1, 2.0.2, 2.0.3]. replacer/pkg replaces regular/pkg and thus cannot coexist with it.
|
||||
- Root composer.json requires regular/pkg 1.* -> satisfiable by regular/pkg[1.0.0, 1.0.1, 1.0.2, 1.0.3].
|
||||
- Root composer.json requires replacer/pkg 2.* -> satisfiable by replacer/pkg[2.0.0, 2.0.1, 2.0.2, 2.0.3].
|
||||
|
|
Loading…
Reference in New Issue