Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some aliasing warnings to docstrings for mutating functions in Base #50824

Merged
merged 17 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,8 @@ If `dst` and `src` are of the same type, `dst == src` should hold after
the call. If `dst` and `src` are multidimensional arrays, they must have
equal [`axes`](@ref).

Behavior can be unexpected when any mutated argument shares memory with any other argument.

gdalle marked this conversation as resolved.
Show resolved Hide resolved
See also [`copyto!`](@ref).

!!! compat "Julia 1.1"
Expand Down Expand Up @@ -1369,6 +1371,8 @@ _unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
Store values from array `X` within some subset of `A` as specified by `inds`.
The syntax `A[inds...] = X` is equivalent to `(setindex!(A, X, inds...); X)`.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

# Examples
```jldoctest
julia> A = zeros(2,2);
Expand Down Expand Up @@ -3340,6 +3344,8 @@ end
Like [`map`](@ref), but stores the result in `destination` rather than a new
collection. `destination` must be at least as large as the smallest collection.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

See also: [`map`](@ref), [`foreach`](@ref), [`zip`](@ref), [`copyto!`](@ref).

# Examples
Expand Down
8 changes: 8 additions & 0 deletions base/abstractset.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ const ∪ = union
Construct the [`union`](@ref) of passed in sets and overwrite `s` with the result.
Maintain order with arrays.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

# Examples
```jldoctest
julia> a = Set([3, 4, 5]);
Expand Down Expand Up @@ -182,6 +184,8 @@ const ∩ = intersect

Intersect all passed in sets and overwrite `s` with the result.
Maintain order with arrays.

Behavior can be unexpected when any mutated argument shares memory with any other argument.
"""
function intersect!(s::AbstractSet, itrs...)
for x in itrs
Expand Down Expand Up @@ -218,6 +222,8 @@ setdiff(s) = union(s)
Remove from set `s` (in-place) each element of each iterable from `itrs`.
Maintain order with arrays.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

# Examples
```jldoctest
julia> a = Set([1, 3, 4, 5]);
Expand Down Expand Up @@ -272,6 +278,8 @@ symdiff(s) = symdiff!(copy(s))
Construct the symmetric difference of the passed in sets, and overwrite `s` with the result.
When `s` is an array, the order is maintained.
Note that in this case the multiplicity of elements matters.

Behavior can be unexpected when any mutated argument shares memory with any other argument.
"""
function symdiff!(s::AbstractSet, itrs...)
for x in itrs
Expand Down
8 changes: 8 additions & 0 deletions base/accumulate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ end
cumsum!(B, A; dims::Integer)

Cumulative sum of `A` along the dimension `dims`, storing the result in `B`. See also [`cumsum`](@ref).

Behavior can be unexpected when any mutated argument shares memory with any other argument.
"""
cumsum!(B::AbstractArray{T}, A; dims::Integer) where {T} =
accumulate!(add_sum, B, A, dims=dims)
Expand Down Expand Up @@ -150,6 +152,8 @@ cumsum(itr) = accumulate(add_sum, itr)

Cumulative product of `A` along the dimension `dims`, storing the result in `B`.
See also [`cumprod`](@ref).

Behavior can be unexpected when any mutated argument shares memory with any other argument.
"""
cumprod!(B::AbstractArray{T}, A; dims::Integer) where {T} =
accumulate!(mul_prod, B, A, dims=dims)
Expand All @@ -159,6 +163,8 @@ cumprod!(B::AbstractArray{T}, A; dims::Integer) where {T} =

Cumulative product of a vector `x`, storing the result in `y`.
See also [`cumprod`](@ref).

