Skip to content

Commit

Permalink
prevent some unnecessary uses of @pure in traits.jl (#1177)
Browse files Browse the repository at this point in the history
There's no reason for a `Base.@pure` annotation in cases where Julia
successfully infers `:consistent`, `:effect_free` and
`:terminates_globally` without the annotation.

Effect inference tested with Julia v1.9.2, the latest release.

While the effect inference is not favorable for `_Length(::Int...)`, as
the consistency is not inferred, `_Length` actually seems to be an
internal function meant as merely an implementation detail for
`Length`, whose effect inference is perfect for the relevant method.

The script for testing the effect inference is appended. `:consistent`
(`+c`), `:effect_free` (`+e`) and `:terminates_globally` (`+t`) are
successfully inferred in each case:
```julia
using StaticArrays

const d = StaticArraysCore.Dynamic()

const test_sizes = (
  (1,2,3,4,5,6,7,8,9,1,2,3),
  (7,8,9,1,2,3,1,2,3,4,5,6),
  (2,3,4,2,3,4,2,3,4,2,3,4),
  (1,2,3,4,5,6,7,8,9,1,2,d),
  (7,8,9,1,2,3,1,2,3,4,5,d),
  (2,3,4,2,3,4,2,3,4,2,3,d),
  (d,2,3,4,5,6,7,8,9,1,2,3),
  (d,8,9,1,2,3,1,2,3,4,5,6),
  (d,3,4,2,3,4,2,3,4,2,3,4),
  (1,2,3,4,d,6,7,8,d,1,2,3),
  (7,8,9,1,d,3,1,2,d,4,5,6),
  (2,3,4,2,d,4,2,3,d,2,3,4),
)

const test_lengths = (0, 1, 2, 3, d)

const test_size_types = map((s -> Size{s}), test_sizes)
const test_length_types = map((l -> Length{l}), test_lengths)

const test_tuple_int_types = (
  Tuple{},
  Tuple{Int},
  Tuple{Int,Int},
  Tuple{Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int},
  Tuple{Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int},
  Tuple{Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int},
)

println("Length(::Size)")
for S ∈ test_size_types
  display(Base.infer_effects(Length, (S,)))
end
println()

println("(::Type{Tuple})(::Size)")
for S ∈ test_size_types
  display(Base.infer_effects(Tuple, (S,)))
end
println()

println("length(::Size)")
for S ∈ test_size_types
  display(Base.infer_effects(length, (S,)))
end
println()

println("length_val(::Size)")
for S ∈ test_size_types
  display(Base.infer_effects(StaticArrays.length_val, (S,)))
end
println()

println("==(::Size, ::Tuple{Vararg{Int}})")
for S ∈ test_size_types, T ∈ test_tuple_int_types
  display(Base.infer_effects(==, (S, T)))
end
println()

println("==(::Tuple{Vararg{Int}}, ::Size)")
for S ∈ test_size_types, T ∈ test_tuple_int_types
  display(Base.infer_effects(==, (T, S)))
end
println()

println("prod(::Size)")
for S ∈ test_size_types
  display(Base.infer_effects(prod, (S,)))
end
println()

println("size_tuple(::Size)")
for S ∈ test_size_types
  display(Base.infer_effects(StaticArrays.size_tuple, (S,)))
end
println()

println("==(::Length, ::Int)")
for L ∈ test_length_types
  display(Base.infer_effects(==, (L, Int)))
end
println()

println("==(::Int, ::Length)")
for L ∈ test_length_types
  display(Base.infer_effects(==, (Int, L)))
end
println()

println("sizematch(::Size, ::Size)")
for S1 ∈ test_size_types, S2 ∈ test_size_types
  display(Base.infer_effects(StaticArrays.sizematch, (S1, S2)))
end
println()

println("diagsize(::Size)")
for S ∈ test_size_types
  display(Base.infer_effects(StaticArrays.diagsize, (S,)))
end
println()
```

Co-authored-by: Mateusz Baran <[email protected]>
  • Loading branch information
nsajko and mateuszbaran authored Jan 25, 2024
1 parent 0d16e67 commit 5cceb14
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 14 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "StaticArrays"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.9.1"
version = "1.9.2"

[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Expand Down
26 changes: 13 additions & 13 deletions src/traits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,32 +38,32 @@ Length(a::AbstractArray) = Length(Size(a))
Length(::Type{A}) where {A <: AbstractArray} = Length(Size(A))
@pure Length(L::Int) = Length{L}()
Length(::Size{S}) where {S} = _Length(S...)
@pure _Length(S::Int...) = Length{prod(S)}()
_Length(S::Int...) = Length{prod(S)}()
@inline _Length(S...) = Length{Dynamic()}()

# Some @pure convenience functions for `Size`
@pure (::Type{Tuple})(::Size{S}) where {S} = S
# Some convenience functions for `Size`
(::Type{Tuple})(::Size{S}) where {S} = S

@pure getindex(::Size{S}, i::Int) where {S} = i <= length(S) ? S[i] : 1

@pure length(::Size{S}) where {S} = length(S)
@pure length_val(::Size{S}) where {S} = Val{length(S)}
length(::Size{S}) where {S} = length(S)
length_val(::Size{S}) where {S} = Val{length(S)}

# Note - using === here, as Base doesn't inline == for tuples as of julia-0.6
@pure Base.:(==)(::Size{S}, s::Tuple{Vararg{Int}}) where {S} = S === s
@pure Base.:(==)(s::Tuple{Vararg{Int}}, ::Size{S}) where {S} = s === S
Base.:(==)(::Size{S}, s::Tuple{Vararg{Int}}) where {S} = S === s
Base.:(==)(s::Tuple{Vararg{Int}}, ::Size{S}) where {S} = s === S

@pure Base.prod(::Size{S}) where {S} = prod(S)
Base.prod(::Size{S}) where {S} = prod(S)

Base.LinearIndices(::Size{S}) where {S} = LinearIndices(S)

@pure size_tuple(::Size{S}) where {S} = Tuple{S...}
size_tuple(::Size{S}) where {S} = Tuple{S...}

# Some @pure convenience functions for `Length`
@pure (::Type{Int})(::Length{L}) where {L} = Int(L)

@pure Base.:(==)(::Length{L}, l::Int) where {L} = L == l
@pure Base.:(==)(l::Int, ::Length{L}) where {L} = l == L
Base.:(==)(::Length{L}, l::Int) where {L} = L == l
Base.:(==)(l::Int, ::Length{L}) where {L} = l == L

"""
sizematch(::Size, ::Size)
Expand All @@ -72,7 +72,7 @@ Base.LinearIndices(::Size{S}) where {S} = LinearIndices(S)
Determine whether two sizes match, in the sense that they have the same
number of dimensions, and their dimensions match as determined by [`dimmatch`](@ref).
"""
@pure sizematch(::Size{S1}, ::Size{S2}) where {S1, S2} = sizematch(S1, S2)
sizematch(::Size{S1}, ::Size{S2}) where {S1, S2} = sizematch(S1, S2)
@inline sizematch(::Tuple{}, ::Tuple{}) = true
@inline sizematch(S1::Tuple{Vararg{StaticDimension, N}}, S2::Tuple{Vararg{StaticDimension, N}}) where {N} =
dimmatch(S1[1], S2[1]) && sizematch(Base.tail(S1), Base.tail(S2))
Expand Down Expand Up @@ -115,4 +115,4 @@ end

# Return the "diagonal size" of a matrix - the minimum of the two dimensions
diagsize(A::StaticMatrix) = diagsize(Size(A))
@pure diagsize(::Size{S}) where {S} = min(S...)
diagsize(::Size{S}) where {S} = min(S...)

0 comments on commit 5cceb14

Please sign in to comment.