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 16 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/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ time_ns() = ccall(:jl_hrtime, UInt64, ())

start_base_include = time_ns()

# A warning to be interpolated in the docstring of every dangerous mutating function in Base, see PR #50824
const _DOCS_ALIASING_WARNING = """
!!! warning
Behavior can be unexpected when any mutated argument shares memory with any other argument.
"""

## Load essential files and libraries
include("essentials.jl")
include("ctypes.jl")
Expand Down
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).

$(_DOCS_ALIASING_WARNING)

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)`.

$(_DOCS_ALIASING_WARNING)

# 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.

$(_DOCS_ALIASING_WARNING)

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.

$(_DOCS_ALIASING_WARNING)

# 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.

$(_DOCS_ALIASING_WARNING)
"""
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.

$(_DOCS_ALIASING_WARNING)

# 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.

$(_DOCS_ALIASING_WARNING)
"""
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).

$(_DOCS_ALIASING_WARNING)
"""
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).

$(_DOCS_ALIASING_WARNING)
"""
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).

$(_DOCS_ALIASING_WARNING)
"""
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.

$(_DOCS_ALIASING_WARNING)

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.

$(_DOCS_ALIASING_WARNING)
"""
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)`.

$(_DOCS_ALIASING_WARNING)

!!! 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.

$(_DOCS_ALIASING_WARNING)

`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.

$(_DOCS_ALIASING_WARNING)
"""
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.)

$(_DOCS_ALIASING_WARNING)

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.)

$(_DOCS_ALIASING_WARNING)

# 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).
$(_DOCS_ALIASING_WARNING)

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`.

$(_DOCS_ALIASING_WARNING)

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.

$(_DOCS_ALIASING_WARNING)

!!! 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.

$(_DOCS_ALIASING_WARNING)

# 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`.

$(_DOCS_ALIASING_WARNING)

# 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`.

$(_DOCS_ALIASING_WARNING)

# 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`.

$(_DOCS_ALIASING_WARNING)

# 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`.

$(_DOCS_ALIASING_WARNING)

!!! 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`.

$(_DOCS_ALIASING_WARNING)

# 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`.

$(_DOCS_ALIASING_WARNING)

# 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`.

$(_DOCS_ALIASING_WARNING)
"""
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`.

$(_DOCS_ALIASING_WARNING)
"""
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.

$(_DOCS_ALIASING_WARNING)
LilithHafner marked this conversation as resolved.
Show resolved Hide resolved

# 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)`.

$(_DOCS_ALIASING_WARNING)
LilithHafner marked this conversation as resolved.
Show resolved Hide resolved

!!! 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 produces the expected result, it is the responsibility of the caller to ensure proper behavior on such inputs.

## Argument-type declarations

Expand Down