Behavior can be unexpected when any mutated argument shares memory with any other argument.
"""
cumprod!(y::AbstractVector, x::AbstractVector) = cumprod!(y, x, dims=1)

Expand Down Expand Up @@ -301,6 +307,8 @@ Cumulative operation `op` on `A` along the dimension `dims`, storing the result
Providing `dims` is optional for vectors. If the keyword argument `init` is given, its
value is used to instantiate the accumulation.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

See also [`accumulate`](@ref), [`cumsum!`](@ref), [`cumprod!`](@ref).

# Examples
Expand Down
6 changes: 6 additions & 0 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@ source and `do` in the destination (1-indexed).
The `unsafe` prefix on this function indicates that no validation is performed to ensure
that N is inbounds on either array. Incorrect usage may corrupt or segfault your program, in
the same manner as C.

Behavior can be unexpected when any mutated argument shares memory with any other argument.
"""
function unsafe_copyto!(dest::Array{T}, doffs, src::Array{T}, soffs, n) where T
t1 = @_gc_preserve_begin dest
Expand Down Expand Up @@ -1781,6 +1783,8 @@ place of the removed items; in this case, `indices` must be a `AbstractUnitRange
To insert `replacement` before an index `n` without removing any items, use
`splice!(collection, n:n-1, replacement)`.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

!!! compat "Julia 1.5"
Prior to Julia 1.5, `indices` must always be a `UnitRange`.

Expand Down Expand Up @@ -2782,6 +2786,8 @@ Remove the items at all the indices which are not given by `inds`,
and return the modified `a`.
Items which are kept are shifted to fill the resulting gaps.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

`inds` must be an iterator of sorted and unique integer indices.
See also [`deleteat!`](@ref).

Expand Down
2 changes: 2 additions & 0 deletions base/asyncmap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,8 @@ length(itr::AsyncGenerator) = length(itr.collector.enumerator)

Like [`asyncmap`](@ref), but stores output in `results` rather than
returning a collection.

Behavior can be unexpected when any mutated argument shares memory with any other argument.
"""
function asyncmap!(f, r, c1, c...; ntasks=0, batch_size=nothing)
foreach(identity, AsyncCollector(f, r, c1, c...; ntasks=ntasks, batch_size=batch_size))
Expand Down
4 changes: 4 additions & 0 deletions base/combinatorics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ it is even faster to write into a pre-allocated output array with `u .= @view v[
(Even though `permute!` overwrites `v` in-place, it internally requires some allocation
to keep track of which elements have been moved.)

Behavior can be unexpected when any mutated argument shares memory with any other argument.

See also [`invpermute!`](@ref).

# Examples
Expand Down Expand Up @@ -222,6 +224,8 @@ Note that if you have a pre-allocated output array (e.g. `u = similar(v)`),
it is quicker to instead employ `u[p] = v`. (`invpermute!` internally
allocates a copy of the data.)

Behavior can be unexpected when any mutated argument shares memory with any other argument.

# Examples
```jldoctest
julia> A = [1, 1, 3, 4];
Expand Down
5 changes: 3 additions & 2 deletions base/multidimensional.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1179,8 +1179,7 @@ circshift!(dest::AbstractArray, src, ::Tuple{}) = copyto!(dest, src)
Circularly shift, i.e. rotate, the data in `src`, storing the result in
`dest`. `shifts` specifies the amount to shift in each dimension.

The `dest` array must be distinct from the `src` array (they cannot
alias each other).
Behavior can be unexpected when any mutated argument shares memory with any other argument.

See also [`circshift`](@ref).
"""
Expand Down Expand Up @@ -1238,6 +1237,8 @@ their indices; any offset results in a (circular) wraparound. If the
arrays have overlapping indices, then on the domain of the overlap
`dest` agrees with `src`.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

See also: [`circshift`](@ref).

# Examples
Expand Down
22 changes: 20 additions & 2 deletions base/reducedim.jl
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,8 @@ _count(f, A::AbstractArrayOrBroadcasted, dims, init) = mapreduce(_bool(f), add_s
Count the number of elements in `A` for which `f` returns `true` over the
singleton dimensions of `r`, writing the result into `r` in-place.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

!!! compat "Julia 1.5"
inplace `count!` was added in Julia 1.5.

Expand Down Expand Up @@ -525,8 +527,8 @@ sum(f, A::AbstractArray; dims)
sum!(r, A)

Sum elements of `A` over the singleton dimensions of `r`, and write results to `r`.
Note that since the sum! function is intended to operate without making any allocations,
the target should not alias with the source.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

# Examples
```jldoctest
Expand Down Expand Up @@ -601,6 +603,8 @@ prod(f, A::AbstractArray; dims)

Multiply elements of `A` over the singleton dimensions of `r`, and write results to `r`.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

# Examples
```jldoctest
julia> A = [1 2; 3 4]
Expand Down Expand Up @@ -678,6 +682,8 @@ maximum(f, A::AbstractArray; dims)

Compute the maximum value of `A` over the singleton dimensions of `r`, and write results to `r`.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

# Examples
```jldoctest
julia> A = [1 2; 3 4]
Expand Down Expand Up @@ -755,6 +761,8 @@ minimum(f, A::AbstractArray; dims)

Compute the minimum value of `A` over the singleton dimensions of `r`, and write results to `r`.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

# Examples
```jldoctest
julia> A = [1 2; 3 4]
Expand Down Expand Up @@ -820,6 +828,8 @@ extrema(f, A::AbstractArray; dims)

Compute the minimum and maximum value of `A` over the singleton dimensions of `r`, and write results to `r`.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

!!! compat "Julia 1.8"
This method requires Julia 1.8 or later.

Expand Down Expand Up @@ -895,6 +905,8 @@ all(::Function, ::AbstractArray; dims)

Test whether all values in `A` along the singleton dimensions of `r` are `true`, and write results to `r`.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

# Examples
```jldoctest
julia> A = [true false; true false]
Expand Down Expand Up @@ -968,6 +980,8 @@ any(::Function, ::AbstractArray; dims)
Test whether any values in `A` along the singleton dimensions of `r` are `true`, and write
results to `r`.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

# Examples
```jldoctest
julia> A = [true false; true false]
Expand Down Expand Up @@ -1085,6 +1099,8 @@ end
Find the minimum of `A` and the corresponding linear index along singleton
dimensions of `rval` and `rind`, and store the results in `rval` and `rind`.
`NaN` is treated as less than all other values except `missing`.

Behavior can be unexpected when any mutated argument shares memory with any other argument.
"""
function findmin!(rval::AbstractArray, rind::AbstractArray, A::AbstractArray;
init::Bool=true)
Expand Down Expand Up @@ -1156,6 +1172,8 @@ end
Find the maximum of `A` and the corresponding linear index along singleton
dimensions of `rval` and `rind`, and store the results in `rval` and `rind`.
`NaN` is treated as greater than all other values except `missing`.

Behavior can be unexpected when any mutated argument shares memory with any other argument.
"""
function findmax!(rval::AbstractArray, rind::AbstractArray, A::AbstractArray;
init::Bool=true)
Expand Down
4 changes: 4 additions & 0 deletions base/sort.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1583,6 +1583,8 @@ v[ix[k]] == partialsort(v, k)
The return value is the `k`th element of `ix` if `k` is an integer, or view into `ix` if `k` is
a range.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

# Examples
```jldoctest
julia> v = [3, 1, 2, 1];
Expand Down Expand Up @@ -1707,6 +1709,8 @@ end
Like [`sortperm`](@ref), but accepts a preallocated index vector or array `ix` with the same `axes` as `A`.
`ix` is initialized to contain the values `LinearIndices(A)`.

Behavior can be unexpected when any mutated argument shares memory with any other argument.

!!! compat "Julia 1.9"
The method accepting `dims` requires at least Julia 1.9.

Expand Down
3 changes: 3 additions & 0 deletions doc/src/manual/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ As a common convention in Julia (not a syntactic requirement), such a function w
[typically be named `f!(x, y)`](@ref man-punctuation) rather than `f(x, y)`, as a visual reminder at
the call site that at least one of the arguments (often the first one) is being mutated.

!!! warning "Shared memory between arguments"
The behavior of a mutating function can be unexpected when a mutated argument shares memory with another argument, a situation known as aliasing (e.g. when one is a view of the other).
Unless the function docstring explicitly indicates that aliasing is safe, it is the responsibility of the caller to ensure proper behavior on such inputs.

## Argument-type declarations

Expand Down