From e4fbcc40a322fd1557f0370a3b19fe6c48398525 Mon Sep 17 00:00:00 2001
From: Chris Elrod <elrodc@gmail.com>
Date: Tue, 8 Sep 2020 23:30:24 -0400
Subject: [PATCH 01/12] Added tests for Static.

---
 README.md             |  8 +++++
 src/ArrayInterface.jl |  1 +
 src/ranges.jl         | 59 +++++++++++++++++----------------
 src/static.jl         | 76 +++++++++++++++++++++++++++++++++++++++++++
 test/runtests.jl      | 42 +++++++++++++++++++-----
 5 files changed, 150 insertions(+), 36 deletions(-)
 create mode 100644 src/static.jl

diff --git a/README.md b/README.md
index 5fcc56f64..ca1e862f9 100644
--- a/README.md
+++ b/README.md
@@ -134,6 +134,14 @@ Otherwise, returns `nothing`. For example, `known_step(UnitRange{Int})` returns
 If `length` of an instance of type `T` is known at compile time, return it.
 Otherwise, return `nothing`.
 
+## Static(N::Int)
+
+Creates a static integer with value known at compile time. It is a number,
+supporting basic arithmetic. Many operations with two `Static` integers
+will produce another `Static` integer. If one of the arguments to a
+function call isn't static (e.g., `Static(4) + 3`) then the `Static`
+number will promote to a dynamic value.
+
 # List of things to add
 
 - https://github.com/JuliaLang/julia/issues/22216
diff --git a/src/ArrayInterface.jl b/src/ArrayInterface.jl
index d666ac594..cb6aab1fa 100644
--- a/src/ArrayInterface.jl
+++ b/src/ArrayInterface.jl
@@ -699,6 +699,7 @@ function __init__()
   end
 end
 
+include("static.jl")
 include("ranges.jl")
 
 end
diff --git a/src/ranges.jl b/src/ranges.jl
index e47be321f..a4f626e5a 100644
--- a/src/ranges.jl
+++ b/src/ranges.jl
@@ -44,6 +44,8 @@ known_step(::Type{<:AbstractUnitRange{T}}) where {T} = one(T)
 
 _get(x) = x
 _get(::Val{V}) where {V} = V
+_get(::Static{V}) where {V} = V
+_get(::Type{Static{V}}) where {V} = V
 _convert(::Type{T}, x) where {T} = convert(T, x)
 _convert(::Type{T}, ::Val{V}) where {T,V} = Val(convert(T, V))
 
@@ -56,7 +58,7 @@ at compile time. An `OptionallyStaticUnitRange` is intended to be constructed in
 from other valid indices. Therefore, users should not expect the same checks are used
 to ensure construction of a valid `OptionallyStaticUnitRange` as a `UnitRange`.
 """
-struct OptionallyStaticUnitRange{T,F,L} <: AbstractUnitRange{T}
+struct OptionallyStaticUnitRange{T <: Integer, F <: Integer, L <: Integer} <: AbstractUnitRange{T}
   start::F
   stop::L
 
@@ -79,10 +81,8 @@ struct OptionallyStaticUnitRange{T,F,L} <: AbstractUnitRange{T}
 
   function OptionallyStaticUnitRange(x::AbstractRange)
     if step(x) == 1
-      fst = known_first(x)
-      fst = fst === nothing ? first(x) : Val(fst)
-      lst = known_last(x)
-      lst = lst === nothing ? last(x) : Val(lst)
+      fst = static_first(x)
+      lst = static_last(x)
       return OptionallyStaticUnitRange(fst, lst)
     else
         throw(ArgumentError("step must be 1, got $(step(r))"))
@@ -90,17 +90,17 @@ struct OptionallyStaticUnitRange{T,F,L} <: AbstractUnitRange{T}
   end
 end
 
-Base.first(r::OptionallyStaticUnitRange{<:Any,Val{F}}) where {F} = F
-Base.first(r::OptionallyStaticUnitRange{<:Any,<:Any}) = r.start
+Base.:(:)(L, ::Static{U}) where {U} = OptionallyStaticUnitRange(L, Static(U))
+Base.:(:)(::Static{L}, U) where {L} = OptionallyStaticUnitRange(Static(L), U)
+Base.:(:)(::Static{L}, ::Static{U}) where {L,U} = OptionallyStaticUnitRange(Static(L), Static(U))
 
+Base.first(r::OptionallyStaticUnitRange) = r.start
 Base.step(r::OptionallyStaticUnitRange{T}) where {T} = oneunit(T)
+Base.last(r::OptionallyStaticUnitRange) = r.stop
 
-Base.last(r::OptionallyStaticUnitRange{<:Any,<:Any,Val{L}}) where {L} = L
-Base.last(r::OptionallyStaticUnitRange{<:Any,<:Any,<:Any}) = r.stop
-
-known_first(::Type{<:OptionallyStaticUnitRange{<:Any,Val{F}}}) where {F} = F
+known_first(::Type{<:OptionallyStaticUnitRange{<:Any,Static{F}}}) where {F} = F
 known_step(::Type{<:OptionallyStaticUnitRange{T}}) where {T} = one(T)
-known_last(::Type{<:OptionallyStaticUnitRange{<:Any,<:Any,Val{L}}}) where {L} = L
+known_last(::Type{<:OptionallyStaticUnitRange{<:Any,<:Any,Static{L}}}) where {L} = L
 
 function Base.isempty(r::OptionallyStaticUnitRange)
   if known_first(r) === oneunit(eltype(r))
@@ -141,10 +141,19 @@ end
   return convert(eltype(r), val)
 end
 
-_try_static(x, y) = Val(x)
-_try_static(::Nothing, y) = Val(y)
-_try_static(x, ::Nothing) = Val(x)
-_try_static(::Nothing, ::Nothing) = nothing
+@inline _try_static(::Static{N}, ::Static{N}) where {N} = Static{N}()
+function _try_static(::Static{N}, x) where {N}
+    @assert N == x "Unequal Indices: Static{$N}() != x == $x"
+    Static{N}()
+end
+function _try_static(x, ::Static{N}) where {N}
+    @assert N == x "Unequal Indices: x == $x != Static{$N}()"
+    Static{N}()
+end
+function _try_static(x, y)
+    @assert x == y "Unequal Indicess: x == $x != $y == y"
+    x
+end
 
 ###
 ### length
@@ -193,7 +202,7 @@ specified then indices for visiting each index of `x` is returned.
 """
 @inline function indices(x)
   inds = eachindex(x)
