Skip to content

Commit 88b62b6

Browse files
author
bors-servo
authored
Auto merge of #150 - ehuss:extend-resume, r=emilio
Fix `extend` from assuming a fused iterator. Iterators may resume after returning None. I think it is generally expected that `extend` should stop on the first None. Fixes #147. Specifically, in rustc, there are some situations where an iterator of Results are collected into a `Result<SmallVec, _>` (such as [here](https://github.com/rust-lang/rust/blob/c1c60d292e2dd2deff7084208274f9a02f750d43/src/librustc/ty/relate.rs#L139-L142) which ends up in [this call to `collect`](https://github.com/rust-lang/rust/blob/c1c60d292e2dd2deff7084208274f9a02f750d43/src/librustc/ty/context.rs#L3002)). The [Result adapter](https://github.com/rust-lang/rust/blob/c1c60d292e2dd2deff7084208274f9a02f750d43/src/libcore/result.rs#L1245-L1258) returns None for the first `Err` in the sequence. However, it is possible for an iterator to have additional elements after the first Err. With this bug, SmallVec was falling through to the slow-path `for` loop, and resuming the iterator grabbing too many elements. I believe this was having some bad interactions with the type interner where the additional elements after the `Err` were getting processed (via a `map()`) and interned when they shouldn't be (or otherwise having some side effects from the `map`). <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/rust-smallvec/150) <!-- Reviewable:end -->
2 parents f96322b + 1fbaf10 commit 88b62b6

File tree

1 file changed

+13
-1
lines changed

1 file changed

+13
-1
lines changed

lib.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -1356,7 +1356,7 @@ impl<A: Array> Extend<A::Item> for SmallVec<A> {
13561356
ptr::write(ptr.offset(len.get() as isize), out);
13571357
len.increment_len(1);
13581358
} else {
1359-
break;
1359+
return;
13601360
}
13611361
}
13621362
}
@@ -2329,4 +2329,16 @@ mod tests {
23292329
v.push(4);
23302330
assert_eq!(v[..], [4]);
23312331
}
2332+
2333+
#[test]
2334+
fn resumable_extend() {
2335+
let s = "a b c";
2336+
// This iterator yields: (Some('a'), None, Some('b'), None, Some('c')), None
2337+
let it = s
2338+
.chars()
2339+
.scan(0, |_, ch| if ch.is_whitespace() { None } else { Some(ch) });
2340+
let mut v: SmallVec<[char; 4]> = SmallVec::new();
2341+
v.extend(it);
2342+
assert_eq!(v[..], ['a']);
2343+
}
23322344
}

0 commit comments

Comments
 (0)