From 567110f0d3a10d608332efe8020072bb9b5521ff Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Fri, 2 Aug 2019 23:52:39 -0700 Subject: [PATCH] Remove inference API-based code path (outtype) --- benchmark/bench_dot.jl | 4 +- benchmark/bench_missing_argmax.jl | 23 ++-- benchmark/bench_missing_dot.jl | 12 +- docs/src/doctests/show_rf.md | 35 +++-- docs/src/interface.md | 1 - docs/src/manual.md | 1 - examples/transducers.jl | 11 -- src/Transducers.jl | 4 +- src/core.jl | 175 +++++------------------- src/evals.jl | 17 --- src/library.jl | 114 +++------------ src/lister.jl | 1 - src/processes.jl | 90 +++--------- src/show.jl | 24 ---- src/simd.jl | 45 +++--- test/__test_ir.jl | 8 +- test/preamble.jl | 2 +- test/test_core.jl | 54 +------- test/test_examples_transducers.jl | 3 +- test/test_examples_tutorial_missings.jl | 6 - test/test_library.jl | 54 -------- test/test_processes.jl | 46 +------ test/test_simd.jl | 2 +- 23 files changed, 127 insertions(+), 605 deletions(-) delete mode 100644 src/evals.jl diff --git a/benchmark/bench_dot.jl b/benchmark/bench_dot.jl index 7c6887f01f..591d1af81f 100644 --- a/benchmark/bench_dot.jl +++ b/benchmark/bench_dot.jl @@ -29,8 +29,8 @@ suite["xf"] = @benchmarkable( # This is a bit "cheating" since it's using non-public API. It is # just to show the lower-bound of Transducers.jl runtime: -rf = Transducers._reducingfunction( - MapSplat(*), +, Tuple{Float64, Float64}; +rf = reducingfunction( + MapSplat(*), +; simd = true) suite["rf"] = @benchmarkable( transduce($rf, 0.0, zs), diff --git a/benchmark/bench_missing_argmax.jl b/benchmark/bench_missing_argmax.jl index 386e0b7f3f..6a8e753b21 100644 --- a/benchmark/bench_missing_argmax.jl +++ b/benchmark/bench_missing_argmax.jl @@ -21,14 +21,14 @@ end random_missings(n = 10^3, th=2) = [abs(x) > th ? missing : x for x in randn(n)] argext_step(should_update) = - ((oldindex, oldvalue), (index, value)) -> - should_update(oldvalue, value) ? (index, value) : (oldindex, oldvalue) -init_helper(::typeof(>), ::Type{Tuple{F, S}}) where {F, S} = (zero(F), typemax(S)) -init_helper(::typeof(<), ::Type{Tuple{F, S}}) where {F, S} = (zero(F), typemin(S)) -argext_init(should_update) = Initializer(TT -> init_helper(should_update, TT)) + (old, (index, value)) -> + if old === nothing || should_update(old[2], value) + (index, value) + else + old + end -xf_scanext(should_update) = Scan(argext_step(should_update), - argext_init(should_update)) +xf_scanext(should_update) = Scan(argext_step(should_update), nothing) xf_argmax = Enumerate() |> OfType(Tuple{Integer, Number}) |> @@ -45,17 +45,16 @@ let xs = random_missings() end suite["xf"] = @benchmarkable( - foldl(right, ed; init=$(argext_init(<))), + foldl(right, ed; init=nothing), setup=(ed = eduction(xf_argmax, random_missings()))) -rf = Transducers._reducingfunction( +rf = reducingfunction( xf_argmax, - right, - Union{Missing, Float64}; + right; # simd = true, ) suite["rf"] = @benchmarkable( - transduce($rf, $(argext_init(<)), xs), + transduce($rf, nothing, xs), setup=(xs = random_missings())) suite["man"] = @benchmarkable( diff --git a/benchmark/bench_missing_dot.jl b/benchmark/bench_missing_dot.jl index c51b5e6a3b..ce088bf7ff 100644 --- a/benchmark/bench_missing_dot.jl +++ b/benchmark/bench_missing_dot.jl @@ -67,22 +67,18 @@ suite["xf"] = @benchmarkable( # This is a bit "cheating" since it's using non-public API. It is # just to show the lower-bound of Transducers.jl runtime: -rf_nota = Transducers._reducingfunction( +rf_nota = reducingfunction( MapSplat(*) |> NotA(Missing), - +, - Tuple{Union{Missing, Float64}, - Union{Missing, Float64}}; + +; # simd = true, ) suite["rf_nota"] = @benchmarkable( transduce($rf_nota, 0.0, zs), setup=(zs = zip(random_missings.(($n, $n))...))) -rf_oftype = Transducers._reducingfunction( +rf_oftype = reducingfunction( OfType(Tuple{Vararg{Number}}) |> MapSplat(*), - +, - Tuple{Union{Missing, Float64}, - Union{Missing, Float64}}; + +; # simd = true, ) suite["rf"] = @benchmarkable( diff --git a/docs/src/doctests/show_rf.md b/docs/src/doctests/show_rf.md index 5be252d862..82a40b5c34 100644 --- a/docs/src/doctests/show_rf.md +++ b/docs/src/doctests/show_rf.md @@ -8,29 +8,26 @@ end ``` ```jldoctest -Reduction( - Filter(isfinite) |> Map(sin), - +, - Float64) +Reduction(Filter(isfinite) |> Map(sin), +) # output -Reduction{▶ Float64}( +Reduction( Filter(isfinite), - Reduction{▶ Float64}( + Reduction( Map(sin), - BottomRF{▶ Float64}( + BottomRF( +))) ``` ```jldoctest -rf = Reduction(Map(error), right, Int64) +rf = Reduction(Map(error), right) # output -Reduction{▶ Int64}( +Reduction( Map(error), - BottomRF{▶ Union{}}( + BottomRF( Transducers.right)) ``` @@ -38,21 +35,21 @@ Reduction{▶ Int64}( rf = Reduction( TeeZip(Filter(isodd) |> Map(identity) |> TeeZip(Map(identity))), right, - Any) +) # output -Splitter{▶ Any}( - Reduction{▶ Any}( +Splitter( + Reduction( Filter(isodd), - Reduction{▶ Any}( + Reduction( Map(identity), - Splitter{▶ Any}( - Reduction{▶ Any}( + Splitter( + Reduction( Map(identity), - Joiner{▶ ⦃Any, Any⦄}( - Joiner{▶ ⦃Any, ⦃Any, Any⦄⦄}( - BottomRF{▶ ⦃Any, ⦃Any, Any⦄⦄}( + Joiner( + Joiner( + BottomRF( Transducers.right)))))))) ``` diff --git a/docs/src/interface.md b/docs/src/interface.md index efb424a8fb..379d8c34d2 100644 --- a/docs/src/interface.md +++ b/docs/src/interface.md @@ -12,7 +12,6 @@ Transducers.start Transducers.next Transducers.@next Transducers.complete -Transducers.outtype ``` ## Helpers for stateful transducers diff --git a/docs/src/manual.md b/docs/src/manual.md index 6db722652c..d57132d23a 100644 --- a/docs/src/manual.md +++ b/docs/src/manual.md @@ -57,7 +57,6 @@ reducingfunction Completing OnInit CopyInit -Initializer right setinput AdHocFoldable diff --git a/examples/transducers.jl b/examples/transducers.jl index 478aecdfdf..d81e5faac8 100644 --- a/examples/transducers.jl +++ b/examples/transducers.jl @@ -35,15 +35,6 @@ end # hide collect(AddOneIfInt(), Any[3, nothing, 2.0, missing, 5]) -# Notice that output `eltype` is `Any`; it can be fixed by defining -# `outtype`: - -Transducers.outtype(::AddOneIfInt, _intype) = Int - -addone_out2 = begin # hide -collect(AddOneIfInt(), 1:5) -end # hide - # ## Stateful transducer # # `AddOneIfInt` is a stateless transducer which is very easy to @@ -97,8 +88,6 @@ function Transducers.next(rf::R_{RandomRecall}, result, input) end end -Transducers.outtype(::RandomRecall, intype) = intype - # Any transducer with custom [`Transducers.start`](@ref) must have a # corresponding [`Transducers.complete`](@ref). It is responsible for # unwrapping the `result` and call the `complete` for the inner diff --git a/src/Transducers.jl b/src/Transducers.jl index 0866669a5d..76edfd3358 100644 --- a/src/Transducers.jl +++ b/src/Transducers.jl @@ -5,7 +5,7 @@ export Transducer, Map, Filter, Cat, MapCat, Take, PartitionBy, Scan, Zip, Interpose, Dedupe, Partition, Iterated, Count, GroupBy, ReduceIf, TakeLast, FlagFirst, MapSplat, ScanEmit, Enumerate, NotA, OfType, transduce, eduction, setinput, Reduced, reduced, unreduced, ifunreduced, - Completing, Initializer, OnInit, CopyInit, right, reducingfunction, + Completing, OnInit, CopyInit, right, reducingfunction, AdHocFoldable # Deprecated: @@ -37,8 +37,6 @@ include("deprecated.jl") include("interop/blockarrays.jl") include("interop/lazyarrays.jl") -include("evals.jl") - function __init__() @require BlockArrays="8e7c35d0-a365-5155-bbbb-fb81a777f24e" begin __foldl__(rf, acc, coll::BlockArrays.BlockArray) = diff --git a/src/core.jl b/src/core.jl index 0a921f5ff1..8306634d74 100644 --- a/src/core.jl +++ b/src/core.jl @@ -185,21 +185,6 @@ macro next(rf, state, input) end end -struct NoType end -const NOTYPE = NoType() -const Typeish{T} = Union{Type{T}, NoType} - -astype(::NoType) = Any -astype(T::Type) = T - -function Base.show(io::IO, ::NoType) - if !get(io, :limit, false) - # Don't show full name in REPL etc.: - print(io, "Transducers.") - end - print(io, "NOTYPE") -end - abstract type Transducer end abstract type AbstractFilter <: Transducer end @@ -224,19 +209,13 @@ Transducer """ AbstractFilter <: Transducer -The abstract type for filter-like transducers. [`outtype`](@ref) is -appropriately defined for child types. +The abstract type for filter-like transducers. """ AbstractFilter -abstract type AbstractReduction{intype, innertype} end - -InType(::T) where T = InType(T) -InType(NOTYPE::NoType) = NOTYPE -InType(::Type{<:AbstractReduction{intype}}) where {intype} = intype -InType(T::Type) = throw(MethodError(InType, (T,))) +abstract type AbstractReduction{innertype} end -InnerType(::Type{<:AbstractReduction{<:Any, T}}) where T = T +InnerType(::Type{<:AbstractReduction{T}}) where T = T Setfield.constructor_of(::Type{T}) where {T <: AbstractReduction} = T @@ -257,14 +236,12 @@ xform(rf::AbstractReduction) = rf.xform has(rf::AbstractReduction, T::Type{<:Transducer}) = has(Transducer(rf), T) -struct BottomRF{intype, F} <: AbstractReduction{intype, F} +struct BottomRF{F} <: AbstractReduction{F} inner::F end -BottomRF{intype}(f::F) where {intype, F} = BottomRF{intype, F}(f) - -ensurerf(rf::AbstractReduction, ::Typeish) = rf -ensurerf(f, intype::Typeish) = BottomRF{intype}(f) +ensurerf(rf::AbstractReduction) = rf +ensurerf(f) = BottomRF(f) # Not calling rf.inner(result, input) etc. directly since it can be # `Completing` etc. @@ -273,10 +250,6 @@ next(rf::BottomRF, result, input) = next(inner(rf), result, input) complete(rf::BottomRF, result) = complete(inner(rf), result) combine(rf::BottomRF, a, b) = combine(inner(rf), a, b) -FinalType(::T) where {T <: AbstractReduction} = FinalType(T) -FinalType(::Type{<:BottomRF{intype}}) where intype = intype -FinalType(::Type{T}) where {T <: AbstractReduction} = FinalType(InnerType(T)) - Transducer(::BottomRF) = IdentityTransducer() as(rf::T, ::Type{T}) where T = rf @@ -286,20 +259,29 @@ as(rf, T::Type) = as(inner(rf), T) # whatever, input -> whatever # # The `Reduction` type corresponds to such a function, but keeps extra information: -# * InType records the type of input # * `xform` and `inner` are a decomposition of the reduction function into # a transducer `xform` and an inner reduction function `inner`. # `inner` can be either a `Reduction` or a function with arity-2 and arity-1 methods # -struct Reduction{X <: Transducer, I, intype} <: AbstractReduction{intype, I} +struct Reduction{X <: Transducer, I} <: AbstractReduction{I} xform::X inner::I + + Reduction{X, I}(xf, inner) where {X, I} = new{X, I}(xf, inner) + + Reduction(xf::X, inner::I) where {X <: Transducer, I} = + if I <: AbstractReduction + new{X, I}(xf, inner) + else + rf = ensurerf(inner) + new{X, typeof(rf)}(xf, rf) + end end @inline (rf::Reduction)(state, input) = next(rf, state, input) -prependxf(rf::AbstractReduction, xf) = Reduction(xf, rf, InType(rf)) -setinner(rf::Reduction, inner) = Reduction(xform(rf), inner, InType(rf)) +prependxf(rf::AbstractReduction, xf) = Reduction(xf, rf) +setinner(rf::Reduction, inner) = Reduction(xform(rf), inner) Transducer(rf::Reduction) = if inner(rf) isa BottomRF @@ -318,29 +300,16 @@ transducer `xform(rf)::X` and the inner reducing function """ const R_{X} = Reduction{<:X} -Reduction(xf::X, inner::I, InType::Typeish) where {X, I} = - if I <: AbstractReduction - Reduction{X, I, InType}(xf, inner) - else - Reduction(xf, ensurerf(inner, _outtype(xf, InType)), InType) - end - -@inline function Reduction(xf_::Composition, f, intype::Typeish) +@inline function Reduction(xf_::Composition, f) xf = _normalize(xf_) # @assert !(xf.outer isa Composition) - return Reduction( - xf.outer, - Reduction(xf.inner, f, _outtype(xf.outer, intype)), - intype) + return Reduction(xf.outer, Reduction(xf.inner, f)) end @inline _normalize(xf) = xf @inline _normalize(xf::Composition{<:Composition}) = _normalize(xf.outer.outer |> _normalize(xf.outer.inner |> xf.inner)) -outtype(xf::Composition, intype) = outtype(xf.inner, outtype(xf.outer, intype)) -# TeeZip needs it - # Not sure if this a good idea... (But it's easier to type) @inline Base.:|>(f::Transducer, g::Transducer) = _normalize(Composition(f, g)) # Base.∘(f::Transducer, g::Transducer) = Composition(f, g) @@ -353,9 +322,8 @@ outtype(xf::Composition, intype) = outtype(xf.inner, outtype(xf.outer, intype)) Reset "bottom" reducing function of `rf` to `f`. """ -reform(rf::Reduction, f) = - Reduction(xform(rf), reform(inner(rf), f), InType(rf)) -reform(rf::BottomRF, f) = BottomRF{InType(rf)}(reform(inner(rf), f)) +reform(rf::Reduction, f) = Reduction(xform(rf), reform(inner(rf), f)) +reform(rf::BottomRF, f) = BottomRF(reform(inner(rf), f)) reform(::Any, f) = f """ @@ -537,7 +505,7 @@ This is intended to be used only in [`start`](@ref). Inside Consider a reducing step constructed as - rf = Reduction(xf₁ |> xf₂ |> xf₃, f, intype) + rf = Reduction(xf₁ |> xf₂ |> xf₃, f) where each `xfₙ` is a stateful transducer and hence needs a private state `stateₙ`. Then, calling `start(rf, result))` is equivalent to @@ -597,41 +565,6 @@ unwrap_all(ps::PrivateState) = unwrap_all(psresult(ps)) unwrap_all(result) = result unwrap_all(ps::Reduced) = Reduced(unwrap_all(unreduced(ps))) -""" - needintype(xf::Transducer) :: Bool - needintype(T::Type{<:Transducer}) :: Bool - -Return `false` if `start(xf::T, _)` does not need `intype`. Abstract -`Transducer` defaults to return `true`. This is because it is -impossible to know if a user-defined transducer needs `intype` -(typically via `initvalue`). -""" -needintype(::T) where {T <: Transducer} = needintype(T) -needintype(::Type{Composition{XO, XI}}) where {XO, XI} = - needintype(XO) || needintype(XI) - -# This definition is not used in the builtin transducers. It will be -# used only for the transducers defined outside Transducers.jl: -needintype(::Type{<:Transducer}) = true - -function default_needintype_with_init(T::Type{<:Transducer}) - I = fieldtype(T, :init) - return I <: AbstractInitializer - # Maybe I need to do this? - # return !isconcretetype(I) || I <: AbstractInitializer -end - -""" - outtype(xf::Transducer, intype) - -Output item type for the transducer `xf` when the input type is `intype`. -""" -outtype(::Any, ::Any) = Any -outtype(::AbstractFilter, intype) = intype - -_outtype(::Any, ::NoType) = NOTYPE -_outtype(xf, intype) = outtype(xf, intype) - # isexpansive(::Any) = true isexpansive(::Transducer) = true isexpansive(::AbstractFilter) = false @@ -646,7 +579,6 @@ iscontractive(rf::Reduction) = iscontractive(xform(rf)) && iscontractive(inner(r =# struct NoComplete <: Transducer end -outtype(::NoComplete, intype) = intype next(rf::R_{NoComplete}, result, input) = next(inner(rf), result, input) complete(::R_{NoComplete}, result) = result # don't call inner complete @@ -670,11 +602,10 @@ combine(rf::Completing, a, b) = combine(rf.f, a, b) # If I expose `Reduction` as a user-interface, I should export # `skipcomplete` instead of the struct `Completing`. -skipcomplete(rf::Reduction) = Reduction(NoComplete(), rf, InType(rf)) +skipcomplete(rf::Reduction) = Reduction(NoComplete(), rf) skipcomplete(f) = Completing(f) # skipcomplete(f) = Reduction(NoComplete(), f, Any) -# TODO: get rid of `Completing` struct. I need to make sure it's -# possible to refine `InType` from `Any` when it's re-composed. +# TODO: get rid of `Completing` struct. struct SideEffect{F} # Note: not a Transducer f::F @@ -730,49 +661,9 @@ abstract type Foldable <: Reducible end abstract type AbstractInitializer end -""" - Initializer(f) - -Wrap a factory function to create an initial value for transducible -processes (e.g., [`mapfoldl`](@ref)) and "stateful" transducers (e.g., -[`Scan`](@ref)). Factory function `f` takes the input type to the -transducer or the reducing function. - -!!! compat "Transducers.jl 0.3" - - `Initializer` is deprecated since Transducers 0.3. Please use - [`OnInit`](@ref). -""" -struct Initializer{F} <: AbstractInitializer - f::F - - Initializer{F}(f) where F = new{F}(f) -end - -function Initializer(f) - Base.depwarn( - """ - `Initializer(T -> ...)` is deprecated. Please use `OnInit(() -> ...)`. - """, - :Initializer) - return Initializer{typeof(f)}(f) -end - -initvalue(x, ::Any) = x -initvalue(init::Initializer, intype) = init.f(astype(intype)) - -_initvalue(rf::Reduction) = initvalue(xform(rf).init, InType(rf)) +initvalue(x) = x -inittypeof(::T, ::Type) where T = T -function inittypeof(init::AbstractInitializer, intype::Type) - # Maybe I should just call it? But that would be a bit of waste - # when `init.f` allocates... - T = Base.promote_op(initvalue, typeof(init), Type{intype}) - isconcretetype(T) && return T - return typeof(initvalue(init, intype)) # T==Union{} hits this code pass -end - -Base.show(io::IO, init::Initializer) = _default_show(io, init) +_initvalue(rf::Reduction) = initvalue(xform(rf).init) """ OnInit(f) @@ -866,8 +757,7 @@ struct OnInit{F} <: AbstractInitializer f::F end -initvalue(init::OnInit, ::Any) = init.f() -inittypeof(::OnInit, ::Type) = Any +initvalue(init::OnInit) = init.f() Base.show(io::IO, init::OnInit) = _default_show(io, init) @@ -876,8 +766,6 @@ Base.show(io::IO, init::OnInit) = _default_show(io, init) This is equivalent to `OnInit(() -> deepcopy(value))`. -See [`Initializer`](@ref). - !!! compat "Transducers.jl 0.3" New in version 0.3. @@ -905,8 +793,7 @@ struct CopyInit{T} <: AbstractInitializer value::T end -initvalue(init::CopyInit, ::Any) = deepcopy(init.value) -inittypeof(::CopyInit{T}, ::Type) where T = T +initvalue(init::CopyInit) = deepcopy(init.value) Base.show(io::IO, init::CopyInit) = _default_show(io, init) @@ -1012,7 +899,7 @@ _realbottomrf(op) = op _realbottomrf(rf::AbstractReduction) = _realbottomrf(as(rf, BottomRF).inner) _realbottomrf(rf::Completing) = rf.f -provide_init(rf, init) = initvalue(init, FinalType(rf)) +provide_init(rf, init) = initvalue(init) function provide_init(rf, ::MissingInit) op = _realbottomrf(rf) hasinitialvalue(op) && return DefaultInit(op) diff --git a/src/evals.jl b/src/evals.jl deleted file mode 100644 index 89d0eb5501..0000000000 --- a/src/evals.jl +++ /dev/null @@ -1,17 +0,0 @@ -for name in names(@__MODULE__; all=true) - T = getproperty((@__MODULE__), name) - T isa Type{<:Transducer} || continue - isstructtype(T) || continue - nameof(T) === name || continue - T === Composition && continue - @assert T !== Transducer - @assert T !== AbstractFilter - - if :init ∈ fieldnames(T) - # This is required only for `Initializer`. - @eval needintype(T::Type{<:$T}) = default_needintype_with_init(T) - else - # All other builtin transducers do not require the input type. - @eval needintype(::Type{<:$T}) = false - end -end diff --git a/src/library.jl b/src/library.jl index d818a330e5..daca2e1df9 100644 --- a/src/library.jl +++ b/src/library.jl @@ -48,7 +48,6 @@ struct Map{F} <: Transducer end isexpansive(::Map) = false -outtype(xf::Map, intype) = Union{Base.return_types(xf.f, (intype,))...} next(rf::R_{Map}, result, input) = next(inner(rf), result, xform(rf).f(input)) """ @@ -73,7 +72,6 @@ struct MapSplat{F} <: Transducer end isexpansive(::MapSplat) = false -outtype(xf::MapSplat, intype) = Union{Base.return_types(xf.f, intype)...} next(rf::R_{MapSplat}, result, input) = next(inner(rf), result, xform(rf).f(input...)) @@ -120,7 +118,6 @@ struct Replace{D} <: Transducer end isexpansive(::Replace) = false -outtype(xf::Replace, intype) = Union{intype, avaltype(xf.d)} next(rf::R_{Replace}, result, input) = next(inner(rf), result, get(xform(rf).d, input, input)) @@ -144,8 +141,6 @@ true struct Cat <: Transducer end -outtype(::Cat, intype) = ieltype(intype) - next(rf::R_{Cat}, result, input) = foldl_nocomplete(inner(rf), result, input) # https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/mapcat @@ -221,8 +216,6 @@ julia> collect(NotA(Missing), [1, missing, 2]) struct NotA{T} <: AbstractFilter end NotA(T::Type) = NotA{T}() -outtype(::NotA{T}, intype) where T = Core.Compiler.typesubtract(intype, T) - next(rf::R_{NotA{T}}, result, input) where T = input isa T ? result : next(inner(rf), result, input) @@ -231,8 +224,6 @@ next(rf::R_{NotA{T}}, result, input) where T = # information to the compiler), it seems `Filter(!ismissing)` is # enough for a small example. See: # https://discourse.julialang.org/t/19159/11 -# -# So, the main benefit of `NotA` over `Filter` is `outtype`. """ OfType(T) @@ -254,8 +245,6 @@ julia> collect(OfType(Int), [1, missing, 2]) struct OfType{T} <: AbstractFilter end OfType(T::Type) = OfType{T}() -outtype(::OfType{T}, intype) where T = Base.typeintersect(T, intype) - @inline next(rf::R_{OfType{T}}, result, input) where T = _next_oftype(T, inner(rf), result, input) @@ -665,7 +654,6 @@ julia> collect(FlagFirst(), 1:3) struct FlagFirst <: Transducer end isexpansive(::FlagFirst) = false -outtype(::FlagFirst, intype) = Tuple{Bool,intype} start(rf::R_{FlagFirst}, result) = wrap(rf, true, start(inner(rf), result)) complete(rf::R_{FlagFirst}, result) = complete(inner(rf), unwrap(rf, result)[2]) @@ -729,7 +717,6 @@ Partition(size, step; flush = false) = Partition(size; step = step, flush = flus Partition(size; step = size, flush = false) = Partition(size, step, flush) isexpansive(::Partition) = false -outtype(::Partition, intype) = DenseSubVector{intype} function start(rf::R_{Partition}, result) buf = Union{}[] @@ -835,7 +822,6 @@ end struct Unseen end isexpansive(::PartitionBy) = false -outtype(::PartitionBy, intype) = Vector{intype} function start(rf::R_{PartitionBy}, result) iinput = Union{}[] @@ -896,9 +882,6 @@ struct Keep{F} <: Transducer end isexpansive(::Keep) = false -outtype(xf::Keep, intype) = - Core.Compiler.typesubtract(Union{Base.return_types(xf.f, (intype,))...}, - Nothing) function next(rf::R_{Keep}, result, input) iinput = xform(rf).f(input) @@ -972,8 +955,6 @@ struct Interpose{T} <: Transducer sep::T end -outtype(xf::Interpose, intype) = Union{typeof(xf.sep), intype} - start(rf::R_{Interpose}, result) = wrap(rf, Val(true), start(inner(rf), result)) complete(rf::R_{Interpose}, result) = complete(inner(rf), unwrap(rf, result)[2]) @@ -1082,23 +1063,7 @@ end Scan(f) = Scan(f, makeid(f, Init)) -_lefttype(xf::Scan, intype) = inittypeof(xf.init, intype) - -# Maybe this is fine: -# outtype(xf::Scan, intype) = Union{_lefttype(xf, intype), intype} - isexpansive(::Scan) = false -outtype(xf::Scan, intype) = - _type_scan_fixedpoint(xf.f, _lefttype(xf, intype), intype) - -function _type_scan_fixedpoint(f, A, X, limit = 10) - for _ in 1:limit - Y = Union{A,Base.return_types(f, (A, X))...} - A === Y && return Y - A = Y - end - return Any -end function start(rf::R_{Scan}, result) init = _initvalue(rf) @@ -1159,17 +1124,6 @@ ScanEmit(f, init) = ScanEmit(f, init, nothing) isexpansive(xf::ScanEmit) = xf.onlast === nothing -function outtype(xf::ScanEmit, intype) - U = _type_scan_fixedpoint((u, x) -> xf.f(u, x)[2], - inittypeof(xf.init, intype), - intype) - Y = Base._return_type((u, x) -> xf.f(u, x)[1], Tuple{U, intype}) - if xf.onlast === nothing - return Y - end - return Union{Y, Base._return_type(xf.onlast, Tuple{U})} -end - start(rf::R_{ScanEmit}, result) = wrap(rf, _initvalue(rf), start(inner(rf), result)) @@ -1295,15 +1249,13 @@ function complete(rf::R_{AdHocXF}, result) end """ - Iterated(f, init[, T::Type]) + Iterated(f, init) Generate a sequence `init`, `f(init)`, `f(f(init))`, `f(f(f(init)))`, and so on. $(_shared_notes_unfold) -Use the third argument `T` to specify the output type of `f`. - $_use_initializer See also: [`Scan`](@ref), [`ScanEmit`](@ref). @@ -1335,23 +1287,9 @@ julia> collect(Zip(Map(identity), Iterated(x -> 2x, 1)), 1:5) struct Iterated{F, T} <: Transducer f::F init::T - - Iterated(f::F, init, T::Type) where F = new{F, T}(f, init) -end - -Iterated(f, init::T) where T = Iterated(f, init, _type_fixedpoint(f, T)) - -function _type_fixedpoint(f, X, limit = 10) - for _ in 1:limit - Y = Union{X, Base.return_types(f, (X,))...} - X === Y && return Y - X = Y - end - return Any end isexpansive(::Iterated) = false -outtype(xf::Iterated, intype) = inittypeof(xf.init, intype) start(rf::R_{Iterated}, result) = wrap(rf, _initvalue(rf), start(inner(rf), result)) complete(rf::R_{Iterated}, result) = complete(inner(rf), unwrap(rf, result)[2]) @@ -1399,7 +1337,6 @@ end Count(start = 1) = Count(start, oneunit(start)) isexpansive(::Count) = false -outtype(xf::Count{T}, ::Any) where T = T start(rf::R_{Count}, result) = wrap(rf, xform(rf).start, start(inner(rf), result)) complete(rf::R_{Count}, result) = complete(inner(rf), unwrap(rf, result)[2]) next(rf::R_{Count}, result, ::Any) = @@ -1473,57 +1410,49 @@ end # MapSplat(*), # rf)))))) -struct Splitter{intype, R} <: AbstractReduction{intype, R} +struct Splitter{R} <: AbstractReduction{R} inner::R end -Splitter(inner::R) where R = Splitter{InType(R), R}(inner) setinner(rf::Splitter, inner) = Splitter(inner) reform(rf::Splitter, f) = Splitter(reform(inner(rf), f)) -struct Joiner{intype, F} <: AbstractReduction{intype, F} +struct Joiner{F} <: AbstractReduction{F} inner::F # original inner reduction end -Joiner(inner::R) where R = Joiner{InType(R), R}(inner) setinner(rf::Joiner, inner) = Joiner(inner) reform(rf::Joiner, f) = Joiner(reform(inner(rf), f)) # It's ugly that `Reduction` returns a non-`Reduction` type! TODO: fix it -function Reduction(xf::Composition{<:TeeZip}, f, intype::Typeish) +function Reduction(xf::Composition{<:TeeZip}, f) @nospecialize - rf = _teezip_rf(xf.outer.xform, intype, (xf.inner, f, intype)) + rf = _teezip_rf(xf.outer.xform, (xf.inner, f)) return Splitter(rf) end -function Reduction(xf::TeeZip, f, intype::Typeish) +function Reduction(xf::TeeZip, f) @nospecialize - rf = _teezip_rf(xf.xform, intype, (nothing, f, intype)) + rf = _teezip_rf(xf.xform, (nothing, f)) return Splitter(rf) end -function _teezip_rf(xf::Composition, intype, downstream) +function _teezip_rf(xf::Composition, downstream) @nospecialize - intype_inner = _outtype(xf.outer, intype) - rf_inner = _teezip_rf(xf.inner, intype_inner, downstream) - return Reduction(xf.outer, rf_inner, intype) + rf_inner = _teezip_rf(xf.inner, downstream) + return Reduction(xf.outer, rf_inner) end -function _teezip_rf(xf, intype, downstream) +function _teezip_rf(xf, downstream) @nospecialize - xf_ds, f, intype_orig = downstream - if intype_orig === NOTYPE - intype_ds = NOTYPE - else - intype_ds = Tuple{intype_orig, outtype(xf, intype)} - end + xf_ds, f = downstream if xf_ds === nothing - rf_ds = ensurerf(f, intype_ds) + rf_ds = ensurerf(f) else - rf_ds = Reduction(xf_ds, f, intype_ds) + rf_ds = Reduction(xf_ds, f) end - joiner = Joiner{intype_ds, typeof(rf_ds)}(rf_ds) - return Reduction(xf, joiner, intype) + joiner = Joiner(rf_ds) + return Reduction(xf, joiner) end const SplitterState = PrivateState{<:Splitter} @@ -1567,7 +1496,6 @@ next(rf::Joiner, result, input) = # Putting `state` back to make it type stable. isexpansive(xf::TeeZip) = isexpansive(xf.xform) -outtype(xf::TeeZip, intype) = Tuple{intype, outtype(xf.xform, intype)} function Transducer(rf::Splitter) xf_split, rf_ds = _rf_to_teezip(inner(rf)) @@ -1660,9 +1588,6 @@ GetIndex{inbounds}(array::A) where {inbounds, A} = GetIndex{inbounds, A}(array) GetIndex(array) = GetIndex{false}(array) isexpansive(::GetIndex) = false -outtype(xf::GetIndex, ::Type{<:Integer}) = eltype(xf.array) -outtype(::GetIndex, T) = - error("Unexpected non-integer input type for GetIndex:\n", T) next(rf::R_{GetIndex{true}}, result, input) = next(inner(rf), result, @inbounds xform(rf).array[input]) @@ -1705,9 +1630,6 @@ SetIndex{inbounds}(array::A) where {inbounds, A} = SetIndex{inbounds, A}(array) SetIndex(array) = SetIndex{false}(array) isexpansive(::SetIndex) = false -outtype(xf::SetIndex, ::Type{<:Tuple{Integer, <:Any}}) = eltype(xf.array) -outtype(::SetIndex, T) = - error("Unexpected non-integer input type for SetIndex:\n", T) next(rf::R_{SetIndex{true}}, result, input::NTuple{2, Any}) = next(inner(rf), result, (@inbounds xform(rf).array[input[1]] = input[2];)) @@ -1767,7 +1689,6 @@ struct Inject{T} <: Transducer end isexpansive(::Inject) = false -outtype(xf::Inject, intype) = Tuple{intype, ieltype(xf.iterator)} start(rf::R_{Inject}, result) = wrap(rf, iterate(xform(rf).iterator), start(inner(rf), result)) complete(rf::R_{Inject}, result) = complete(inner(rf), unwrap(rf, result)[2]) @@ -1814,7 +1735,6 @@ end Enumerate(start = 1) = Enumerate(start, oneunit(start)) isexpansive(::Enumerate) = false -outtype(xf::Enumerate{T}, intype) where {T} = Tuple{T, intype} start(rf::R_{Enumerate}, result) = wrap(rf, xform(rf).start, start(inner(rf), result)) complete(rf::R_{Enumerate}, result) = complete(inner(rf), unwrap(rf, result)[2]) @@ -1949,7 +1869,7 @@ complete(rf::R_{GroupBy}, result) = complete(inner(rf), unwrap(rf, result)[2]) key = xform(rf).key(input) gstate, somegr = dictset!!(gstate, key) do value if value === nothing - gr0 = start(xform(rf).rf, initvalue(xform(rf).init, NOTYPE)) + gr0 = start(xform(rf).rf, initvalue(xform(rf).init)) else gr0 = something(value) end diff --git a/src/lister.jl b/src/lister.jl index 5dd5f88c92..c28eaf61e1 100644 --- a/src/lister.jl +++ b/src/lister.jl @@ -17,7 +17,6 @@ _unexported_public_api = ( start, next, complete, - outtype, # Helpers for stateful transducers wrap, unwrap, diff --git a/src/processes.jl b/src/processes.jl index 6e16d733cd..6e625ba255 100644 --- a/src/processes.jl +++ b/src/processes.jl @@ -68,8 +68,7 @@ julia> transduce(rf_bad, "", 1:3) "123112312123123" ``` -One way to solve this issue is to use [`CopyInit`](@ref) or -[`Initializer`](@ref). +One way to solve this issue is to use [`CopyInit`](@ref) or [`OnInit`](@ref). ```jldoctest reducingfunction julia> scan_state = CopyInit([]) @@ -87,12 +86,8 @@ julia> transduce(rf_good, "", 1:3) "112123" ``` """ -@inline reducingfunction(xf::Transducer, step; kwargs...) = - _reducingfunction(xf, step, NOTYPE; kwargs...) - -@inline _reducingfunction(xf::Transducer, step, intype::Typeish; - simd::SIMDFlag = Val(false)) = - maybe_usesimd(Reduction(xf, step, intype), simd) +@inline reducingfunction(xf::Transducer, step; simd::SIMDFlag = Val(false)) = + maybe_usesimd(Reduction(xf, step), simd) """ __foldl__(rf, init, reducible::T) @@ -224,7 +219,7 @@ may be able to emit a good code. This function exists only for performance tuning. """ function simple_transduce(xform, f, init, coll) - rf = rf_for(xform, f, init, eltype(coll)) + rf = Reduction(xform, f) return __simple_foldl__(rf, _start_init(rf, init), coll) end @@ -300,18 +295,10 @@ See [`mapfoldl`](@ref). transduce function transduce(xform::Transducer, f, init, coll; kwargs...) - rf = rf_for(xform, f, init, ieltype(coll)) + rf = Reduction(xform, f) return transduce(rf, init, coll; kwargs...) end -_needintype(xf, step, init) = - (init isa MissingInit && !hasinitialvalue(_realbottomrf(step))) || - (init isa Initializer && !(init isa CopyInit)) || - needintype(xf) - -rf_for(xf, step, init, intype) = - Reduction(xf, step, _needintype(xf, step, init) ? intype : NOTYPE) - # Materialize initial value and then call start. _start_init(rf, init) = start(rf, provide_init(rf, init)) @@ -425,7 +412,7 @@ function transduce_assoc( basesize = Threads.nthreads() == 1 ? typemax(Int) : 512, ) reducible = SizedReducible(coll, basesize) - rf = maybe_usesimd(rf_for(xform, step, init, ieltype(coll)), simd) + rf = maybe_usesimd(Reduction(xform, step), simd) stop = Threads.Atomic{Bool}(false) acc = @return_if_reduced __reduce__(stop, rf, init, reducible) return complete(rf, acc) @@ -504,17 +491,7 @@ struct Eduction{F, C} end Eduction(xform::Transducer, coll) = - Eduction(rf_for(xform, Completing(push!!), Union{}[], ieltype(coll)), coll) - -infer_input_types(ed::Eduction) = - if FinalType(ed.rf) isa Type - ed - else - Eduction(Reduction(Transducer(ed.rf), - as(ed.rf, BottomRF).inner, - ieltype(ed.coll)), - ed.coll) - end + Eduction(Reduction(xform, Completing(push!!)), coll) Transducer(ed::Eduction) = Transducer(ed.rf) @@ -523,10 +500,6 @@ transduce(xform::Transducer, f, init, ed::Eduction) = Base.IteratorSize(::Type{<:Eduction}) = Base.SizeUnknown() -Base.IteratorEltype(::Type{<:Eduction{F}}) where {F} = - F === NOTYPE ? Base.EltypeUnknown() : Base.HasEltype() -Base.eltype(::Type{<:Eduction{F}}) where F = astype(FinalType(F)) - function Base.iterate(ts::Eduction, state = nothing) if state === nothing cret = iterate(ts.coll) @@ -673,13 +646,8 @@ julia> collect(Interpose(missing), 1:3) ``` """ function Base.collect(xf::Transducer, coll) - if needintype(xf) - rf = Reduction(xf, Completing(push!), eltype(coll)) - to = FinalType(rf)[] - else - rf = reducingfunction(xf, Completing(push!!)) - to = Union{}[] - end + rf = Reduction(xf, Completing(push!!)) + to = Union{}[] result = unreduced(transduce(rf, to, coll)) if result isa Vector{Union{}} et = @default_finaltype(xf, coll) @@ -747,10 +715,9 @@ function _prepare_map(xf, dest, src, simd) # TODO: support Dict indices = eachindex(dest, src) - rf = _reducingfunction( + rf = reducingfunction( TeeZip(GetIndex{true}(src) |> xf) |> SetIndex{true}(dest), (::Vararg) -> nothing, - needintype(xf) ? eltype(indices) : NOTYPE; simd = simd) return rf, indices, dest @@ -808,14 +775,10 @@ function Base.foldl(step, xform::Transducer, itr; mapfoldl(xform, Completing(step), itr; kw...) end -@inline Base.foldl(step, ed::Eduction; init=MissingInit(), kwargs...) = - if FinalType(ed.rf) === NOTYPE - xf = Transducer(ed.rf) - unreduced(transduce(xf, Completing(step), init, ed.coll; kwargs...)) - else - rf = reform(ed.rf, Completing(step)) - unreduced(transduce(rf, init, ed.coll; kwargs...)) - end +@inline function Base.foldl(step, ed::Eduction; init=MissingInit(), kwargs...) + xf = Transducer(ed.rf) + return unreduced(transduce(xf, Completing(step), init, ed.coll; kwargs...)) +end """ foreach(eff, xf::Transducer, reducible; simd) @@ -1018,7 +981,6 @@ through a channel. `Channel(xf, itr)` and `Channel(eduction(xf, itr))` are equivalent. Note that `itr` itself can be a `Channel`. Keyword arguments are passed to `Channel(function; kwargs...)`. -`ctype` is inferred from `xf` if not specified. # Examples ```jldoctest @@ -1032,9 +994,6 @@ julia> ed = eduction(Map(x -> 1:x), ch2); julia> ch3 = Channel(Cat(), ed); -julia> typeof(ch1) === typeof(ch2) === typeof(ch3) === Channel{Int} -true - julia> foreach(PartitionBy(isequal(1)), ch3) do input @show input end; @@ -1044,29 +1003,12 @@ input = [1] input = [2, 3, 4, 5, 6, 7, 8, 9] ``` """ -Base.Channel(xform::Transducer, itr; - ctype::Type = _chan_ctype(xform, itr), - kwargs...) = - Channel(; ctype = ctype, kwargs...) do chan +Base.Channel(xform::Transducer, itr; kwargs...) = + Channel(; kwargs...) do chan foreach(x -> put!(chan, x), xform, itr) return end -function _chan_ctype(xform, itr) - ctype = outtype(xform, ieltype(itr)) - if ctype === Union{} - error(""" -$_non_executable_transducer_msg -Use `mapfoldl` etc. with `init` argument to run the transducer -forcefully and find out which one causes the problem. -""") - end - return ctype -end - -Base.Channel(xform::Transducer, ed::Eduction; kwargs...) = - Channel(Transducer(ed) |> xform, ed.coll; kwargs...) - Base.Channel(ed::Eduction; kwargs...) = Channel(Transducer(ed), ed.coll; kwargs...) diff --git a/src/show.jl b/src/show.jl index 7b85079bca..ad990adaa9 100644 --- a/src/show.jl +++ b/src/show.jl @@ -177,29 +177,6 @@ function _show_noindent(io, mime, x::Function) print(io, nameof(x)) end -function _show_intype(io, rf) - print(io, "{▶ ") - _show_type(io, InType(rf)) - print(io, "}") -end - -_show_type(io, t) = show(io, t) -_show_type(io, t::Type{Union{}}) = show(io, t) - -function _show_type(io, t::Type{<:Tuple}) - print(io, '⦃') - isfirst = true - for e in t.types - if isfirst - isfirst = false - else - print(io, ", ") - end - _show_type(io, e) - end - print(io, '⦄') -end - function _show_impl(io, mime, rf::AbstractReduction) indent = get(io, :indent, "") first_indent = get(io, :first_indent, indent) @@ -210,7 +187,6 @@ function _show_impl(io, mime, rf::AbstractReduction) print(io, first_indent) print(io, Base.typename(typeof(rf)).name) - _show_intype(io, rf) println(io, '(') _show_multiline_args(next_io, mime, rf) print(io, ")") diff --git a/src/simd.jl b/src/simd.jl index d1e1bd9c11..8e297f74a5 100644 --- a/src/simd.jl +++ b/src/simd.jl @@ -5,15 +5,12 @@ Tell the reducible to run the inner reducing function using `@simd`. The reducible can support it using `@simd_if`. """ struct UseSIMD{ivdep} <: Transducer end -outtype(::UseSIMD, intype) = intype next(rf::R_{UseSIMD}, result, input) = next(inner(rf), result, input) # Make sure UseSIMD is the outer-most transducer when UseSIMD is used # via Cat. skipcomplete(rf::R_{UseSIMD}) = - Reduction(xform(rf)::UseSIMD, - skipcomplete(inner(rf)), - InType(rf)) + Reduction(xform(rf)::UseSIMD, skipcomplete(inner(rf))) isivdep(::UseSIMD{ivdep}) where ivdep = ivdep isivdep(rf::Reduction) = isivdep(xform(rf)) @@ -60,37 +57,37 @@ julia> using Transducers using Transducers: maybe_usesimd julia> maybe_usesimd(reducingfunction(Map(identity), right), false) -Reduction{▶ NOTYPE}( +Reduction( Map(identity), - BottomRF{▶ NOTYPE}( + BottomRF( Transducers.right)) julia> maybe_usesimd(reducingfunction(Map(identity), right), true) -Reduction{▶ NOTYPE}( +Reduction( Transducers.UseSIMD{false}(), - Reduction{▶ NOTYPE}( + Reduction( Map(identity), - BottomRF{▶ NOTYPE}( + BottomRF( Transducers.right))) julia> maybe_usesimd(reducingfunction(Cat(), right), true) -Reduction{▶ NOTYPE}( +Reduction( Cat(), - Reduction{▶ NOTYPE}( + Reduction( Transducers.UseSIMD{false}(), - BottomRF{▶ NOTYPE}( + BottomRF( Transducers.right))) julia> maybe_usesimd(reducingfunction(Map(sin) |> Cat() |> Map(cos), right), :ivdep) -Reduction{▶ NOTYPE}( +Reduction( Map(sin), - Reduction{▶ NOTYPE}( + Reduction( Cat(), - Reduction{▶ NOTYPE}( + Reduction( Transducers.UseSIMD{true}(), - Reduction{▶ NOTYPE}( + Reduction( Map(cos), - BottomRF{▶ NOTYPE}( + BottomRF( Transducers.right))))) julia> maybe_usesimd( @@ -100,19 +97,19 @@ julia> maybe_usesimd( ), true, ) -Reduction{▶ NOTYPE}( +Reduction( Map(sin), - Reduction{▶ NOTYPE}( + Reduction( Cat(), - Reduction{▶ NOTYPE}( + Reduction( Map(cos), - Reduction{▶ NOTYPE}( + Reduction( Cat(), - Reduction{▶ NOTYPE}( + Reduction( Transducers.UseSIMD{false}(), - Reduction{▶ NOTYPE}( + Reduction( Map(tan), - BottomRF{▶ NOTYPE}( + BottomRF( Transducers.right))))))) ``` """ diff --git a/test/__test_ir.jl b/test/__test_ir.jl index 4694e156a8..ce8c3b1e9a 100644 --- a/test/__test_ir.jl +++ b/test/__test_ir.jl @@ -49,7 +49,7 @@ end @testset "Cat SIMD" begin coll = [Float64[]] - rf = maybe_usesimd(Reduction(Cat(), +, eltype(coll)), true) + rf = maybe_usesimd(Reduction(Cat(), +), true) ir = llvm_ir(transduce, (rf, 0.0, coll)) @test_broken_if( VERSION < v"1.1-", @@ -84,9 +84,7 @@ unsafe_setter(ys) = # Manually "expand" `foreach` internal (so that I can observe # SIMD in the IR). - rf = Reduction(xf, - SideEffect(unsafe_setter(ys)), - eltype(xs)) + rf = Reduction(xf, SideEffect(unsafe_setter(ys))) rf = maybe_usesimd(rf, true) fill!(ys, 0) transduce(rf, nothing, xs) @@ -107,7 +105,7 @@ end okunion = r"UNION\{NOTHING, *TUPLE\{INT64, *INT64\}\}" coll = Float64[] - rf = Reduction(xf, +, eltype(coll)) + rf = Reduction(xf, +) val = start(rf, 0.0) ir = julia_ir(__foldl__, (rf, val, coll)) @test anyunions(replace(ir, okunion => "")) == [] diff --git a/test/preamble.jl b/test/preamble.jl index e8956b37c0..c4a8e86ff0 100644 --- a/test/preamble.jl +++ b/test/preamble.jl @@ -4,7 +4,7 @@ using SparseArrays: issparse, sparse using Statistics: mean using Transducers using Transducers: Transducer, simple_transduce, Reduced, isexpansive, - TeeZip, GetIndex, SetIndex, Inject, @~, outtype, infer_input_types, + TeeZip, GetIndex, SetIndex, Inject, @~, EmptyResultError, IdentityNotDefinedError, AbortIf, @next using InitialValues: Init using Logging: NullLogger, with_logger diff --git a/test/test_core.jl b/test/test_core.jl index d5a45a21f7..32ce77b3e9 100644 --- a/test/test_core.jl +++ b/test/test_core.jl @@ -1,6 +1,6 @@ module TestCore include("preamble.jl") -using Transducers: has, reform, needintype +using Transducers: has, reform @testset "has" begin @test has(Count(), Count) @@ -8,15 +8,6 @@ using Transducers: has, reform, needintype @test has(Count() |> Map(identity), Count) end -@testset "needintype" begin - @test !needintype(Map) - @test !needintype(TeeZip) - @test !needintype(Scan(+, 0)) - with_logger(NullLogger()) do - @test needintype(Scan(+, Initializer(T -> zero(T)))) - end -end - @testset "reform" begin f = Completing(Transducers.push!!) # bottom reducing function for eduction @testset for xf in [ @@ -30,49 +21,6 @@ end end end -@testset "Initializer" begin -with_logger(NullLogger()) do - @testset "mapfoldl" begin - @testset for xs in iterator_variants(1:3) - init(T::Type{<:Tuple}) = T[] - @test mapfoldl( - Zip(Map(identity), Map(string)), - push!, - xs, - init = Initializer(init) - ) == [(1, "1"), (2, "2"), (3, "3")] - end - end - @testset "Scan" begin - @testset for xs in iterator_variants(1:10) - @test_broken_if( - (xs isa Base.Generator), - collect(Scan(+, Initializer(T -> 5one(T))), xs) == - cumsum(vcat(5, collect(xs)))[2:end]) - end - end - @testset "ScanEmit" begin - @testset for xs in iterator_variants(1:10) - @test_broken_if( - (xs isa Base.Generator), - collect(ScanEmit((u, x) -> (u + x, u + x), - Initializer(T -> 5one(T))) |> Map(first), - xs) == - cumsum(vcat(5, collect(xs)))[2:end]) - end - end - @testset "Iterated" begin - @testset for xs in iterator_variants(1:10) - @test_broken_if( - (xs isa Base.Generator), - collect(Iterated(inc, Initializer(T -> 5one(T))) |> Map(first), - xs) == - (1:10) .+ (5 - 1)) - end - end -end -end - @testset "OnInit" begin @testset "mapfoldl" begin @testset for xs in iterator_variants(1:3) diff --git a/test/test_examples_transducers.jl b/test/test_examples_transducers.jl index 1768f13e26..cdfd9c52a6 100644 --- a/test/test_examples_transducers.jl +++ b/test/test_examples_transducers.jl @@ -2,8 +2,7 @@ module TestExamplesTransducers include("preamble.jl") include("../examples/transducers.jl") -@test eltype(addone_out1) === Any -@test eltype(addone_out2) === Int +@test eltype(addone_out1) === Int @test length(recall_out1) == 5 @test length(recall_out2) == 5 + RandomRecall().history diff --git a/test/test_examples_tutorial_missings.jl b/test/test_examples_tutorial_missings.jl index d80690f987..9c5cfb9696 100644 --- a/test/test_examples_tutorial_missings.jl +++ b/test/test_examples_tutorial_missings.jl @@ -2,12 +2,6 @@ module TestExamplesTutorialMissings include("../examples/tutorial_missings.jl") include("preamble.jl") -@testset "outtype of xf_sum_columns" begin - @test eltype(eduction(xf_sum_columns(Float64[]), Any[])) === - Vector{Float64} - @test eltype(eduction(xf_sum_columns(Float64[]), Any[])) <: Vector -end - slow_xf_fullextrema = Zip(Count(), NotA(Missing)) |> Zip(xf_scanext(>), xf_scanext(<)) diff --git a/test/test_library.jl b/test/test_library.jl index 00018b4a30..8947776c17 100644 --- a/test/test_library.jl +++ b/test/test_library.jl @@ -52,18 +52,6 @@ end @test collect(Scan(max), xs) == [0, 0, 3, 3, 3] @test collect(Scan(min), xs) == [0, -1, -1, -2, -2] end - - @testset "outtype" begin - @test outtype(Scan(+), Int) == Union{Int, typeof(Init(+))} - @test outtype(Scan(+, 0.0), Int) === Float64 - @test outtype(Scan(+, missing), Int) === Missing -with_logger(NullLogger()) do - @test outtype(Scan(+, Initializer(_ -> rand())), Int) === - Float64 - @test outtype(Scan(+, Initializer(_ -> rand(Int))), Int) === - Int -end - end end @testset "ScanEmit" begin @@ -78,21 +66,6 @@ end end end - @testset "outtype" begin - @test outtype(ScanEmit(tuple, 0), Int) === Int - @test outtype(ScanEmit(tuple, 0.0), Int) === - Union{Float64, Int64} - @test outtype( - ScanEmit(tuple, missing), Int) === Union{Missing, Int64} -with_logger(NullLogger()) do - @test outtype( - ScanEmit(tuple, Initializer(_ -> rand())), Int) === - Union{Float64, Int64} - @test outtype( - ScanEmit(tuple, Initializer(_ -> rand(Int))), Int) === Int -end - end - @testset "Do not call `complete` when reduced" begin xs = 1:8 xf = ScanEmit(CopyInit([]), identity) do u, x @@ -133,15 +106,6 @@ end collect(zip(1:2:5, 2:2:6)) end - ed = eduction(TeeZip(Filter(isodd) |> Map(x -> x + 1.0)) |> - Map(last) |> - Scan(+, - with_logger(NullLogger()) do - Initializer(T -> zero(T)) - end), - 1:5) - @test eltype(ed) === Float64 - xf = Map(inc) |> TeeZip(Filter(isodd)) |> Map(first) @testset for xs in iterator_variants(1:6) @test collect(xf, xs) == 3:2:7 @@ -491,24 +455,6 @@ end end @testset "OfType" begin - @testset "outtype" begin - @test outtype(OfType(Int), Int) === Int - @test outtype(OfType(Int), Union{Int,Missing}) === Int - @test outtype(OfType(Number), Union{Int,Missing}) === Int - @test outtype(OfType(Integer), Union{Int,Missing}) === Int - @test outtype( - OfType(Tuple{Int,Int}), - Tuple{Union{Int,Missing}, Int} - ) === Tuple{Int,Int} - @test outtype( - OfType(Tuple{Vararg{Int}}), - Tuple{Union{Int,Missing}, Int} - ) === Tuple{Int,Int} - @test outtype( - OfType(Tuple{Vararg{Number}}), - Tuple{Union{Int,Missing}, Int} - ) === Tuple{Int,Int} - end @testset "_next_oftype for non-tuple" begin @testset for xs in iterator_variants([0.0, 1.0, missing]) @test collect(OfType(Float64), xs) == [0.0, 1.0] diff --git a/test/test_processes.jl b/test/test_processes.jl index 754a945c1e..5d8db4c727 100644 --- a/test/test_processes.jl +++ b/test/test_processes.jl @@ -30,7 +30,6 @@ include("preamble.jl") @test foldl(+, xf, iter, init=32.) === 32. ed = eduction(xf, iter) - ed = infer_input_types(ed) @test_throws EmptyResultError foldl(+, ed) @test foldl(+, ed, init=32.) === 32. @@ -98,8 +97,6 @@ end end ed = eduction(xf, 1:5) - ed = infer_input_types(ed) - @test eltype(ed) === Int @testset "inference" begin xf = Zip(Count(), Map(identity), Map(x -> 2x)) |> MapSplat(*) @@ -115,51 +112,22 @@ end push!(result, x) end === reduced() end - - @testset "eltype" begin - for (xf, desiredtype) in [ - (Map(identity), Int), - (Filter(isodd), Int), - (Map(x -> 1/x), float(Int)), - ] - ed = eduction(xf, 1:10) - ed = infer_input_types(ed) - @test Base.IteratorEltype(typeof(ed)) == - Base.IteratorEltype(ed) == - Base.HasEltype() - @test eltype(typeof(ed)) == eltype(ed) == desiredtype - end - end end @testset "setinput" begin xf = Zip(Count(), Map(identity), Map(x -> 2x)) |> MapSplat(*) ed = eduction(xf, 1:10) - ed = infer_input_types(ed) @testset for xs in iterator_variants(1:10) @test setinput(ed, xs).coll isa typeof(xs) @test collect(setinput(ed, xs)) == collect(ed) end - @testset "changing eltype" begin - edchar = eduction(Zip(Map(identity), Count()), "abc") - edchar = infer_input_types(edchar) - @test eltype(edchar) === Tuple{Char, Int} - edf64 = setinput(edchar, Float64[]) - edf64 = infer_input_types(edf64) - @test eltype(edf64) === Tuple{Float64, Int} - end - @testset "inference" begin @test (@inferred setinput(ed, [0])).coll isa Vector{Int} @test (@inferred setinput(ed, view([0], 1:1))).coll isa SubArray{Int} - - err = @test_error @inferred setinput(ed, Float64[]) - msg = sprint(showerror, err) - @test occursin("return type", msg) - @test occursin("does not match inferred return type", msg) + @test_broken (@inferred setinput(ed, Float64[])).coll isa Vector{Float64} end end @@ -280,18 +248,6 @@ end @test occursin("EmptyResultError:", sprint(showerror, err)) end - @testset for ex in @expressions begin - Channel(Map(error), Int[]) - Channel(eduction(Map(error), Int[])) - Channel(Map(error), eduction(Map(identity), Int[])) - Channel(Map(identity), eduction(Map(error), Int[])) - end - - err = @eval @test_error $ex - @test occursin("inferred", sprint(showerror, err)) - @test occursin("`Union{}`", sprint(showerror, err)) - end - @testset for ex in @expressions begin mapfoldl(Map(error), +, ["hello"]; init=0) foldl(+, Map(error), ["hello"]; init=0) diff --git a/test/test_simd.jl b/test/test_simd.jl index 5ab30e23d5..61bfe85baa 100644 --- a/test/test_simd.jl +++ b/test/test_simd.jl @@ -17,7 +17,7 @@ end @test simd_if_demo(UseSIMD{true}(), zero(xs), xs) == 2xs end -asrf(xf) = Reduction(xf, right, Int) +asrf(xf) = Reduction(xf, right) @testset "usesimd" begin xfsimd = UseSIMD{false}()