-  if inds isa AbstractUnitRange{<:Integer}
+  if inds isa AbstractUnitRange#{<:Integer} # prevents inference
     return Base.Slice(OptionallyStaticUnitRange(inds))
   else
     return inds
@@ -202,30 +211,24 @@ end
 
 function indices(x::Tuple)
   inds = map(eachindex, x)
-  @assert all(isequal(first(inds)), Base.tail(inds)) "Not all specified axes are equal: $inds"
   return reduce(_pick_range, inds)
 end
 
-indices(x, d) = indices(axes(x, d))
+@inline indices(x, d) = indices(axes(x, d))
 
-@inline function indices(x::NTuple{N,<:Any}, dim) where {N}
+@inline function indices(x::Tuple{Vararg{Any,N}}, dim) where {N}
   inds = map(x_i -> indices(x_i, dim), x)
-  @assert all(isequal(first(inds)), Base.tail(inds)) "Not all specified axes are equal: $inds"
   return reduce(_pick_range, inds)
 end
 
-@inline function indices(x::NTuple{N,<:Any}, dim::NTuple{N,<:Any}) where {N}
+@inline function indices(x::Tuple{Vararg{Any,N}}, dim::Tuple{Vararg{Any,N}}) where {N}
   inds = map(indices, x, dim)
-  @assert all(isequal(first(inds)), Base.tail(inds)) "Not all specified axes are equal: $inds"
   return reduce(_pick_range, inds)
 end
 
 @inline function _pick_range(x, y)
-  fst = _try_static(known_first(x), known_first(y))
-  fst = fst === nothing ? first(x) : fst
-
-  lst = _try_static(known_last(x), known_last(y))
-  lst = lst === nothing ? last(x) : lst
+  fst = _try_static(static_first(x), static_first(y))
+  lst = _try_static(static_last(x), static_last(y))
   return Base.Slice(OptionallyStaticUnitRange(fst, lst))
 end
 
diff --git a/src/static.jl b/src/static.jl
new file mode 100644
index 000000000..28d7a1e3a
--- /dev/null
+++ b/src/static.jl
@@ -0,0 +1,76 @@
+
+"""
+A statically sized `Int`.
+Use `Static(N)` instead of `Val(N)` when you want it to behave like a number.
+"""
+struct Static{N} <: Integer
+    Static{N}()  where {N} = new{N::Int}()
+end
+Base.@pure Static(N::Int) = Static{N}()
+Static(N) = Static(convert(Int,N))
+Static(::Val{N}) where {N} = Static{N}()
+@inline Base.Val(::Static{N}) where {N} = Val{N}()
+Base.convert(::Type{T}, ::Static{N}) where {T<:Number,N} = convert(T, N)
+Base.convert(::Type{Static{N}}, ::Static{N}) where {N} = Static{N}()
+Base.promote_rule(::Type{<:Static}, ::Type{T}) where {T} = promote_rule(Int, T)
+Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T} = promote_rule(T, Int)
+Base.promote_rule(::Type{<:Static}, ::Type{<:Static}) where {T} = Int
+Base.:(%)(::Static{N}, ::Type{Integer}) where {N} = N
+
+@inline Base.iszero(::Static{0}) = true
+@inline Base.iszero(::Static) = false
+
+Base.:(+)(i::Number, ::Static{0}) = i
+Base.:(+)(::Static{0}, i::Number) = i
+Base.:(+)(::Static{0}, i::Integer) = i
+Base.:(+)(::Static{0}, ::Static{0}) = Static{0}()
+Base.:(+)(::Static{N}, ::Static{0}) where {N} = Static{N}()
+Base.:(+)(::Static{0}, ::Static{N}) where {N} = Static{N}()
+Base.:(+)(::Static{M}, ::Static{N}) where {M,N} = Static{M + N}()
+
+Base.:(-)(::Static{0}, i::Number) = -i
+Base.:(-)(i::Number, ::Static{0}) = i
+Base.:(-)(::Static{0}, ::Static{0}) = Static{0}()
+Base.:(-)(::Static{0}, ::Static{N}) where {N} = Static{-N}()
+Base.:(-)(::Static{N}, ::Static{0}) where {N} = Static{N}()
+Base.:(-)(::Static{M}, ::Static{N}) where {M,N} = Static{M - N}()
+
+Base.:(*)(::Static{0}, i::Number) = Static{0}()
+Base.:(*)(i::Number, ::Static{0}) = Static{0}()
+Base.:(*)(::Static{0}, ::Static{M}) where {M} = Static{0}()
+Base.:(*)(::Static{M}, ::Static{0}) where {M} = Static{0}()
+Base.:(*)(::Static{0}, ::Static{0}) = Static{0}()
+Base.:(*)(::Static{1}, i::Number) = i
+Base.:(*)(i::Number, ::Static{1}) = i
+Base.:(*)(::Static{0}, ::Static{1}) where {M} = Static{0}()
+Base.:(*)(::Static{1}, ::Static{0}) where {M} = Static{0}()
+Base.:(*)(::Static{M}, ::Static{1}) where {M} = Static{M}()
+Base.:(*)(::Static{1}, ::Static{M}) where {M} = Static{M}()
+Base.:(*)(::Static{1}, ::Static{1}) = Static{1}()
+Base.:(*)(::Static{M}, ::Static{N}) where {M,N} = Static{M * N}()
+
+Base.:(÷)(::Static{M}, ::Static{N}) where {M,N} = Static{M ÷ N}()
+Base.:(%)(::Static{M}, ::Static{N}) where {M,N} = Static{M % N}()
+Base.:(<<)(::Static{M}, ::Static{N}) where {M,N} = Static{M << N}()
+Base.:(>>)(::Static{M}, ::Static{N}) where {M,N} = Static{M >> N}()
+Base.:(>>>)(::Static{M}, ::Static{N}) where {M,N} = Static{M >>> N}()
+Base.:(&)(::Static{M}, ::Static{N}) where {M,N} = Static{M & N}()
+Base.:(|)(::Static{M}, ::Static{N}) where {M,N} = Static{M | N}()
+Base.:(⊻)(::Static{M}, ::Static{N}) where {M,N} = Static{M ⊻ N}()
+
+Base.:(==)(::Static{M}, ::Static{N}) where {M,N} = false
+Base.:(==)(::Static{M}, ::Static{M}) where {M} = true
+Base.:(≤)(::Static{M}, N::Int) where {M} = M ≤ N
+Base.:(≤)(N::Int, ::Static{M}) where {M} = N ≤ M
+Base.:(≥)(::Static{M}, N::Int) where {M} = M ≤ N
+Base.:(≥)(N::Int, ::Static{M}) where {M} = N ≥ M
+
+@inline function maybe_static(f::F, g::G, x) where {F, G}
+    L = f(x)
+    isnothing(L) ? g(x) : Static(L)
+end
+@inline static_length(x) = maybe_static(known_length, length, x)
+@inline static_first(x) = maybe_static(known_first, first, x)
+@inline static_last(x) = maybe_static(known_last, last, x)
+@inline static_step(x) = maybe_static(known_step, step, x)
+
diff --git a/test/runtests.jl b/test/runtests.jl
index 4a6902341..29192e694 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -1,6 +1,6 @@
 using ArrayInterface, Test
 using Base: setindex
