Skip to content

Commit

Permalink
fix up and avoid inference blowup
Browse files Browse the repository at this point in the history
  • Loading branch information
aviatesk committed May 9, 2024
1 parent 5490a38 commit 703de63
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 11 deletions.
13 changes: 7 additions & 6 deletions base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1347,13 +1347,11 @@ end

# Specialized variant of in for Tuple, which can generate typed comparisons for each element
# of the tuple, skipping values that are statically known to be != at compile time.
function in(x, itr::Tuple)
@_terminates_globally
_in_tuple(x, itr, false)
end
in(x, itr::Tuple) = _in_tuple(x, itr, false)
# This recursive function will be unrolled at compiletime, and will not generate separate
# llvm-compiled specializations for each step of the recursion.
@inline function _in_tuple(x, @nospecialize(itr::Tuple), anymissing::Bool)
function _in_tuple(x, @nospecialize(itr::Tuple), anymissing::Bool)
@inline
# Base case
if isempty(itr)
return anymissing ? missing : false
Expand All @@ -1365,9 +1363,12 @@ end
elseif v
return true
end
return _in_tuple(x, Base.tail(itr), anymissing)
return _in_tuple(x, tail(itr), anymissing)
end

# fallback to the loop implementation after some number of arguments to avoid inference blowup
in(x, itr::Any32) = invoke(in, Tuple{Any,Any}, x, itr)

const = in
(x, itr) = !(x, itr)
(itr) = Fix2(, itr)
Expand Down
24 changes: 19 additions & 5 deletions test/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,8 @@ end
@test B46327() <= B46327()
end

@testset "concrete eval `x in itr::Tuple`" begin
@testset "inference for `x in itr::Tuple`" begin
# concrete evaluation
@test Core.Compiler.is_foldable(Base.infer_effects(in, (Int,Tuple{Int,Int,Int})))
@test Core.Compiler.is_foldable(Base.infer_effects(in, (Char,Tuple{Char,Char,Char})))
for i = (1,2,3)
Expand All @@ -389,10 +390,23 @@ end
end |> only == Val{true}
end
end
@test Base.return_types() do
@test Base.infer_return_type() do
Val(4 in (1,2,3))
end |> only == Val{false}
@test Base.return_types() do
end == Val{false}
@test Base.infer_return_type() do
Val('1' in ('1','2','3'))
end |> only == Val{true}
end == Val{true}

# constant propagation
@test Base.infer_return_type((Int,Int)) do x, y
Val(1 in (x,2,y))
end >: Val{true}
@test Base.infer_return_type((Int,Int)) do x, y
Val(2 in (x,2,y))
end == Val{true}

# should use the loop implementation given large tuples to avoid inference blowup
let t = ntuple(x->'A', 10000);
@test Base.infer_return_type(in, (Char,typeof(t))) == Bool
end
end

0 comments on commit 703de63

Please sign in to comment.