Skip to content

Commit

Permalink
Improve evaluation of nested ComposedFunctions (JuliaLang#45925)
Browse files Browse the repository at this point in the history
* ~~Add (the equivalent of) `@assume_effects :terminates_globally` to
  `unwrap_composed`. Although it could be inferred as `Const`, without
  the annotation, it was not elided for too complex inputs, resulting in
  unnecessary runtime overhead.~~
  EDIT: now JuliaLang#45993 is merged and this part isn't included.
* Reverse recursion order in `call_composed`. This prevents potentially
  changing argument types being piped through the recursion, making
  inference bail out. With the reversed order, only the tuple of
  remaining functions is changing during recursion and is becoming
  strictly simpler, letting inference succeed.

Co-authored-by: Shuhei Kadowaki <aviatesk@gmail.com>
  • Loading branch information
2 people authored and pcjentsch committed Aug 18, 2022
1 parent 740efce commit 543a877
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 7 deletions.
11 changes: 4 additions & 7 deletions base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1017,14 +1017,11 @@ struct ComposedFunction{O,I} <: Function
ComposedFunction(outer, inner) = new{Core.Typeof(outer),Core.Typeof(inner)}(outer, inner)
end

function (c::ComposedFunction)(x...; kw...)
fs = unwrap_composed(c)
call_composed(fs[1](x...; kw...), tail(fs)...)
end
unwrap_composed(c::ComposedFunction) = (unwrap_composed(c.inner)..., unwrap_composed(c.outer)...)
(c::ComposedFunction)(x...; kw...) = call_composed(unwrap_composed(c), x, kw)
unwrap_composed(c::ComposedFunction) = (unwrap_composed(c.outer)..., unwrap_composed(c.inner)...)
unwrap_composed(c) = (maybeconstructor(c),)
call_composed(x, f, fs...) = (@inline; call_composed(f(x), fs...))
call_composed(x, f) = f(x)
call_composed(fs, x, kw) = (@inline; fs[1](call_composed(tail(fs), x, kw)))
call_composed(fs::Tuple{Any}, x, kw) = fs[1](x...; kw...)

struct Constructor{F} <: Function end
(::Constructor{F})(args...; kw...) where {F} = (@inline; F(args...; kw...))
Expand Down
7 changes: 7 additions & 0 deletions test/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

using Random: randstring

include("compiler/irutils.jl")

@testset "ifelse" begin
@test ifelse(true, 1, 2) == 1
@test ifelse(false, 1, 2) == 2
Expand Down Expand Up @@ -182,6 +184,11 @@ end
@test (@inferred g(1)) == ntuple(Returns(1), 13)
h = (-) (-) (-) (-) (-) (-) sum
@test (@inferred h((1, 2, 3); init = 0.0)) == 6.0
issue_45877 = reduce(, fill(sin,500))
@test Core.Compiler.is_foldable(Base.infer_effects(Base.unwrap_composed, (typeof(issue_45877),)))
@test fully_eliminated() do
issue_45877(1.0)
end
end

@testset "function negation" begin
Expand Down

0 comments on commit 543a877

Please sign in to comment.