-import ArrayInterface: has_sparsestruct, findstructralnz, fast_scalar_indexing, lu_instance
+import ArrayInterface: has_sparsestruct, findstructralnz, fast_scalar_indexing, lu_instance, Static
 @test ArrayInterface.ismutable(rand(3))
 
 using StaticArrays
@@ -220,12 +220,38 @@ end
 end
 
 @testset "indices" begin
-    @test @inferred(ArrayInterface.indices((ones(2, 3), ones(3, 2)))) == 1:6
-    @test @inferred(ArrayInterface.indices(ones(2, 3))) == 1:6
-    @test @inferred(ArrayInterface.indices(ones(2, 3), 1)) == 1:2
-    @test @inferred(ArrayInterface.indices((ones(2, 3), ones(3, 2)), (1, 2))) == 1:2
-    @test @inferred(ArrayInterface.indices((ones(2, 3), ones(2, 3)), 1)) == 1:2
-    @test_throws AssertionError ArrayInterface.indices((ones(2, 3), ones(3, 3)), 1)
-    @test_throws AssertionError ArrayInterface.indices((ones(2, 3), ones(3, 3)), (1, 2))
+    A23 = ones(2,3); SA23 = @SMatrix ones(2,3);
+    A32 = ones(3,2); SA32 = @SMatrix ones(3,2);
+    @test @inferred(ArrayInterface.indices((A23, A32))) == 1:6
+    @test @inferred(ArrayInterface.indices((SA23, A32))) == 1:6
+    @test @inferred(ArrayInterface.indices((A23, SA32))) == 1:6
+    @test @inferred(ArrayInterface.indices((SA23, SA32))) == 1:6
+    @test @inferred(ArrayInterface.indices(A23)) == 1:6
+    @test @inferred(ArrayInterface.indices(SA23)) == 1:6
+    @test @inferred(ArrayInterface.indices(A23, 1)) == 1:2
+    @test @inferred(ArrayInterface.indices(SA23, Static(1))) === Base.Slice(Static(1):Static(2))
+    @test @inferred(ArrayInterface.indices((A23, A32), (1, 2))) == 1:2
+    @test @inferred(ArrayInterface.indices((SA23, A32), (Static(1), 2))) === Base.Slice(Static(1):Static(2))
+    @test @inferred(ArrayInterface.indices((A23, SA32), (1, Static(2)))) === Base.Slice(Static(1):Static(2))
+    @test @inferred(ArrayInterface.indices((SA23, SA32), (Static(1), Static(2)))) === Base.Slice(Static(1):Static(2))
+    @test @inferred(ArrayInterface.indices((A23, A23), 1)) == 1:2
+    @test @inferred(ArrayInterface.indices((SA23, SA23), Static(1))) === Base.Slice(Static(1):Static(2))
+    @test @inferred(ArrayInterface.indices((SA23, A23), Static(1))) === Base.Slice(Static(1):Static(2))
+    @test @inferred(ArrayInterface.indices((A23, SA23), Static(1))) === Base.Slice(Static(1):Static(2))
+    @test @inferred(ArrayInterface.indices((SA23, SA23), Static(1))) === Base.Slice(Static(1):Static(2))
+    @test_throws AssertionError ArrayInterface.indices((A23, ones(3, 3)), 1)
+    @test_throws AssertionError ArrayInterface.indices((A23, ones(3, 3)), (1, 2))
+    @test_throws AssertionError ArrayInterface.indices((SA23, ones(3, 3)), Static(1))
+    @test_throws AssertionError ArrayInterface.indices((SA23, ones(3, 3)), (Static(1), 2))
+end
+
+@testset "Static" begin
+    @test iszero(Static(0))
+    @test !iszero(Static(1))
+    # test for ambiguities and correctness
+    for i ∈ [Static(0), Static(1), Static(2), 3], j ∈ [Static(0), Static(1), Static(2), 3], f ∈ [+, -, *, ÷, %, <<, >>, >>>, &, |, ⊻, ==, ≤, ≥]
+        (iszero(j) && ((f === ÷) || (f === %))) && continue # integer division error
+        @test convert(Int, @inferred(f(i,j))) == f(convert(Int, i), convert(Int, j))
+    end
 end
 

From 1260be6751e020b7afaaf9b42b80751c5d228de1 Mon Sep 17 00:00:00 2001
From: Chris Elrod <elrodc@gmail.com>
Date: Wed, 9 Sep 2020 03:36:47 -0400
Subject: [PATCH 02/12] Allow all bitsinteger types.

---
 src/static.jl | 112 ++++++++++++++++++++++++++++----------------------
 1 file changed, 62 insertions(+), 50 deletions(-)

