Skip to content

Commit 35264b7

Browse files
gdalleKristofferC
authored andcommitted
Add aliasing warnings to docstrings for mutating functions in Base (#50824)
(cherry picked from commit 58030da)
1 parent db55742 commit 35264b7

11 files changed

+70
-4
lines changed

base/Base.jl

+6
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ time_ns() = ccall(:jl_hrtime, UInt64, ())
115115

116116
start_base_include = time_ns()
117117

118+
# A warning to be interpolated in the docstring of every dangerous mutating function in Base, see PR #50824
119+
const _DOCS_ALIASING_WARNING = """
120+
!!! warning
121+
Behavior can be unexpected when any mutated argument shares memory with any other argument.
122+
"""
123+
118124
## Load essential files and libraries
119125
include("essentials.jl")
120126
include("ctypes.jl")

base/abstractarray.jl

+6
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,8 @@ If `dst` and `src` are of the same type, `dst == src` should hold after
905905
the call. If `dst` and `src` are multidimensional arrays, they must have
906906
equal [`axes`](@ref).
907907
908+
$(_DOCS_ALIASING_WARNING)
909+
908910
See also [`copyto!`](@ref).
909911
910912
!!! compat "Julia 1.1"
@@ -1369,6 +1371,8 @@ _unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
13691371
Store values from array `X` within some subset of `A` as specified by `inds`.
13701372
The syntax `A[inds...] = X` is equivalent to `(setindex!(A, X, inds...); X)`.
13711373
1374+
$(_DOCS_ALIASING_WARNING)
1375+
13721376
# Examples
13731377
```jldoctest
13741378
julia> A = zeros(2,2);
@@ -3339,6 +3343,8 @@ end
33393343
Like [`map`](@ref), but stores the result in `destination` rather than a new
33403344
collection. `destination` must be at least as large as the smallest collection.
33413345
3346+
$(_DOCS_ALIASING_WARNING)
3347+
33423348
See also: [`map`](@ref), [`foreach`](@ref), [`zip`](@ref), [`copyto!`](@ref).
33433349
33443350
# Examples

base/abstractset.jl

+8
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ const ∪ = union
6565
Construct the [`union`](@ref) of passed in sets and overwrite `s` with the result.
6666
Maintain order with arrays.
6767
68+
$(_DOCS_ALIASING_WARNING)
69+
6870
# Examples
6971
```jldoctest
7072
julia> a = Set([3, 4, 5]);
@@ -182,6 +184,8 @@ const ∩ = intersect
182184
183185
Intersect all passed in sets and overwrite `s` with the result.
184186
Maintain order with arrays.
187+
188+
$(_DOCS_ALIASING_WARNING)
185189
"""
186190
function intersect!(s::AbstractSet, itrs...)
187191
for x in itrs
@@ -218,6 +222,8 @@ setdiff(s) = union(s)
218222
Remove from set `s` (in-place) each element of each iterable from `itrs`.
219223
Maintain order with arrays.
220224
225+
$(_DOCS_ALIASING_WARNING)
226+
221227
# Examples
222228
```jldoctest
223229
julia> a = Set([1, 3, 4, 5]);
@@ -272,6 +278,8 @@ symdiff(s) = symdiff!(copy(s))
272278
Construct the symmetric difference of the passed in sets, and overwrite `s` with the result.
273279
When `s` is an array, the order is maintained.
274280
Note that in this case the multiplicity of elements matters.
281+
282+
$(_DOCS_ALIASING_WARNING)
275283
"""
276284
function symdiff!(s::AbstractSet, itrs...)
277285
for x in itrs

base/accumulate.jl

+8
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ end
4242
cumsum!(B, A; dims::Integer)
4343
4444
Cumulative sum of `A` along the dimension `dims`, storing the result in `B`. See also [`cumsum`](@ref).
45+
46+
$(_DOCS_ALIASING_WARNING)
4547
"""
4648
cumsum!(B::AbstractArray{T}, A; dims::Integer) where {T} =
4749
accumulate!(add_sum, B, A, dims=dims)
@@ -150,6 +152,8 @@ cumsum(itr) = accumulate(add_sum, itr)
150152
151153
Cumulative product of `A` along the dimension `dims`, storing the result in `B`.
152154
See also [`cumprod`](@ref).
155+
156+
$(_DOCS_ALIASING_WARNING)
153157
"""
154158
cumprod!(B::AbstractArray{T}, A; dims::Integer) where {T} =
155159
accumulate!(mul_prod, B, A, dims=dims)
@@ -159,6 +163,8 @@ cumprod!(B::AbstractArray{T}, A; dims::Integer) where {T} =
159163
160164
Cumulative product of a vector `x`, storing the result in `y`.
161165
See also [`cumprod`](@ref).
166+
167+
$(_DOCS_ALIASING_WARNING)
162168
"""
163169
cumprod!(y::AbstractVector, x::AbstractVector) = cumprod!(y, x, dims=1)
164170

@@ -301,6 +307,8 @@ Cumulative operation `op` on `A` along the dimension `dims`, storing the result
301307
Providing `dims` is optional for vectors. If the keyword argument `init` is given, its
302308
value is used to instantiate the accumulation.
303309
310+
$(_DOCS_ALIASING_WARNING)
311+
304312
See also [`accumulate`](@ref), [`cumsum!`](@ref), [`cumprod!`](@ref).
305313
306314
# Examples

base/array.jl

+6
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,8 @@ source and `do` in the destination (1-indexed).
322322
The `unsafe` prefix on this function indicates that no validation is performed to ensure
323323
that N is inbounds on either array. Incorrect usage may corrupt or segfault your program, in
324324
the same manner as C.
325+
326+
$(_DOCS_ALIASING_WARNING)
325327
"""
326328
function unsafe_copyto!(dest::Array{T}, doffs, src::Array{T}, soffs, n) where T
327329
t1 = @_gc_preserve_begin dest
@@ -1781,6 +1783,8 @@ place of the removed items; in this case, `indices` must be a `AbstractUnitRange
17811783
To insert `replacement` before an index `n` without removing any items, use
17821784
`splice!(collection, n:n-1, replacement)`.
17831785
1786+
$(_DOCS_ALIASING_WARNING)
1787+
17841788
!!! compat "Julia 1.5"
17851789
Prior to Julia 1.5, `indices` must always be a `UnitRange`.
17861790
@@ -2760,6 +2764,8 @@ Remove the items at all the indices which are not given by `inds`,
27602764
and return the modified `a`.
27612765
Items which are kept are shifted to fill the resulting gaps.
27622766
2767+
$(_DOCS_ALIASING_WARNING)
2768+
27632769
`inds` must be an iterator of sorted and unique integer indices.
27642770
See also [`deleteat!`](@ref).
27652771

base/asyncmap.jl

+2
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,8 @@ length(itr::AsyncGenerator) = length(itr.collector.enumerator)
394394
395395
Like [`asyncmap`](@ref), but stores output in `results` rather than
396396
returning a collection.
397+
398+
$(_DOCS_ALIASING_WARNING)
397399
"""
398400
function asyncmap!(f, r, c1, c...; ntasks=0, batch_size=nothing)
399401
foreach(identity, AsyncCollector(f, r, c1, c...; ntasks=ntasks, batch_size=batch_size))

base/combinatorics.jl

+4
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ it is even faster to write into a pre-allocated output array with `u .= @view v[
169169
(Even though `permute!` overwrites `v` in-place, it internally requires some allocation
170170
to keep track of which elements have been moved.)
171171
172+
$(_DOCS_ALIASING_WARNING)
173+
172174
See also [`invpermute!`](@ref).
173175
174176
# Examples
@@ -222,6 +224,8 @@ Note that if you have a pre-allocated output array (e.g. `u = similar(v)`),
222224
it is quicker to instead employ `u[p] = v`. (`invpermute!` internally
223225
allocates a copy of the data.)
224226
227+
$(_DOCS_ALIASING_WARNING)
228+
225229
# Examples
226230
```jldoctest
227231
julia> A = [1, 1, 3, 4];

base/multidimensional.jl

+3-2
Original file line numberDiff line numberDiff line change
@@ -1179,8 +1179,7 @@ circshift!(dest::AbstractArray, src, ::Tuple{}) = copyto!(dest, src)
11791179
Circularly shift, i.e. rotate, the data in `src`, storing the result in
11801180
`dest`. `shifts` specifies the amount to shift in each dimension.
11811181
1182-
The `dest` array must be distinct from the `src` array (they cannot
1183-
alias each other).
1182+
$(_DOCS_ALIASING_WARNING)
11841183
11851184
See also [`circshift`](@ref).
11861185
"""
@@ -1238,6 +1237,8 @@ their indices; any offset results in a (circular) wraparound. If the
12381237
arrays have overlapping indices, then on the domain of the overlap
12391238
`dest` agrees with `src`.
12401239
1240+
$(_DOCS_ALIASING_WARNING)
1241+
12411242
See also: [`circshift`](@ref).
12421243
12431244
# Examples

base/reducedim.jl

+20-2
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,8 @@ _count(f, A::AbstractArrayOrBroadcasted, dims, init) = mapreduce(_bool(f), add_s
448448
Count the number of elements in `A` for which `f` returns `true` over the
449449
singleton dimensions of `r`, writing the result into `r` in-place.
450450
451+
$(_DOCS_ALIASING_WARNING)
452+
451453
!!! compat "Julia 1.5"
452454
inplace `count!` was added in Julia 1.5.
453455
@@ -525,8 +527,8 @@ sum(f, A::AbstractArray; dims)
525527
sum!(r, A)
526528
527529
Sum elements of `A` over the singleton dimensions of `r`, and write results to `r`.
528-
Note that since the sum! function is intended to operate without making any allocations,
529-
the target should not alias with the source.
530+
531+
$(_DOCS_ALIASING_WARNING)
530532
531533
# Examples
532534
```jldoctest
@@ -601,6 +603,8 @@ prod(f, A::AbstractArray; dims)
601603
602604
Multiply elements of `A` over the singleton dimensions of `r`, and write results to `r`.
603605
606+
$(_DOCS_ALIASING_WARNING)
607+
604608
# Examples
605609
```jldoctest
606610
julia> A = [1 2; 3 4]
@@ -678,6 +682,8 @@ maximum(f, A::AbstractArray; dims)
678682
679683
Compute the maximum value of `A` over the singleton dimensions of `r`, and write results to `r`.
680684
685+
$(_DOCS_ALIASING_WARNING)
686+
681687
# Examples
682688
```jldoctest
683689
julia> A = [1 2; 3 4]
@@ -755,6 +761,8 @@ minimum(f, A::AbstractArray; dims)
755761
756762
Compute the minimum value of `A` over the singleton dimensions of `r`, and write results to `r`.
757763
764+
$(_DOCS_ALIASING_WARNING)
765+
758766
# Examples
759767
```jldoctest
760768
julia> A = [1 2; 3 4]
@@ -820,6 +828,8 @@ extrema(f, A::AbstractArray; dims)
820828
821829
Compute the minimum and maximum value of `A` over the singleton dimensions of `r`, and write results to `r`.
822830
831+
$(_DOCS_ALIASING_WARNING)
832+
823833
!!! compat "Julia 1.8"
824834
This method requires Julia 1.8 or later.
825835
@@ -895,6 +905,8 @@ all(::Function, ::AbstractArray; dims)
895905
896906
Test whether all values in `A` along the singleton dimensions of `r` are `true`, and write results to `r`.
897907
908+
$(_DOCS_ALIASING_WARNING)
909+
898910
# Examples
899911
```jldoctest
900912
julia> A = [true false; true false]
@@ -968,6 +980,8 @@ any(::Function, ::AbstractArray; dims)
968980
Test whether any values in `A` along the singleton dimensions of `r` are `true`, and write
969981
results to `r`.
970982
983+
$(_DOCS_ALIASING_WARNING)
984+
971985
# Examples
972986
```jldoctest
973987
julia> A = [true false; true false]
@@ -1085,6 +1099,8 @@ end
10851099
Find the minimum of `A` and the corresponding linear index along singleton
10861100
dimensions of `rval` and `rind`, and store the results in `rval` and `rind`.
10871101
`NaN` is treated as less than all other values except `missing`.
1102+
1103+
$(_DOCS_ALIASING_WARNING)
10881104
"""
10891105
function findmin!(rval::AbstractArray, rind::AbstractArray, A::AbstractArray;
10901106
init::Bool=true)
@@ -1156,6 +1172,8 @@ end
11561172
Find the maximum of `A` and the corresponding linear index along singleton
11571173
dimensions of `rval` and `rind`, and store the results in `rval` and `rind`.
11581174
`NaN` is treated as greater than all other values except `missing`.
1175+
1176+
$(_DOCS_ALIASING_WARNING)
11591177
"""
11601178
function findmax!(rval::AbstractArray, rind::AbstractArray, A::AbstractArray;
11611179
init::Bool=true)

base/sort.jl

+4
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,8 @@ v[ix[k]] == partialsort(v, k)
15831583
The return value is the `k`th element of `ix` if `k` is an integer, or view into `ix` if `k` is
15841584
a range.
15851585
1586+
$(Base._DOCS_ALIASING_WARNING)
1587+
15861588
# Examples
15871589
```jldoctest
15881590
julia> v = [3, 1, 2, 1];
@@ -1707,6 +1709,8 @@ end
17071709
Like [`sortperm`](@ref), but accepts a preallocated index vector or array `ix` with the same `axes` as `A`.
17081710
`ix` is initialized to contain the values `LinearIndices(A)`.
17091711
1712+
$(Base._DOCS_ALIASING_WARNING)
1713+
17101714
!!! compat "Julia 1.9"
17111715
The method accepting `dims` requires at least Julia 1.9.
17121716

doc/src/manual/functions.md

+3
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ As a common convention in Julia (not a syntactic requirement), such a function w
102102
[typically be named `f!(x, y)`](@ref man-punctuation) rather than `f(x, y)`, as a visual reminder at
103103
the call site that at least one of the arguments (often the first one) is being mutated.
104104

105+
!!! warning "Shared memory between arguments"
106+
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).
107+
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.
105108

106109
## Argument-type declarations
107110

0 commit comments

Comments
 (0)