From 5cceb14f20463d79ab099c5f778aa4e90a7a6ea6 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Thu, 25 Jan 2024 12:07:05 +0100 Subject: [PATCH] prevent some unnecessary uses of `@pure` in traits.jl (#1177) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- Project.toml | 2 +- src/traits.jl | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Project.toml b/Project.toml index 7fb1abd6..9b2bd2aa 100644 --- a/Project.toml +++ b/Project.toml @@ -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" diff --git a/src/traits.jl b/src/traits.jl index ad0ecb8e..920a2f81 100644 --- a/src/traits.jl +++ b/src/traits.jl @@ -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) @@ -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)) @@ -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...)