diff --git a/src/static.jl b/src/static.jl
index 28d7a1e3a..3bf4ce488 100644
--- a/src/static.jl
+++ b/src/static.jl
@@ -4,12 +4,15 @@ A statically sized `Int`.
 Use `Static(N)` instead of `Val(N)` when you want it to behave like a number.
 """
 struct Static{N} <: Integer
-    Static{N}()  where {N} = new{N::Int}()
+    function Static{N}()  where {N}
+        @assert isa(typeof(N), Base.BitIntegerType) "$N is not a primitive integer type"
+        return new{N}()
+    end
 end
-Base.@pure Static(N::Int) = Static{N}()
-Static(N) = Static(convert(Int,N))
+Base.@pure Static(N::Union{Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UInt128}) = Static{N}()
+Static(N) = Static(convert(Int, N))
 Static(::Val{N}) where {N} = Static{N}()
-@inline Base.Val(::Static{N}) where {N} = Val{N}()
+Base.Val(::Static{N}) where {N} = Val{N}()
 Base.convert(::Type{T}, ::Static{N}) where {T<:Number,N} = convert(T, N)
 Base.convert(::Type{Static{N}}, ::Static{N}) where {N} = Static{N}()
 Base.promote_rule(::Type{<:Static}, ::Type{T}) where {T} = promote_rule(Int, T)
@@ -17,53 +20,62 @@ Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T} = promote_rule(T, Int)
 Base.promote_rule(::Type{<:Static}, ::Type{<:Static}) where {T} = Int
 Base.:(%)(::Static{N}, ::Type{Integer}) where {N} = N
 
-@inline Base.iszero(::Static{0}) = true
-@inline Base.iszero(::Static) = false
+@inline Base.iszero(::Static{M}) where {M} = iszero(M)
+@inline Base.isone(::Static{M}) where {M} = isone(M)
 
-Base.:(+)(i::Number, ::Static{0}) = i
-Base.:(+)(::Static{0}, i::Number) = i
-Base.:(+)(::Static{0}, i::Integer) = i
-Base.:(+)(::Static{0}, ::Static{0}) = Static{0}()
-Base.:(+)(::Static{N}, ::Static{0}) where {N} = Static{N}()
-Base.:(+)(::Static{0}, ::Static{N}) where {N} = Static{N}()
-Base.:(+)(::Static{M}, ::Static{N}) where {M,N} = Static{M + N}()
-
-Base.:(-)(::Static{0}, i::Number) = -i
-Base.:(-)(i::Number, ::Static{0}) = i
-Base.:(-)(::Static{0}, ::Static{0}) = Static{0}()
-Base.:(-)(::Static{0}, ::Static{N}) where {N} = Static{-N}()
-Base.:(-)(::Static{N}, ::Static{0}) where {N} = Static{N}()
-Base.:(-)(::Static{M}, ::Static{N}) where {M,N} = Static{M - N}()
-
-Base.:(*)(::Static{0}, i::Number) = Static{0}()
-Base.:(*)(i::Number, ::Static{0}) = Static{0}()
-Base.:(*)(::Static{0}, ::Static{M}) where {M} = Static{0}()
-Base.:(*)(::Static{M}, ::Static{0}) where {M} = Static{0}()
-Base.:(*)(::Static{0}, ::Static{0}) = Static{0}()
-Base.:(*)(::Static{1}, i::Number) = i
-Base.:(*)(i::Number, ::Static{1}) = i
-Base.:(*)(::Static{0}, ::Static{1}) where {M} = Static{0}()
-Base.:(*)(::Static{1}, ::Static{0}) where {M} = Static{0}()
-Base.:(*)(::Static{M}, ::Static{1}) where {M} = Static{M}()
-Base.:(*)(::Static{1}, ::Static{M}) where {M} = Static{M}()
-Base.:(*)(::Static{1}, ::Static{1}) = Static{1}()
-Base.:(*)(::Static{M}, ::Static{N}) where {M,N} = Static{M * N}()
-
-Base.:(÷)(::Static{M}, ::Static{N}) where {M,N} = Static{M ÷ N}()
-Base.:(%)(::Static{M}, ::Static{N}) where {M,N} = Static{M % N}()
-Base.:(<<)(::Static{M}, ::Static{N}) where {M,N} = Static{M << N}()
-Base.:(>>)(::Static{M}, ::Static{N}) where {M,N} = Static{M >> N}()
-Base.:(>>>)(::Static{M}, ::Static{N}) where {M,N} = Static{M >>> N}()
-Base.:(&)(::Static{M}, ::Static{N}) where {M,N} = Static{M & N}()
-Base.:(|)(::Static{M}, ::Static{N}) where {M,N} = Static{M | N}()
-Base.:(⊻)(::Static{M}, ::Static{N}) where {M,N} = Static{M ⊻ N}()
-
-Base.:(==)(::Static{M}, ::Static{N}) where {M,N} = false
-Base.:(==)(::Static{M}, ::Static{M}) where {M} = true
-Base.:(≤)(::Static{M}, N::Int) where {M} = M ≤ N
-Base.:(≤)(N::Int, ::Static{M}) where {M} = N ≤ M
-Base.:(≥)(::Static{M}, N::Int) where {M} = M ≤ N
-Base.:(≥)(N::Int, ::Static{M}) where {M} = N ≥ M
+for T ∈ [:Any, :Number]
+    @eval begin
+        @inline function Base.:(+)(i::$T, ::Static{M}) where {M}
+            if iszero(M)
+                i
+            else
+                i + M
+            end
+        end
+        @inline function Base.:(+)(::Static{M}, i::$T) where {M}
+            if iszero(M)
+                i
+            else
+                M + i
+            end
+        end
+        @inline function Base.:(-)(i::$T, ::Static{M}) where {M}
+            if iszero(M)
+                i
+            else
+                i - M
+            end
+        end
+        @inline function Base.:(*)(i::$T, j::Static{M}) where {M}
+            if iszero(M)
+                j
+            elseif isone(M)
+                i
+            else
+                i * M
+            end
+        end
+        @inline function Base.:(*)(j::Static{M}, i::$T) where {M}
+            if iszero(M)
+                j
+            elseif isone(M)
+                i
+            else
+                M * i
+            end
+        end
+    end
+end
+for f ∈ [:(+), :(-), :(*), :(/), :(÷), :(%), :(<<), :(>>), :(>>>), :(&), :(|), :(⊻)]
+    @eval @generated Base.$f(::Static{M}, ::Static{N}) where {M,N} = Expr(:call, Expr(:curly, :Static, $f(M, N)))
+end
+for f ∈ [:(==), :(!=), :(<), :(≤), :(>), :(≥)]
+    @eval begin
+        @inline Base.$f(::Static{M}, ::Static{N}) where {M,N} = $f(M, N)
+        @inline Base.$f(::Static{M}, x::Integer) where {M} = $f(M, x)
+        @inline Base.$f(x::Integer, ::Static{M}) where {M} = $f(x, M)
+    end
+end
 
 @inline function maybe_static(f::F, g::G, x) where {F, G}
     L = f(x)

From 0ce3a686b6ac9a438cdfa9f5f6e6cc2ad983c417 Mon Sep 17 00:00:00 2001
From: Chris Elrod <elrodc@gmail.com>
Date: Wed, 9 Sep 2020 03:50:06 -0400
Subject: [PATCH 03/12] Only allow `Int` once again.

---
 src/static.jl | 66 +++++++++++++++++----------------------------------
 1 file changed, 22 insertions(+), 44 deletions(-)

diff --git a/src/static.jl b/src/static.jl
index 3bf4ce488..ef42c6714 100644
--- a/src/static.jl
+++ b/src/static.jl
@@ -5,11 +5,10 @@ Use `Static(N)` instead of `Val(N)` when you want it to behave like a number.
 """
 struct Static{N} <: Integer
     function Static{N}()  where {N}
