Skip to content

Commit 8f560de

Browse files
authored
Fix ParAff Alt error behavior (#111)
1 parent b79371c commit 8f560de

File tree

2 files changed

+80
-49
lines changed

2 files changed

+80
-49
lines changed

src/Control/Monad/Aff.js

Lines changed: 71 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -646,18 +646,20 @@ var Aff = function () {
646646

647647
switch (step.tag) {
648648
case FORKED:
649-
tmp = fibers[step._1];
650-
kills[count++] = tmp.kill(error, function (result) {
651-
return function () {
652-
count--;
653-
if (fail === null && util.isLeft(result)) {
654-
fail = result;
655-
}
656-
if (count === 0) {
657-
cb(fail || util.right(void 0))();
658-
}
659-
};
660-
});
649+
if (step._3 === EMPTY) {
650+
tmp = fibers[step._1];
651+
kills[count++] = tmp.kill(error, function (result) {
652+
return function () {
653+
count--;
654+
if (fail === null && util.isLeft(result)) {
655+
fail = result;
656+
}
657+
if (count === 0) {
658+
cb(fail || util.right(void 0))();
659+
}
660+
};
661+
});
662+
}
661663
// Terminal case.
662664
if (head === null) {
663665
break loop;
@@ -685,11 +687,15 @@ var Aff = function () {
685687
}
686688
}
687689

688-
// Run the cancelation effects. We alias `count` because it's mutable.
689-
kid = 0;
690-
tmp = count;
691-
for (; kid < tmp; kid++) {
692-
kills[kid] = kills[kid]();
690+
if (count === 0) {
691+
cb(fail || util.right(void 0))();
692+
} else {
693+
// Run the cancelation effects. We alias `count` because it's mutable.
694+
kid = 0;
695+
tmp = count;
696+
for (; kid < tmp; kid++) {
697+
kills[kid] = kills[kid]();
698+
}
693699
}
694700

695701
return kills;
@@ -753,48 +759,64 @@ var Aff = function () {
753759
// the first error.
754760
if (util.isLeft(lhs)) {
755761
if (util.isLeft(rhs)) {
756-
if (step === lhs) {
757-
step = rhs;
762+
if (fail === lhs) {
763+
fail = rhs;
758764
}
759765
} else {
760-
step = lhs;
766+
fail = lhs;
761767
}
768+
step = null;
769+
head._3 = fail;
762770
} else if (util.isLeft(rhs)) {
763-
step = rhs;
771+
step = null;
772+
fail = rhs;
773+
head._3 = fail;
764774
} else {
765-
head._3 = util.right(util.fromRight(lhs)(util.fromRight(rhs)));
766-
step = head._3;
775+
step = util.right(util.fromRight(lhs)(util.fromRight(rhs)));
776+
head._3 = step;
767777
}
768778
break;
769779
case ALT:
770-
lhs = head._1._3;
771-
rhs = head._2._3;
772-
head._3 = step;
773-
tmp = true;
774-
kid = killId++;
775-
// Once a side has resolved, we need to cancel the side that is still
776-
// pending before we can continue.
777-
kills[kid] = kill(early, step === lhs ? head._2 : head._1, function (killResult) {
778-
return function () {
779-
delete kills[kid];
780-
if (util.isLeft(killResult)) {
781-
fail = killResult;
782-
step = null;
783-
}
784-
if (tmp) {
785-
tmp = false;
786-
} else if (tail === null) {
787-
join(fail || step, null, null);
788-
} else {
789-
join(fail || step, tail._1, tail._2);
790-
}
791-
};
792-
});
793-
794-
if (tmp) {
795-
tmp = false;
780+
lhs = head._1._3;
781+
rhs = head._2._3;
782+
// We can only proceed if both have resolved or we have a success
783+
if (lhs === EMPTY && util.isLeft(rhs) || rhs === EMPTY && util.isLeft(lhs)) {
796784
return;
797785
}
786+
// If both sides resolve with an error, we should continue with the
787+
// first error
788+
if (lhs !== EMPTY && util.isLeft(lhs) && rhs !== EMPTY && util.isLeft(rhs)) {
789+
fail = step === lhs ? rhs : lhs;
790+
step = null;
791+
head._3 = fail;
792+
} else {
793+
head._3 = step;
794+
tmp = true;
795+
kid = killId++;
796+
// Once a side has resolved, we need to cancel the side that is still
797+
// pending before we can continue.
798+
kills[kid] = kill(early, step === lhs ? head._2 : head._1, function (killResult) {
799+
return function () {
800+
delete kills[kid];
801+
if (util.isLeft(killResult)) {
802+
fail = killResult;
803+
step = null;
804+
}
805+
if (tmp) {
806+
tmp = false;
807+
} else if (tail === null) {
808+
join(fail || step, null, null);
809+
} else {
810+
join(fail || step, tail._1, tail._2);
811+
}
812+
};
813+
});
814+
815+
if (tmp) {
816+
tmp = false;
817+
return;
818+
}
819+
}
798820
break;
799821
}
800822

test/Test/Main.purs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,14 @@ test_parallel_alt = assert "parallel/alt" do
420420
r2 ← joinFiber f1
421421
pure (r1 == "bar" && r2 == "bar")
422422

423+
test_parallel_alt_throw eff. TestAff eff Unit
424+
test_parallel_alt_throw = assert "parallel/alt/throw" do
425+
r1 ← sequential $
426+
parallel (delay (Milliseconds 10.0) *> throwError (error "Nope."))
427+
<|> parallel (delay (Milliseconds 11.0) $> "foo")
428+
<|> parallel (delay (Milliseconds 12.0) $> "bar")
429+
pure (r1 == "foo")
430+
423431
test_parallel_alt_sync eff. TestAff eff Unit
424432
test_parallel_alt_sync = assert "parallel/alt/sync" do
425433
ref ← newRef ""
@@ -569,6 +577,7 @@ main = do
569577
test_parallel
570578
test_kill_parallel
571579
test_parallel_alt
580+
test_parallel_alt_throw
572581
test_parallel_alt_sync
573582
test_parallel_mixed
574583
test_kill_parallel_alt

0 commit comments

Comments
 (0)