Skip to content

Commit def8bf3

Browse files
prepare for v0.5 release (#91)
* remove AnonymousWalk * add inferred test * revisit leaves
1 parent 2945731 commit def8bf3

File tree

14 files changed

+59
-80
lines changed

14 files changed

+59
-80
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
fail-fast: false
1818
matrix:
1919
version:
20-
- '1.6' # Replace this with the minimum Julia version that your package supports.
20+
- '1.10' # Replace this with the minimum Julia version that your package supports.
2121
- '1' # automatically expands to the latest stable 1.x release of Julia
2222
- 'nightly'
2323
os:

Project.toml

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
name = "Functors"
22
uuid = "d9f16b24-f501-4c13-a1f2-28368ffc5196"
33
authors = ["Mike J Innes <[email protected]>"]
4-
version = "0.4.12"
4+
version = "0.5.0"
55

66
[deps]
77
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
88
ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
99
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
10+
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1011

1112
[compat]
1213
Compat = "4.16"
1314
ConstructionBase = "1.4"
1415
Measurements = "2"
1516
OrderedCollections = "1.6"
16-
julia = "1.6"
17+
Random = "1"
18+
julia = "1.10"
1719

1820
[extras]
1921
Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7"

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ Bar(Foo(1.0, [1.0, 2.0, 3.0]))
5353
> With v0.5 instead, this is no longer necessary: by default any type is recursively traversed up to the leaves
5454
> and `ConstructionBase.constructorof` is used to reconstruct it.
5555
> In order to opt-out of this behaviour and make a type non traversable you can use `@leaf Foo`.
56+
>
57+
> Most users should be unaffected by the change and could remove `@functor` from their custom types.
5658
5759
## Further Details
5860

docs/src/api.md

-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ Functors.StructuralWalk
4040
Functors.ExcludeWalk
4141
Functors.CachedWalk
4242
Functors.CollectWalk
43-
Functors.AnonymousWalk
4443
Functors.IterateWalk
4544
```
4645

docs/src/index.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ By default all composite types in are functors and can be traversed, unless mark
6464
The following types instead are explicitly marked as leaves in Functors.jl:
6565
- `Number`.
6666
- `AbstractArray{<:Number}`, except for the wrappers `Transpose`, `Adjoint`, and `PermutedDimsArray`.
67-
- `AbstractString`.
67+
- `AbstractRNG`.
68+
- `AbstractString`, `AbstractChar`, `AbstractPattern`, `AbstractMatch`.
6869

6970
This is because in typical application the internals of these are abstracted away and it is not desirable to traverse them.
7071

src/Functors.jl

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module Functors
22
using Compat: @compat
33
using ConstructionBase: constructorof
44
using LinearAlgebra
5+
using Random: AbstractRNG
56

67
export @leaf, @functor, @flexiblefunctor,
78
fmap, fmapstructure, fcollect, execute, fleaves,

src/base.jl

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44

55
@leaf Number
66
@leaf AbstractArray{<:Number}
7-
@leaf AbstractString
7+
@leaf AbstractString
8+
@leaf AbstractChar
9+
@leaf AbstractMatch
10+
@leaf AbstractPattern
11+
@leaf AbstractRNG
812

913
###
1014
### Fast Paths for common types

src/cache.jl

+18-41
Original file line numberDiff line numberDiff line change
@@ -11,48 +11,25 @@ Base.iterate(cache::WalkCache, state...) = iterate(cache.cache, state...)
1111
Base.setindex!(cache::WalkCache, value, key) = setindex!(cache.cache, value, key)
1212
Base.getindex(cache::WalkCache, x) = cache.cache[x]
1313

14-
@static if VERSION >= v"1.10.0-DEV.609"
15-
function __cacheget_generator__(world, source, self, cache, x, args #= for `return_type` only =#)
16-
# :(return cache.cache[x]::(return_type(cache.walk, typeof(args))))
17-
walk = cache.parameters[3]
18-
RT = Core.Compiler.return_type(Tuple{walk, args...}, world)
19-
body = Expr(:call, GlobalRef(Base, :getindex), Expr(:., :cache, QuoteNode(:cache)), :x)
20-
if RT != Any
21-
body = Expr(:(::), body, RT)
22-
end
23-
expr = Expr(:lambda, [Symbol("#self#"), :cache, :x, :args],
24-
Expr(Symbol("scope-block"), Expr(:block, Expr(:meta, :inline), Expr(:return, body))))
25-
ci = ccall(:jl_expand, Any, (Any, Any), expr, @__MODULE__)
26-
ci.inlineable = true
27-
return ci
28-
end
29-
@eval function cacheget(cache::WalkCache, x, args...)
30-
$(Expr(:meta, :generated, __cacheget_generator__))
31-
$(Expr(:meta, :generated_only))
32-
end
33-
else
34-
@generated function cacheget(cache::WalkCache, x, args...)
35-
walk = cache.parameters[3]
36-
world = typemax(UInt)
37-
@static if VERSION >= v"1.8"
38-
RT = Core.Compiler.return_type(Tuple{walk, args...}, world)
39-
else
40-
if isdefined(walk, :instance)
41-
RT = Core.Compiler.return_type(walk.instance, Tuple{args...}, world)
42-
else
43-
RT = Any
44-
end
45-
end
46-
body = Expr(:call, GlobalRef(Base, :getindex), Expr(:., :cache, QuoteNode(:cache)), :x)
47-
if RT != Any
48-
body = Expr(:(::), body, RT)
49-
end
50-
expr = Expr(:lambda, [Symbol("#self#"), :cache, :x, :args],
51-
Expr(Symbol("scope-block"), Expr(:block, Expr(:meta, :inline), Expr(:return, body))))
52-
ci = ccall(:jl_expand, Any, (Any, Any), expr, @__MODULE__)
53-
ci.inlineable = true
54-
return ci
14+
function __cacheget_generator__(world, source, self, cache, x, args #= for `return_type` only =#)
15+
# :(return cache.cache[x]::(return_type(cache.walk, typeof(args))))
16+
walk = cache.parameters[3]
17+
RT = Core.Compiler.return_type(Tuple{walk, args...}, world)
18+
body = Expr(:call, GlobalRef(Base, :getindex), Expr(:., :cache, QuoteNode(:cache)), :x)
19+
if RT != Any
20+
body = Expr(:(::), body, RT)
5521
end
22+
expr = Expr(:lambda, [Symbol("#self#"), :cache, :x, :args],
23+
Expr(Symbol("scope-block"), Expr(:block, Expr(:meta, :inline), Expr(:return, body))))
24+
ci = ccall(:jl_expand, Any, (Any, Any), expr, @__MODULE__)
25+
ci.inlineable = true
26+
return ci
5627
end
28+
29+
@eval function cacheget(cache::WalkCache, x, args...)
30+
$(Expr(:meta, :generated, __cacheget_generator__))
31+
$(Expr(:meta, :generated_only))
32+
end
33+
5734
# fallback behavior that only lookup for `x`
5835
@inline cacheget(cache::AbstractDict, x, args...) = cache[x]

src/functor.jl

-10
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,3 @@ end
8585
macro flexiblefunctor(args...)
8686
flexiblefunctorm(args...)
8787
end
88-
89-
###
90-
### Compat
91-
###
92-
93-
if VERSION < v"1.7"
94-
# Function in 1.7 checks t.name.flags & 0x2 == 0x2,
95-
# but for 1.6 this seems to work instead:
96-
ismutabletype(@nospecialize t) = t.mutable
97-
end

src/maps.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ function fmap(f, x, ys...; exclude = isleaf,
44
walk = DefaultWalk(),
55
cache = IdDict(),
66
prune = NoKeyword())
7-
_walk = ExcludeWalk(AnonymousWalk(walk), f, exclude)
7+
_walk = ExcludeWalk(walk, f, exclude)
88
if !isnothing(cache)
99
_walk = CachedWalk(_walk, prune, WalkCache(_walk, cache))
1010
end

src/walks.jl

-20
Original file line numberDiff line numberDiff line change
@@ -55,26 +55,6 @@ function execute(walk::AbstractWalk, x, ys...)
5555
walk(recurse, x, ys...)
5656
end
5757

58-
"""
59-
AnonymousWalk(walk_fn)
60-
61-
Wrap a `walk_fn` so that `AnonymousWalk(walk_fn) isa AbstractWalk`.
62-
This type only exists for backwards compatability and should not be directly used.
63-
Attempting to wrap an existing `AbstractWalk` is a no-op (i.e. it is not wrapped).
64-
"""
65-
struct AnonymousWalk{F} <: AbstractWalk
66-
walk::F
67-
68-
function AnonymousWalk(walk::F) where F
69-
Base.depwarn("Wrapping a custom walk function as an `AnonymousWalk`. Future versions will only support custom walks that explicitly subtype `AbstractWalk`.", :AnonymousWalk)
70-
return new{F}(walk)
71-
end
72-
end
73-
# do not wrap an AbstractWalk
74-
AnonymousWalk(walk::AbstractWalk) = walk
75-
76-
(walk::AnonymousWalk)(recurse, x, ys...) = walk.walk(recurse, x, ys...)
77-
7858
"""
7959
DefaultWalk()
8060

test/base.jl

+18-2
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,13 @@ end
5757
@test fmap(x -> x + 10, bf) == Base.Broadcast.BroadcastFunction(Bar(13.3))
5858
end
5959

60-
VERSION >= v"1.7" && @testset "Returns" begin
60+
@testset "Returns" begin
6161
ret = Returns([0, pi, 2pi])
6262
@test Functors.functor(ret)[1] == (value = [0, pi, 2pi],)
6363
@test Functors.functor(ret)[2]((value = 1:3,)) === Returns(1:3)
6464
end
6565

66-
VERSION >= v"1.9" && @testset "Splat" begin
66+
@testset "Splat" begin
6767
ret = Base.splat(Returns([0, pi, 2pi]))
6868
@test Functors.functor(ret)[1].f.value == [0, pi, 2pi]
6969
@test Functors.functor(ret)[2]((f = sin,)) === Base.splat(sin)
@@ -187,6 +187,22 @@ end
187187
s = DummyString("hello")
188188
@test Functors.isleaf(s)
189189
end
190+
@testset "AbstractPattern is leaf" begin
191+
struct DummyPattern <: AbstractPattern
192+
pat::Regex
193+
end
194+
p = DummyPattern(r"\d+")
195+
@test Functors.isleaf(p)
196+
@test Functors.isleaf(r"\d+")
197+
end
198+
@testset "AbstractChar is leaf" begin
199+
struct DummyChar <: AbstractChar
200+
ch::Char
201+
end
202+
c = DummyChar('a')
203+
@test Functors.isleaf(c)
204+
@test Functors.isleaf('a')
205+
end
190206

191207
@testset "AbstractDict is functor" begin
192208
od = OrderedDict(1 => 1, 2 => 2)

test/cache.jl

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@testset "inferred" begin
2+
r = [1,2]
3+
x = (a = r, b = 3, c =(4, (d=5, e=r)))
4+
y = @inferred(fmap(float, x))
5+
@test y.a === y.c[2].e
6+
end

test/runtests.jl

+1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ using Measurements: ±
1010
include("base.jl")
1111
include("keypath.jl")
1212
include("flexiblefunctors.jl")
13+
include("cache.jl")
1314
end

0 commit comments

Comments
 (0)