-        @assert isa(typeof(N), Base.BitIntegerType) "$N is not a primitive integer type"
-        return new{N}()
+        return new{N::Int}()
     end
 end
-Base.@pure Static(N::Union{Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UInt128}) = Static{N}()
+Base.@pure Static(N::Int) = Static{N}()
 Static(N) = Static(convert(Int, N))
 Static(::Val{N}) where {N} = Static{N}()
 Base.Val(::Static{N}) where {N} = Val{N}()
@@ -20,52 +19,31 @@ Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T} = promote_rule(T, Int)
 Base.promote_rule(::Type{<:Static}, ::Type{<:Static}) where {T} = Int
 Base.:(%)(::Static{N}, ::Type{Integer}) where {N} = N
 
-@inline Base.iszero(::Static{M}) where {M} = iszero(M)
-@inline Base.isone(::Static{M}) where {M} = isone(M)
+Base.iszero(::Static{0}) = true
+Base.iszero(::Static) = false
+Base.isone(::Static{1}) = true
+Base.isone(::Static) = false
 
 for T ∈ [:Any, :Number]
     @eval begin
-        @inline function Base.:(+)(i::$T, ::Static{M}) where {M}
-            if iszero(M)
-                i
-            else
-                i + M
-            end
-        end
-        @inline function Base.:(+)(::Static{M}, i::$T) where {M}
-            if iszero(M)
-                i
-            else
-                M + i
-            end
-        end
-        @inline function Base.:(-)(i::$T, ::Static{M}) where {M}
-            if iszero(M)
-                i
-            else
-                i - M
-            end
-        end
-        @inline function Base.:(*)(i::$T, j::Static{M}) where {M}
-            if iszero(M)
-                j
-            elseif isone(M)
-                i
-            else
-                i * M
-            end
-        end
-        @inline function Base.:(*)(j::Static{M}, i::$T) where {M}
-            if iszero(M)
-                j
-            elseif isone(M)
-                i
-            else
-                M * i
-            end
-        end
+        @inline Base.:(+)(i::$T, ::Static{0}) = i
+        @inline Base.:(+)(i::$T, ::Static{M}) where {M} = i + M
+        @inline Base.:(+)(::Static{0}, i::$T) = i
+        @inline Base.:(+)(::Static{M}, i::$T) where {M} = M + i
+        @inline Base.:(-)(i::$T, ::Static{0}) = i
+        @inline Base.:(-)(i::$T, ::Static{M}) where {M} = i - M
+        @inline Base.:(*)(i::$T, ::Static{0}) = Static{0}()
+        @inline Base.:(*)(i::$T, ::Static{1}) = i
+        @inline Base.:(*)(i::$T, ::Static{M}) where {M} = i * M
+        @inline Base.:(*)(::Static{0}, i::$T) = Static{0}()
+        @inline Base.:(*)(::Static{1}, i::$T) = i
+        @inline Base.:(*)(::Static{M}, i::$T) where {M} = M * i
     end
 end
+@inline Base.:(*)(::Static{0}, ::Static{0}) = Static{0}()
+@inline Base.:(*)(::Static{1}, ::Static{0}) = Static{0}()
+@inline Base.:(*)(::Static{0}, ::Static{1}) = Static{0}()
+@inline Base.:(*)(::Static{1}, ::Static{1}) = Static{1}()
 for f ∈ [:(+), :(-), :(*), :(/), :(÷), :(%), :(<<), :(>>), :(>>>), :(&), :(|), :(⊻)]
     @eval @generated Base.$f(::Static{M}, ::Static{N}) where {M,N} = Expr(:call, Expr(:curly, :Static, $f(M, N)))
 end

From c6c9c9b95538b6309a65d987322e0ddca42070e7 Mon Sep 17 00:00:00 2001
From: Chris Elrod <elrodc@gmail.com>
Date: Wed, 9 Sep 2020 04:09:34 -0400
Subject: [PATCH 04/12] More tests.

---
 src/static.jl    |  2 +-
 test/runtests.jl | 22 +++++++++++++++++++---
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/src/static.jl b/src/static.jl
index ef42c6714..34a77356f 100644
--- a/src/static.jl
+++ b/src/static.jl
@@ -24,7 +24,7 @@ Base.iszero(::Static) = false
 Base.isone(::Static{1}) = true
 Base.isone(::Static) = false
 
-for T ∈ [:Any, :Number]
+for T ∈ [:Any, :Number, :Integer]
     @eval begin
         @inline Base.:(+)(i::$T, ::Static{0}) = i
         @inline Base.:(+)(i::$T, ::Static{M}) where {M} = i + M
diff --git a/test/runtests.jl b/test/runtests.jl
index 29192e694..f7e80a09f 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -249,9 +249,25 @@ end
     @test iszero(Static(0))
     @test !iszero(Static(1))
     # test for ambiguities and correctness
-    for i ∈ [Static(0), Static(1), Static(2), 3], j ∈ [Static(0), Static(1), Static(2), 3], f ∈ [+, -, *, ÷, %, <<, >>, >>>, &, |, ⊻, ==, ≤, ≥]
-        (iszero(j) && ((f === ÷) || (f === %))) && continue # integer division error
-        @test convert(Int, @inferred(f(i,j))) == f(convert(Int, i), convert(Int, j))
+    for i ∈ [Static(0), Static(1), Static(2), 3]
+        for j ∈ [Static(0), Static(1), Static(2), 3]
+            i === j === 3 && continue
+            for f ∈ [+, -, *, ÷, %, <<, >>, >>>, &, |, ⊻, ==, ≤, ≥]
+                (iszero(j) && ((f === ÷) || (f === %))) && continue # integer division error
+                @test convert(Int, @inferred(f(i,j))) == f(convert(Int, i), convert(Int, j))
+            end
+        end
+        i == 3 && break
+        for f ∈ [+, -, *, /, ÷, %, ==, ≤, ≥]
+            x = f(convert(Int, i), 1.4)
+            y = f(1.4, convert(Int, i))
+            @test convert(typeof(x), @inferred(f(i, 1.4))) === x
+            @test convert(typeof(y), @inferred(f(1.4, i))) === y # if f is division and i === Static(0), returns `NaN`; hence use of ==== in check.
+        end
     end
