From ed4cb8a4968c3be4f4a90adc5525d04bf3377d8a Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Fri, 11 May 2018 17:58:26 -0400 Subject: [PATCH] More robust iteration over Vectors Currently, if a vector is resized in the midst of iteration, then `done` might "miss" the end of iteration. This trivially changes the definition to catch such a case. I am not sure what guarantees we make about mutating iterables during iteration, but this seems simple and easy to support. Note, though, that it is somewhat tricky: until #13866 we used `i > length(a)`, but that foils vectorization due to the `typemax` case. This definition seems to get the best of both worlds. For a definition like `f` below, this new definition just requires one extra `add i64` operation in the preamble (before the loop). Everything else is identical to master. ```julia function f(A) r = 0 @inbounds for x in A r += x end r end ``` --- base/array.jl | 2 +- test/arrayops.jl | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/base/array.jl b/base/array.jl index 86050b207a608..aa4910cbeefde 100644 --- a/base/array.jl +++ b/base/array.jl @@ -642,7 +642,7 @@ end ## Iteration ## start(A::Array) = 1 next(a::Array,i) = (@_propagate_inbounds_meta; (a[i],i+1)) -done(a::Array,i) = (@_inline_meta; i == length(a)+1) +done(a::Array,i) = (@_inline_meta; i >= length(a)+1) ## Indexing: getindex ## diff --git a/test/arrayops.jl b/test/arrayops.jl index 82d213a3d6a1e..e17ddd60b3d63 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -2424,6 +2424,25 @@ end @inferred hash([1,2,3]) end +function f27079() + X = rand(5) + for x in X + resize!(X, 0) + end + length(X) +end +function g27079(X) + r = 0 + @inbounds for x in X + r += x + end + r +end +@testset "iteration over resized vector" begin + @test f27079() == 0 + @test occursin("vector.body", sprint(code_llvm, g27079, Tuple{Vector{Int}})) +end + @testset "indices-related shape promotion errors" begin @test_throws DimensionMismatch Base.promote_shape((2,), (3,)) @test_throws DimensionMismatch Base.promote_shape((2, 3), (2, 4))