When changing watched literals of a rule, update the parent's next pointer
The previous rule was not previously updated to point to the next rule when removing a middle rule from the watch tree for a literal. This resulted in jumping from one literal's watch tree to another's, which could then jump back to the original and cause infinite loop in a case like #265. Fixes #265pull/325/head
parent
8484199677
commit
1ee5d99405
|
@ -1222,7 +1222,8 @@ class Solver
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ($rule = $this->watches[$literal->getId()]; $rule !== null; $rule = $nextRule) {
|
$prevRule = null;
|
||||||
|
for ($rule = $this->watches[$literal->getId()]; $rule !== null; $prevRule = $rule, $rule = $nextRule) {
|
||||||
$nextRule = $rule->getNext($literal);
|
$nextRule = $rule->getNext($literal);
|
||||||
|
|
||||||
if ($rule->isDisabled()) {
|
if ($rule->isDisabled()) {
|
||||||
|
@ -1242,13 +1243,23 @@ class Solver
|
||||||
if ($otherWatch !== $ruleLiteral->getId() &&
|
if ($otherWatch !== $ruleLiteral->getId() &&
|
||||||
!$this->decisionsConflict($ruleLiteral)) {
|
!$this->decisionsConflict($ruleLiteral)) {
|
||||||
|
|
||||||
|
|
||||||
if ($literal->getId() === $rule->watch1) {
|
if ($literal->getId() === $rule->watch1) {
|
||||||
$rule->watch1 = $ruleLiteral->getId();
|
$rule->watch1 = $ruleLiteral->getId();
|
||||||
$rule->next1 = (isset($this->watches[$ruleLiteral->getId()])) ? $this->watches[$ruleLiteral->getId()] : null ;
|
$rule->next1 = (isset($this->watches[$ruleLiteral->getId()])) ? $this->watches[$ruleLiteral->getId()] : null;
|
||||||
} else {
|
} else {
|
||||||
$rule->watch2 = $ruleLiteral->getId();
|
$rule->watch2 = $ruleLiteral->getId();
|
||||||
$rule->next2 = (isset($this->watches[$ruleLiteral->getId()])) ? $this->watches[$ruleLiteral->getId()] : null ;
|
$rule->next2 = (isset($this->watches[$ruleLiteral->getId()])) ? $this->watches[$ruleLiteral->getId()] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prevRule) {
|
||||||
|
if ($prevRule->watch1 === $literal->getId()) {
|
||||||
|
$prevRule->next1 = $nextRule;
|
||||||
|
} else {
|
||||||
|
$prevRule->next2 = $nextRule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->watches[$literal->getId()] = $nextRule;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->watches[$ruleLiteral->getId()] = $rule;
|
$this->watches[$ruleLiteral->getId()] = $rule;
|
||||||
|
|
|
@ -485,6 +485,40 @@ class SolverTest extends TestCase
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testIssue265()
|
||||||
|
{
|
||||||
|
$this->repo->addPackage($packageA1 = $this->getPackage('A', '2.0.999999-dev'));
|
||||||
|
$this->repo->addPackage($packageA2 = $this->getPackage('A', '2.1-dev'));
|
||||||
|
$this->repo->addPackage($packageA3 = $this->getPackage('A', '2.2-dev'));
|
||||||
|
$this->repo->addPackage($packageB1 = $this->getPackage('B', '2.0.10'));
|
||||||
|
$this->repo->addPackage($packageB2 = $this->getPackage('B', '2.0.9'));
|
||||||
|
$this->repo->addPackage($packageC = $this->getPackage('C', '2.0-dev'));
|
||||||
|
$this->repo->addPackage($packageD = $this->getPackage('D', '2.0.9'));
|
||||||
|
|
||||||
|
$packageC->setRequires(array(
|
||||||
|
new Link('C', 'A', new VersionConstraint('>=', '2.0'), 'requires'),
|
||||||
|
new Link('C', 'D', new VersionConstraint('>=', '2.0'), 'requires'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$packageD->setRequires(array(
|
||||||
|
new Link('D', 'A', new VersionConstraint('>=', '2.1'), 'requires'),
|
||||||
|
new Link('D', 'B', new VersionConstraint('>=', '2.0-dev'), 'requires'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$packageB1->setRequires(array(new Link('B', 'A', new VersionConstraint('==', '2.1.0.0-dev'), 'requires')));
|
||||||
|
$packageB2->setRequires(array(new Link('B', 'A', new VersionConstraint('==', '2.1.0.0-dev'), 'requires')));
|
||||||
|
|
||||||
|
$packageB2->setReplaces(array(new Link('B', 'D', new VersionConstraint('==', '2.0.9.0'), 'replaces')));
|
||||||
|
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('C', new VersionConstraint('==', '2.0.0.0-dev'));
|
||||||
|
|
||||||
|
$this->setExpectedException('Composer\DependencyResolver\SolverProblemsException');
|
||||||
|
|
||||||
|
$this->solver->solve($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
public function testConflictResultEmpty()
|
public function testConflictResultEmpty()
|
||||||
{
|
{
|
||||||
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
|
Loading…
Reference in New Issue