+    @test @inferred("Hello world!" * Static(0)) === Static(0)
+    @test @inferred("Hello world!" * Static(1)) === "Hello world!"
+    @test @inferred(Static(0) * "Hello world!") === Static(0)
+    @test @inferred(Static(1) * "Hello world!") === "Hello world!"
 end
 

From e679776be9cdddaee72fd3f471dc433d65c7c692 Mon Sep 17 00:00:00 2001
From: Chris Elrod <elrodc@gmail.com>
Date: Wed, 9 Sep 2020 04:20:55 -0400
Subject: [PATCH 05/12] Detect ambiguities and unbound_args.

---
 src/ranges.jl    | 5 +++--
 test/runtests.jl | 4 ++++
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/ranges.jl b/src/ranges.jl
index a4f626e5a..be0460c86 100644
--- a/src/ranges.jl
+++ b/src/ranges.jl
@@ -90,8 +90,8 @@ struct OptionallyStaticUnitRange{T <: Integer, F <: Integer, L <: Integer} <: Ab
   end
 end
 
-Base.:(:)(L, ::Static{U}) where {U} = OptionallyStaticUnitRange(L, Static(U))
-Base.:(:)(::Static{L}, U) where {L} = OptionallyStaticUnitRange(Static(L), U)
+Base.:(:)(L::Integer, ::Static{U}) where {U} = OptionallyStaticUnitRange(L, Static(U))
+Base.:(:)(::Static{L}, U::Integer) where {L} = OptionallyStaticUnitRange(Static(L), U)
 Base.:(:)(::Static{L}, ::Static{U}) where {L,U} = OptionallyStaticUnitRange(Static(L), Static(U))
 
 Base.first(r::OptionallyStaticUnitRange) = r.start
@@ -142,6 +142,7 @@ end
 end
 
 @inline _try_static(::Static{N}, ::Static{N}) where {N} = Static{N}()
+@inline _try_static(::Static{M}, ::Static{N}) where {M, N} = @assert false "Unequal Indices: Static{$M}() != Static{$N}()"
 function _try_static(::Static{N}, x) where {N}
     @assert N == x "Unequal Indices: Static{$N}() != x == $x"
     Static{N}()
diff --git a/test/runtests.jl b/test/runtests.jl
index f7e80a09f..70b7821f7 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -3,6 +3,9 @@ using Base: setindex
 import ArrayInterface: has_sparsestruct, findstructralnz, fast_scalar_indexing, lu_instance, Static
 @test ArrayInterface.ismutable(rand(3))
 
+@test isempty(detect_unbound_args(ArrayInterface))
+@test isempty(detect_ambiguities(ArrayInterface))
+
 using StaticArrays
 x = @SVector [1,2,3]
 @test ArrayInterface.ismutable(x) == false
@@ -243,6 +246,7 @@ end
     @test_throws AssertionError ArrayInterface.indices((A23, ones(3, 3)), (1, 2))
     @test_throws AssertionError ArrayInterface.indices((SA23, ones(3, 3)), Static(1))
     @test_throws AssertionError ArrayInterface.indices((SA23, ones(3, 3)), (Static(1), 2))
+    @test_throws AssertionError ArrayInterface.indices((SA23, SA23), (Static(1), Static(2)))
 end
 
 @testset "Static" begin

From b68a8a6cfa11daa6480716dd5b681b70fc6624b6 Mon Sep 17 00:00:00 2001
From: Chris Elrod <elrodc@gmail.com>
Date: Wed, 9 Sep 2020 04:30:22 -0400
Subject: [PATCH 06/12] One line inner constructor.

---
 src/static.jl | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/static.jl b/src/static.jl
index 34a77356f..cfc1b0ddb 100644
--- a/src/static.jl
+++ b/src/static.jl
@@ -4,9 +4,7 @@ A statically sized `Int`.
 Use `Static(N)` instead of `Val(N)` when you want it to behave like a number.
 """
 struct Static{N} <: Integer
-    function Static{N}()  where {N}
-        return new{N::Int}()
-    end
+    Static{N}() where {N} = new{N::Int}()
 end
 Base.@pure Static(N::Int) = Static{N}()
 Static(N) = Static(convert(Int, N))

From 9bae9f64d0560805b6a8e02e4308bf9a155cb84a Mon Sep 17 00:00:00 2001
From: Chris Elrod <elrodc@gmail.com>
Date: Wed, 9 Sep 2020 06:30:48 -0400
Subject: [PATCH 07/12] Fix type ambiguities on master.

---
 src/static.jl    | 44 +++++++++++++++++++++++++++++++++++++-------
 test/runtests.jl |  4 ----
 2 files changed, 37 insertions(+), 11 deletions(-)

diff --git a/src/static.jl b/src/static.jl
index cfc1b0ddb..e81ca828f 100644
--- a/src/static.jl
+++ b/src/static.jl
@@ -7,14 +7,34 @@ struct Static{N} <: Integer
     Static{N}() where {N} = new{N::Int}()
 end
 Base.@pure Static(N::Int) = Static{N}()
-Static(N) = Static(convert(Int, N))
+Static(N::Integer) = Static(convert(Int, N))
+Static(::Static{N}) where {N} = Static{N}()
 Static(::Val{N}) where {N} = Static{N}()
 Base.Val(::Static{N}) where {N} = Val{N}()
 Base.convert(::Type{T}, ::Static{N}) where {T<:Number,N} = convert(T, N)
 Base.convert(::Type{Static{N}}, ::Static{N}) where {N} = Static{N}()
-Base.promote_rule(::Type{<:Static}, ::Type{T}) where {T} = promote_rule(Int, T)
-Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T} = promote_rule(T, Int)
-Base.promote_rule(::Type{<:Static}, ::Type{<:Static}) where {T} = Int
+for S ∈ [:Any, :AbstractIrrational]#, :(Complex{<:Real})]
+# let S = :Any    
+    @eval begin
+        Base.promote_rule(::Type{<:Static}, ::Type{T}) where {T <: $S} = promote_rule(Int, T)
+        Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T <: $S} = promote_rule(T, Int)
+    end
+end
+for (S,T) ∈ [(:Complex,:Real), (:Rational, :Integer), (:(Base.TwicePrecision),:Any)]
+    @eval Base.promote_rule(::Type{$S{T}}, ::Type{<:Static}) where {T <: $T} = promote_rule($S{T}, Int)
+end
+Base.promote_rule(::Type{Union{Nothing,Missing}}, ::Type{<:Static}) = Union{Nothing, Missing, Int}
+Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T >: Union{Missing,Nothing}} = promote_rule(T, Int)
+Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T >: Nothing} = promote_rule(T, Int)
+Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T >: Missing} = promote_rule(T, Int)
+for T ∈ [:Bool, :Missing, :BigFloat, :BigInt, :Nothing]
+# let S = :Any    
+    @eval begin
+        Base.promote_rule(::Type{<:Static}, ::Type{$T}) = promote_rule(Int, $T)
+        Base.promote_rule(::Type{$T}, ::Type{<:Static}) = promote_rule($T, Int)
+    end
+end
+Base.promote_rule(::Type{<:Static}, ::Type{<:Static}) = Int
 Base.:(%)(::Static{N}, ::Type{Integer}) where {N} = N
 
 Base.iszero(::Static{0}) = true
@@ -22,7 +42,7 @@ Base.iszero(::Static) = false
 Base.isone(::Static{1}) = true
 Base.isone(::Static) = false
 
-for T ∈ [:Any, :Number, :Integer]
+for T = [:Real, :Rational, :Integer]
     @eval begin
         @inline Base.:(+)(i::$T, ::Static{0}) = i
         @inline Base.:(+)(i::$T, ::Static{M}) where {M} = i + M
@@ -38,18 +58,28 @@ for T ∈ [:Any, :Number, :Integer]
         @inline Base.:(*)(::Static{M}, i::$T) where {M} = M * i
     end
 end
+@inline Base.:(+)(::Static{0}, ::Static{0}) = Static{0}()
+@inline Base.:(+)(::Static{0}, ::Static{M}) where {M} = Static{M}()
+@inline Base.:(+)(::Static{M}, ::Static{0}) where {M} = Static{M}()
+
+@inline Base.:(-)(::Static{M}, ::Static{0}) where {M} = Static{M}()
+
 @inline Base.:(*)(::Static{0}, ::Static{0}) = Static{0}()
 @inline Base.:(*)(::Static{1}, ::Static{0}) = Static{0}()
 @inline Base.:(*)(::Static{0}, ::Static{1}) = Static{0}()
 @inline Base.:(*)(::Static{1}, ::Static{1}) = Static{1}()
+@inline Base.:(*)(::Static{M}, ::Static{0}) where {M} = Static{0}()
+@inline Base.:(*)(::Static{0}, ::Static{M}) where {M} = Static{0}()
+@inline Base.:(*)(::Static{M}, ::Static{1}) where {M} = Static{M}()
+@inline Base.:(*)(::Static{1}, ::Static{M}) where {M} = Static{M}()
 for f ∈ [:(+), :(-), :(*), :(/), :(÷), :(%), :(<<), :(>>), :(>>>), :(&), :(|), :(⊻)]
     @eval @generated Base.$f(::Static{M}, ::Static{N}) where {M,N} = Expr(:call, Expr(:curly, :Static, $f(M, N)))
 end
 for f ∈ [:(==), :(!=), :(<), :(≤), :(>), :(≥)]
     @eval begin
         @inline Base.$f(::Static{M}, ::Static{N}) where {M,N} = $f(M, N)
-        @inline Base.$f(::Static{M}, x::Integer) where {M} = $f(M, x)
-        @inline Base.$f(x::Integer, ::Static{M}) where {M} = $f(x, M)
+        @inline Base.$f(::Static{M}, x::Int) where {M} = $f(M, x)
+        @inline Base.$f(x::Int, ::Static{M}) where {M} = $f(x, M)
     end
 end
 
diff --git a/test/runtests.jl b/test/runtests.jl
index 70b7821f7..523081c5c 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -269,9 +269,5 @@ end
             @test convert(typeof(y), @inferred(f(1.4, i))) === y # if f is division and i === Static(0), returns `NaN`; hence use of ==== in check.
         end
     end
-    @test @inferred("Hello world!" * Static(0)) === Static(0)
-    @test @inferred("Hello world!" * Static(1)) === "Hello world!"
-    @test @inferred(Static(0) * "Hello world!") === Static(0)
-    @test @inferred(Static(1) * "Hello world!") === "Hello world!"
 end
 

From dc1727c87baef98517b4caa8a8fe00e1272df0a7 Mon Sep 17 00:00:00 2001
From: Chris Elrod <elrodc@gmail.com>
Date: Wed, 9 Sep 2020 11:25:10 -0400
Subject: [PATCH 08/12] Use Aqua to test ambiguities and unbound_args (as well
 as undef exports.

---
 Project.toml     | 3 ++-
 test/runtests.jl | 4 ++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/Project.toml b/Project.toml
index 4473467d6..d70b9896f 100644
--- a/Project.toml
+++ b/Project.toml
@@ -12,6 +12,7 @@ Requires = "0.5, 1.0"
 julia = "1.2"
 
 [extras]
+Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
 BandedMatrices = "aae01518-5342-5314-be14-df237901396f"
 BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0"
 LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800"
@@ -21,4 +22,4 @@ SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"
 Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
 
 [targets]
-test = ["Test", "LabelledArrays", "StaticArrays", "BandedMatrices", "BlockBandedMatrices", "SuiteSparse", "Random"]
+test = ["Test", "LabelledArrays", "StaticArrays", "BandedMatrices", "BlockBandedMatrices", "SuiteSparse", "Random", "Aqua"]
diff --git a/test/runtests.jl b/test/runtests.jl
index 523081c5c..7e3e839f0 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -3,8 +3,8 @@ using Base: setindex
 import ArrayInterface: has_sparsestruct, findstructralnz, fast_scalar_indexing, lu_instance, Static
 @test ArrayInterface.ismutable(rand(3))
 
-@test isempty(detect_unbound_args(ArrayInterface))
-@test isempty(detect_ambiguities(ArrayInterface))
+using Aqua
+Aqua.test_all(ArrayInterface)
 
 using StaticArrays
 x = @SVector [1,2,3]

From dbb41cc4eea91cbdeaa906ea191b0b9ca032c0f2 Mon Sep 17 00:00:00 2001
From: Chris Elrod <elrodc@gmail.com>
Date: Wed, 9 Sep 2020 12:03:52 -0400
Subject: [PATCH 09/12] Minor change.

---
 src/static.jl | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/static.jl b/src/static.jl
index e81ca828f..3312c5e91 100644
--- a/src/static.jl
+++ b/src/static.jl
@@ -30,8 +30,8 @@ Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T >: Missing} = promote_ru
 for T ∈ [:Bool, :Missing, :BigFloat, :BigInt, :Nothing]
 # let S = :Any    
     @eval begin
-        Base.promote_rule(::Type{<:Static}, ::Type{$T}) = promote_rule(Int, $T)
-        Base.promote_rule(::Type{$T}, ::Type{<:Static}) = promote_rule($T, Int)
+        Base.promote_rule(::Type{S}, ::Type{$T}) where {S <: Static} = promote_rule(Int, $T)
+        Base.promote_rule(::Type{$T}, ::Type{S}) where {S <: Static} = promote_rule($T, Int)
     end
 end
 Base.promote_rule(::Type{<:Static}, ::Type{<:Static}) = Int

From 32afe1c9bf7bf4ca8dd1a86e3e77480bfadd158d Mon Sep 17 00:00:00 2001
From: Chris Elrod <elrodc@gmail.com>
Date: Wed, 9 Sep 2020 12:20:06 -0400
Subject: [PATCH 10/12] Trying fix for Julia 1.2.

---
 src/static.jl | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/static.jl b/src/static.jl
index 3312c5e91..29d532588 100644
--- a/src/static.jl
+++ b/src/static.jl
@@ -13,8 +13,9 @@ Static(::Val{N}) where {N} = Static{N}()
 Base.Val(::Static{N}) where {N} = Val{N}()
 Base.convert(::Type{T}, ::Static{N}) where {T<:Number,N} = convert(T, N)
 Base.convert(::Type{Static{N}}, ::Static{N}) where {N} = Static{N}()
-for S ∈ [:Any, :AbstractIrrational]#, :(Complex{<:Real})]
-# let S = :Any    
+# for S ∈ [:Any, :AbstractIrrational]#, :(Complex{<:Real})]
+    # let S = :Any
+let S = :AbstractIrrational
     @eval begin
         Base.promote_rule(::Type{<:Static}, ::Type{T}) where {T <: $S} = promote_rule(Int, T)
         Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T <: $S} = promote_rule(T, Int)
@@ -27,7 +28,7 @@ Base.promote_rule(::Type{Union{Nothing,Missing}}, ::Type{<:Static}) = Union{Noth
 Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T >: Union{Missing,Nothing}} = promote_rule(T, Int)
 Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T >: Nothing} = promote_rule(T, Int)
 Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T >: Missing} = promote_rule(T, Int)
-for T ∈ [:Bool, :Missing, :BigFloat, :BigInt, :Nothing]
+for T ∈ [:Bool, :Missing, :BigFloat, :BigInt, :Nothing, :Any]
 # let S = :Any    
     @eval begin
         Base.promote_rule(::Type{S}, ::Type{$T}) where {S <: Static} = promote_rule(Int, $T)

From 9ab918e5a7d85c27052ffd1c4d9300d1b48a4ad0 Mon Sep 17 00:00:00 2001
From: Chris Elrod <elrodc@gmail.com>
Date: Wed, 9 Sep 2020 13:41:10 -0400
Subject: [PATCH 11/12] Add integer check to `indices` via `eltype(inds) <:
 Integer

---
 src/ranges.jl |  2 +-
 src/static.jl | 11 +++--------
 2 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/src/ranges.jl b/src/ranges.jl
index be0460c86..fddef2bf6 100644
--- a/src/ranges.jl
+++ b/src/ranges.jl
@@ -203,7 +203,7 @@ specified then indices for visiting each index of `x` is returned.
 """
 @inline function indices(x)
   inds = eachindex(x)
-  if inds isa AbstractUnitRange#{<:Integer} # prevents inference
+  if inds isa AbstractUnitRange && eltype(inds) <: Integer
     return Base.Slice(OptionallyStaticUnitRange(inds))
   else
     return inds
diff --git a/src/static.jl b/src/static.jl
index 29d532588..6a90cecd5 100644
--- a/src/static.jl
+++ b/src/static.jl
@@ -13,14 +13,9 @@ Static(::Val{N}) where {N} = Static{N}()
 Base.Val(::Static{N}) where {N} = Val{N}()
 Base.convert(::Type{T}, ::Static{N}) where {T<:Number,N} = convert(T, N)
 Base.convert(::Type{Static{N}}, ::Static{N}) where {N} = Static{N}()
-# for S ∈ [:Any, :AbstractIrrational]#, :(Complex{<:Real})]
-    # let S = :Any
-let S = :AbstractIrrational
-    @eval begin
-        Base.promote_rule(::Type{<:Static}, ::Type{T}) where {T <: $S} = promote_rule(Int, T)
-        Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T <: $S} = promote_rule(T, Int)
-    end
-end
+
+Base.promote_rule(::Type{<:Static}, ::Type{T}) where {T <: AbstractIrrational} = promote_rule(Int, T)
+Base.promote_rule(::Type{T}, ::Type{<:Static}) where {T <: AbstractIrrational} = promote_rule(T, Int)
 for (S,T) ∈ [(:Complex,:Real), (:Rational, :Integer), (:(Base.TwicePrecision),:Any)]
     @eval Base.promote_rule(::Type{$S{T}}, ::Type{<:Static}) where {T <: $T} = promote_rule($S{T}, Int)
 end

From 581b18a4ac80649fde465a78ea918e1b8e7eae83 Mon Sep 17 00:00:00 2001
From: chriselrod <elrodc@gmail.com>
Date: Wed, 9 Sep 2020 14:46:11 -0400
Subject: [PATCH 12/12] Remove `_get` method.

---
 src/ranges.jl | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/ranges.jl b/src/ranges.jl
index fddef2bf6..601c8455e 100644
--- a/src/ranges.jl
+++ b/src/ranges.jl
@@ -43,7 +43,6 @@ known_step(::Type{<:AbstractUnitRange{T}}) where {T} = one(T)
 # add methods to support ArrayInterface
 
 _get(x) = x
-_get(::Val{V}) where {V} = V
 _get(::Static{V}) where {V} = V
 _get(::Type{Static{V}}) where {V} = V
 _convert(::Type{T}, x) where {T} = convert(T, x)