From f940322a22a3029775fb40a69d8af0821d741466 Mon Sep 17 00:00:00 2001 From: Jan Weidner Date: Sat, 28 Jul 2018 15:15:51 +0200 Subject: [PATCH 1/6] Remove mutation support --- .travis.yml | 2 +- REQUIRE | 2 +- src/Setfield.jl | 14 ----- src/lens.jl | 40 ++++--------- src/sugar.jl | 48 ++-------------- test/test_core.jl | 122 ++++++++++++++++++++-------------------- test/test_quicktypes.jl | 5 +- 7 files changed, 80 insertions(+), 153 deletions(-) diff --git a/.travis.yml b/.travis.yml index d40604c..d971c1a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ os: - linux - osx julia: - - 0.6 + - 0.7 - nightly notifications: email: false diff --git a/REQUIRE b/REQUIRE index a612f60..362aa51 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,2 +1,2 @@ -julia 0.6 +julia 0.7- MacroTools diff --git a/src/Setfield.jl b/src/Setfield.jl index 62bc9bb..c37a4de 100644 --- a/src/Setfield.jl +++ b/src/Setfield.jl @@ -1,20 +1,6 @@ __precompile__(true) module Setfield -if isdefined(Base, :getproperty) - using Base: getproperty -else - const getproperty = getfield - # the following breaks type stability: - # @inline getproperty(obj, name) = getfield(obj, name) -end -if isdefined(Base, :setproperty!) - using Base: setproperty! -else - const setproperty! = setfield! - # @inline setproperty!(obj, name, val) = setfield!(obj, name, val) -end - include("lens.jl") include("sugar.jl") include("macrotools.jl") diff --git a/src/lens.jl b/src/lens.jl index e48b2ff..eb15367 100644 --- a/src/lens.jl +++ b/src/lens.jl @@ -2,11 +2,8 @@ export Lens, set, get, modify export @lens export set, get, modify -import Base: get, setindex - -abstract type MutationPolicy end -struct EncourageMutation <: MutationPolicy end -struct ForbidMutation <: MutationPolicy end +import Base: get +using Base: setindex, getproperty """ Lens @@ -74,17 +71,15 @@ Replace a deeply nested part of `obj` by `val`. See also [`Lens`](@ref). """ function set end -set(l::Lens, obj, val) = set(l,obj,val,ForbidMutation()) -modify(f,l::Lens, obj) = modify(f, l,obj,ForbidMutation()) -@inline function modify(f, l::Lens, obj, m::MutationPolicy) +@inline function modify(f, l::Lens, obj) old_val = get(l, obj) new_val = f(old_val) - set(l, obj, new_val, m) + set(l, obj, new_val) end struct IdentityLens <: Lens end get(::IdentityLens, obj) = obj -set(::IdentityLens, obj, val,::MutationPolicy) = val +set(::IdentityLens, obj, val) = val struct PropertyLens{fieldname} <: Lens end @@ -99,14 +94,8 @@ function assert_hasfield(T, field) end end -@generated function set(l::PropertyLens{field}, obj, val, m::MutationPolicy) where {field} - T = obj - M = m - if T.mutable && (M == EncourageMutation) - :(setproperty!(obj, field, val); obj) - else - :(setproperty(obj, Val{field}(), val)) - end +@generated function set(l::PropertyLens{field}, obj, val) where {field} + :(setproperty(obj, Val{field}(), val)) end @generated constructor_of(::Type{T}) where T = @@ -146,10 +135,10 @@ function get(l::ComposedLens, obj) get(l.lens1, inner_obj) end -function set(l::ComposedLens, obj, val, m::MutationPolicy) +function set(l::ComposedLens, obj, val) inner_obj = get(l.lens2, obj) - inner_val = set(l.lens1, inner_obj, val, m) - set(l.lens2, obj, inner_val, m) + inner_val = set(l.lens1, inner_obj, val) + set(l.lens2, obj, inner_val) end struct IndexLens{I <: Tuple} <: Lens @@ -157,11 +146,4 @@ struct IndexLens{I <: Tuple} <: Lens end get(l::IndexLens, obj) = getindex(obj, l.indices...) -set(l::IndexLens, obj, val, ::ForbidMutation) = Base.setindex(obj, val, l.indices...) -function set(l::IndexLens, obj, val, ::EncourageMutation) - if applicable(setindex!, obj, val, l.indices) - setindex!(obj, val, l.indices...) - else - set(l, obj, val, ForbidMutation()) - end -end +set(l::IndexLens, obj, val) = setindex(obj, val, l.indices...) diff --git a/src/sugar.jl b/src/sugar.jl index 716cccc..b4ea674 100644 --- a/src/sugar.jl +++ b/src/sugar.jl @@ -1,4 +1,4 @@ -export @set, @set!, @lens +export @set, @lens using MacroTools """ @@ -27,48 +27,11 @@ T(T(2, 2), 2) julia> @set t.a.b = 3 T(T(2, 3), 2) ``` -See also [`@set!`](@ref). """ macro set(ex) atset_impl(ex) end -""" - @set! assignment - -Update deeply nested parts of an object. In contrast to `@set`, `@set!` -overwrites the variable binding and mutates the original object -if possible. -```jldoctest -julia> using Setfield - -julia> struct T;a;b end - -julia> t = T(1,2) -T(1, 2) - -julia> @set! t.a = 5 -T(5, 2) - -julia> t -T(5, 2) - -julia> @set t.a = 10 -T(10, 2) - -julia> t -T(5, 2) -``` -### Warning -Since `@set!` rebinds the variable, it will cause type instabilites -for updates that change the type. - -See also [`@set`](@ref). -""" -macro set!(ex) - atset_impl(ex, :(EncourageMutation()), true) -end - function parse_obj_lenses(ex) if @capture(ex, front_[indices__]) obj, frontlens = parse_obj_lenses(front) @@ -103,7 +66,7 @@ struct _UpdateOp{OP,V} end (u::_UpdateOp)(x) = u.op(x, u.val) -function atset_impl(ex::Expr, mut=:(ForbidMutation()), rebind=false) +function atset_impl(ex::Expr) @assert ex.head isa Symbol @assert length(ex.args) == 2 ref, val = ex.args @@ -112,18 +75,15 @@ function atset_impl(ex::Expr, mut=:(ForbidMutation()), rebind=false) ret = if ex.head == :(=) quote lens = $lens - set(lens, $obj, $val, $mut) + set(lens, $obj, $val) end else op = UPDATE_OPERATOR_TABLE[ex.head] f = :(_UpdateOp($op,$val)) quote - modify($f, $lens, $obj, $mut) + modify($f, $lens, $obj) end end - if rebind - ret = :($obj = $ret) - end ret end diff --git a/test/test_core.jl b/test/test_core.jl index e4a40c2..1ffd309 100644 --- a/test/test_core.jl +++ b/test/test_core.jl @@ -178,67 +178,67 @@ end @test compose(la, id) === la end -@testset "Mutability" begin - - @testset "array" begin - v_init = [1,2,3] - v = v_init - @set! v[1] = 2 - @test v_init[1] == 2 - @test v === v_init - - # Julia 0.7 with --depwarn=error: - is_deperror07 = VERSION >= v"0.7-" && Base.JLOptions().depwarn == 2 - - v = randn(3) - # @set! v[:] .= 0 # dot-call not supported - @test_broken v == [0,0,0.] - if is_deperror07 - v[:] .= 1 - else - v = @test_deprecated07 (@set! v[:] = 1; v) - end - @test v == [1,1,1.] - if is_deperror07 - v[2:3] .= 4 - else - v = @test_deprecated07 (@set! v[2:3] = 4; v) - end - @test v == [1,4,4] - # @set! v[1:2] .= 5 # dot-call not supported - @test_broken v == [5,5,4] - end - - @testset "@set vs @set!" begin - m1 = M(1,2) - m2 = @set m1.a = 10 - @test !(m2 === m1) - @test m1.a === 1 - @test m2.a === 10 - m3 = @set! m1.a = 100 - @test m3 === m1 - @test m1.a === 100 - end - - @testset "composition only mutates the innermost" begin - m_init = M(1,2) - m = m_init - @set! m.a = 10 - @test m_init.a == 10 - @test m === m_init - m_inner_init = M(1,2) - m_init = M(m_inner_init, 2) - m = m_init - @set! m.a.a = 2 - @test m.a.a == 2 - @test m === m_init - @test m.a === m_inner_init - end - - obj = (1,) - @set! obj[1] = 2 - @test obj === (2,) -end +# @testset "Mutability" begin +# +# @testset "array" begin +# v_init = [1,2,3] +# v = v_init +# @set! v[1] = 2 +# @test v_init[1] == 2 +# @test v === v_init +# +# # Julia 0.7 with --depwarn=error: +# is_deperror07 = VERSION >= v"0.7-" && Base.JLOptions().depwarn == 2 +# +# v = randn(3) +# # @set! v[:] .= 0 # dot-call not supported +# @test_broken v == [0,0,0.] +# if is_deperror07 +# v[:] .= 1 +# else +# v = @test_deprecated07 (@set! v[:] = 1; v) +# end +# @test v == [1,1,1.] +# if is_deperror07 +# v[2:3] .= 4 +# else +# v = @test_deprecated07 (@set! v[2:3] = 4; v) +# end +# @test v == [1,4,4] +# # @set! v[1:2] .= 5 # dot-call not supported +# @test_broken v == [5,5,4] +# end +# +# @testset "@set vs @set!" begin +# m1 = M(1,2) +# m2 = @set m1.a = 10 +# @test !(m2 === m1) +# @test m1.a === 1 +# @test m2.a === 10 +# m3 = @set! m1.a = 100 +# @test m3 === m1 +# @test m1.a === 100 +# end +# +# @testset "composition only mutates the innermost" begin +# m_init = M(1,2) +# m = m_init +# @set! m.a = 10 +# @test m_init.a == 10 +# @test m === m_init +# m_inner_init = M(1,2) +# m_init = M(m_inner_init, 2) +# m = m_init +# @set! m.a.a = 2 +# @test m.a.a == 2 +# @test m === m_init +# @test m.a === m_inner_init +# end +# +# obj = (1,) +# @set! obj[1] = 2 +# @test obj === (2,) +# end struct A{X, Y} x::X diff --git a/test/test_quicktypes.jl b/test/test_quicktypes.jl index cdae5a8..d2128f6 100644 --- a/test/test_quicktypes.jl +++ b/test/test_quicktypes.jl @@ -69,7 +69,7 @@ end @testset "Pack" begin x = Pack([Cat(:Tama, 1), Cat(:Pochi, 2)]) - @set! x.animals[2].nlegs = 5 + x = @set x.animals[2].nlegs = 5 @test x.animals == [Cat(:Tama, 1), Cat(:Pochi, 2, 5)] end @@ -117,8 +117,7 @@ end @testset "Group" begin x = Group([0, 1]) - - x = @set! x.members[2] = 111 + x = @set x.members[2] = 111 @test x.members == [0, 111] end From d8a873000f8459b73d121b6b70f6cf6f6215c80b Mon Sep 17 00:00:00 2001 From: Jan Weidner Date: Mon, 30 Jul 2018 12:00:21 +0200 Subject: [PATCH 2/6] add MultiProperyLens --- src/lens.jl | 33 +++++++++++++++ test/runtests.jl | 16 +------- test/test_core.jl | 102 ++++++++++++++++------------------------------ 3 files changed, 69 insertions(+), 82 deletions(-) diff --git a/src/lens.jl b/src/lens.jl index eb15367..574e066 100644 --- a/src/lens.jl +++ b/src/lens.jl @@ -147,3 +147,36 @@ end get(l::IndexLens, obj) = getindex(obj, l.indices...) set(l::IndexLens, obj, val) = setindex(obj, val, l.indices...) + + +const NNamedTupleLens{N,s} = NamedTuple{s, T} where {T <: NTuple{N, Lens}} +struct MultiPropertyLens{L <: NNamedTupleLens} <: Lens + lenses::L +end + +_keys(::Type{MultiPropertyLens{NamedTuple{s,T}}}) where {s,T} = s +@generated function get(l::MultiPropertyLens, obj) + get_arg(fieldname) = :($fieldname = get(l.lenses.$fieldname, obj.$fieldname)) + args = map(get_arg, _keys(l)) + Expr(:tuple, args...) +end + +@generated function set(l::MultiPropertyLens, obj, val) + T = obj + args = map(fieldnames(T)) do fn + if fn in _keys(l) + quote + obj_inner = obj.$fn + lens_inner = l.lenses.$fn + val_inner = val.$fn + set(lens_inner, obj_inner, val_inner) + end + else + :(obj.$fn) + end + end + Expr(:block, + Expr(:meta, :inline), + Expr(:call, :(constructor_of($T)), args...) + ) +end diff --git a/test/runtests.jl b/test/runtests.jl index ba6813a..7c076d8 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,20 +1,8 @@ module TestSetfield -@static if VERSION < v"0.7-" - using Base.Test -else - using Test -end - -macro test_deprecated07(ex) - if VERSION < v"0.7-" - return esc(ex) - else - return esc(:(Test.@test_deprecated $ex)) - end -end - +using Test using Setfield +const P = Setfield @testset "core" begin include("test_core.jl") diff --git a/test/test_core.jl b/test/test_core.jl index 1ffd309..7ef06ee 100644 --- a/test/test_core.jl +++ b/test/test_core.jl @@ -114,6 +114,12 @@ end test_getset_laws(lens, obj, val1, val2) test_modify_law(f, lens, obj) end + for (lens, val1, val2) in [ + ((P.MultiPropertyLens((a=@lens(_),))), (a=10,), (a=20,)) + ] + test_getset_laws(lens, obj, val1, val2) + test_modify_law(identity, lens, obj) + end end @testset "type stability" begin @@ -134,6 +140,7 @@ end ((@lens _.b.a.b[i+1] ), 4 ), ((@lens _ ), obj), ((@lens _ ), :xy), + (P.MultiPropertyLens((a=(@lens _), b=(@lens _))), (a=1, b=2)), ] @inferred get(lens, obj) @inferred set(lens, obj, val) @@ -178,77 +185,36 @@ end @test compose(la, id) === la end -# @testset "Mutability" begin -# -# @testset "array" begin -# v_init = [1,2,3] -# v = v_init -# @set! v[1] = 2 -# @test v_init[1] == 2 -# @test v === v_init -# -# # Julia 0.7 with --depwarn=error: -# is_deperror07 = VERSION >= v"0.7-" && Base.JLOptions().depwarn == 2 -# -# v = randn(3) -# # @set! v[:] .= 0 # dot-call not supported -# @test_broken v == [0,0,0.] -# if is_deperror07 -# v[:] .= 1 -# else -# v = @test_deprecated07 (@set! v[:] = 1; v) -# end -# @test v == [1,1,1.] -# if is_deperror07 -# v[2:3] .= 4 -# else -# v = @test_deprecated07 (@set! v[2:3] = 4; v) -# end -# @test v == [1,4,4] -# # @set! v[1:2] .= 5 # dot-call not supported -# @test_broken v == [5,5,4] -# end -# -# @testset "@set vs @set!" begin -# m1 = M(1,2) -# m2 = @set m1.a = 10 -# @test !(m2 === m1) -# @test m1.a === 1 -# @test m2.a === 10 -# m3 = @set! m1.a = 100 -# @test m3 === m1 -# @test m1.a === 100 -# end -# -# @testset "composition only mutates the innermost" begin -# m_init = M(1,2) -# m = m_init -# @set! m.a = 10 -# @test m_init.a == 10 -# @test m === m_init -# m_inner_init = M(1,2) -# m_init = M(m_inner_init, 2) -# m = m_init -# @set! m.a.a = 2 -# @test m.a.a == 2 -# @test m === m_init -# @test m.a === m_inner_init -# end -# -# obj = (1,) -# @set! obj[1] = 2 -# @test obj === (2,) -# end - -struct A{X, Y} - x::X - y::Y +struct ABC{A,B,C} + a::A + b::B + c::C +end + +@testset "MultiPropertyLens" begin + x = ABC(1,2,3) + l = P.MultiPropertyLens((a=@lens(_), c=@lens(_))) + @test get(l, x) == (a=1, c=3) + @inferred get(l, x) + + @test set(l,x, (a=10, c=30)) == ABC{Int64,Int64,Int64}(10, 2, 30) + @inferred set(l,x, (a=10, c=30)) + + y = 5 + obj = TT(x, y) + l_nested = P.MultiPropertyLens((a=l,b=@lens(_))) + @test get(l_nested, obj) == (a = (a = 1, c = 3), b = 5) + @inferred get(l_nested, obj) + + @test set(l_nested, obj, (a=(a=10.0, c="twenty"), b=:thirty)) == + TT(ABC(10.0, 2, "twenty"), :thirty) + @inferred set(l_nested, obj, (a=(a=10.0, c="twenty"), b=:thirty)) end @testset "type change during @set (default constructor_of)" begin - obj = A(2,3) - obj2 = @set obj.y = :three - @test obj2 === A(2, :three) + obj = TT(2,3) + obj2 = @set obj.b = :three + @test obj2 === TT(2, :three) end # https://github.com/tkf/Reconstructables.jl#how-to-use-type-parameters From 3c54082b942808bf6f415e9d0e6b7a71b738e3f9 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Wed, 15 Aug 2018 13:06:56 -0700 Subject: [PATCH 3/6] Use Tuple instead of Vector in test_quicktypes.jl (#39) * Test against Julia 1.0 * Use the default test script * Fix after_success for Julia 1.0 * Enable tests with QuickTypes * Use Tuple instead of Vector in test_quicktypes.jl --- .travis.yml | 12 +++++------- test/runtests.jl | 2 -- test/test_quicktypes.jl | 10 +++++----- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index d971c1a..162d36c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ os: - osx julia: - 0.7 + - 1.0 - nightly notifications: email: false @@ -25,13 +26,10 @@ git: #before_script: # homebrew for mac # - if [ $TRAVIS_OS_NAME = osx ]; then brew install gcc; fi -# uncomment the following lines to override the default test script -script: - - julia -e 'Pkg.clone(pwd()); Pkg.build("Setfield"); VERSION < v"0.7-" && Pkg.add("StaticArrays"); Pkg.test("Setfield"; coverage=true)' after_success: # push coverage results to Coveralls - - julia -e 'cd(Pkg.dir("Setfield")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())' + - julia -e 'using Pkg; cd(Pkg.dir("Setfield")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())' # push coverage results to Codecov - - julia -e 'cd(Pkg.dir("Setfield")); Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())' - - julia -e 'Pkg.add("Documenter")' - - julia -e 'cd(Pkg.dir("Setfield")); include(joinpath("docs", "make.jl"))' + - julia -e 'using Pkg; cd(Pkg.dir("Setfield")); Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())' + - julia -e 'using Pkg; Pkg.add("Documenter")' + - julia -e 'using Pkg; cd(Pkg.dir("Setfield")); include(joinpath("docs", "make.jl"))' diff --git a/test/runtests.jl b/test/runtests.jl index 7c076d8..5e65235 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -23,10 +23,8 @@ end include("test_kwonly.jl") end -@static if VERSION < v"0.7-" @testset "QuickTypes.jl" begin include("test_quicktypes.jl") end -end end # module diff --git a/test/test_quicktypes.jl b/test/test_quicktypes.jl index d2128f6..ed5a1ca 100644 --- a/test/test_quicktypes.jl +++ b/test/test_quicktypes.jl @@ -64,13 +64,13 @@ end end -@qstruct Pack{T}(animals::Vector{T}) +@qstruct Pack{T, N}(animals::NTuple{N, T}) @testset "Pack" begin - x = Pack([Cat(:Tama, 1), Cat(:Pochi, 2)]) + x = Pack((Cat(:Tama, 1), Cat(:Pochi, 2))) x = @set x.animals[2].nlegs = 5 - @test x.animals == [Cat(:Tama, 1), Cat(:Pochi, 2, 5)] + @test x.animals == (Cat(:Tama, 1), Cat(:Pochi, 2, 5)) end @@ -116,9 +116,9 @@ end @qstruct Group{x}(members::x; _concise_show=true) @testset "Group" begin - x = Group([0, 1]) + x = Group((0, 1)) x = @set x.members[2] = 111 - @test x.members == [0, 111] + @test x.members == (0, 111) end @settable @qstruct_fp Plane1(nwheels, weight::Number; brand=:zoomba) From 5178ba92397e889b1a94ad2919d273fb9e597fcd Mon Sep 17 00:00:00 2001 From: Jan Weidner Date: Wed, 15 Aug 2018 22:23:55 +0200 Subject: [PATCH 4/6] Use MacroTools.spiltstructdef --- REQUIRE | 2 +- src/Setfield.jl | 3 +- src/macrotools.jl | 69 ----------------------------------------- src/settable.jl | 11 +++---- test/runtests.jl | 3 -- test/test_macrotools.jl | 46 --------------------------- test/test_quicktypes.jl | 7 +---- 7 files changed, 9 insertions(+), 132 deletions(-) delete mode 100644 src/macrotools.jl delete mode 100644 test/test_macrotools.jl diff --git a/REQUIRE b/REQUIRE index 362aa51..157645b 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,2 +1,2 @@ julia 0.7- -MacroTools +MacroTools 0.4.4 diff --git a/src/Setfield.jl b/src/Setfield.jl index c37a4de..cbab666 100644 --- a/src/Setfield.jl +++ b/src/Setfield.jl @@ -1,8 +1,9 @@ __precompile__(true) module Setfield +using MacroTools +using MacroTools: isstructdef, splitstructdef include("lens.jl") include("sugar.jl") -include("macrotools.jl") include("settable.jl") end diff --git a/src/macrotools.jl b/src/macrotools.jl deleted file mode 100644 index b2e4df0..0000000 --- a/src/macrotools.jl +++ /dev/null @@ -1,69 +0,0 @@ -using MacroTools - -const STRUCTSYMBOL = VERSION < v"0.7-" ? :type : :struct -isstructdef(ex) = Meta.isexpr(ex, STRUCTSYMBOL) - -function splittypedef(ex) - ex = MacroTools.striplines(ex) - ex = MacroTools.flatten(ex) - d = Dict{Symbol, Any}() - if @capture(ex, struct header_ body__ end) - d[:mutable] = false - elseif @capture(ex, mutable struct header_ body__ end) - d[:mutable] = true - else - parse_error(ex) - end - - if @capture header nameparam_ <: super_ - nothing - elseif @capture header nameparam_ - super = :Any - else - parse_error(ex) - end - d[:supertype] = super - if @capture nameparam name_{param__} - nothing - elseif @capture nameparam name_ - param = [] - else - parse_error(ex) - end - d[:name] = name - d[:params] = param - d[:fields] = [] - d[:constructors] = [] - for item in body - if @capture item field_::T_ - push!(d[:fields], (field, T)) - elseif item isa Symbol - push!(d[:fields], (item, Any)) - else - push!(d[:constructors], item) - end - end - d -end - -function combinetypedef(d)::Expr - name = d[:name] - parameters = d[:params] - nameparam = isempty(parameters) ? name : :($name{$(parameters...)}) - header = :($nameparam <: $(d[:supertype])) - fields = map(d[:fields]) do field - fieldname, typ = field - :($fieldname::$typ) - end - body = quote - $(fields...) - $(d[:constructors]...) - end - - Expr(STRUCTSYMBOL, d[:mutable], header, body) -end - -function combinefield(x) - fieldname, T = x - :($fieldname::$T) -end diff --git a/src/settable.jl b/src/settable.jl index 1368d53..32ddd0a 100644 --- a/src/settable.jl +++ b/src/settable.jl @@ -1,10 +1,9 @@ export @settable -using MacroTools: prewalk, splitdef, combinedef +using MacroTools: prewalk +using MacroTools: splitdef, combinedef +using MacroTools: splitstructdef, isstructdef, combinestructdef macro settable(ex) - if VERSION < v"0.7-" - __module__ = current_module() - end esc(settable(__module__, ex)) end @@ -87,7 +86,7 @@ function posonly_constructor(dtype::Dict)::Expr end function add_posonly_constructor(ex::Expr)::Expr - dtype = splittypedef(ex) + dtype = splitstructdef(ex) if isempty(dtype[:constructors]) ex elseif has_posonly_constructor(dtype) @@ -95,7 +94,7 @@ function add_posonly_constructor(ex::Expr)::Expr else push!(dtype[:constructors], posonly_constructor(dtype)) @assert has_posonly_constructor(dtype) - combinetypedef(dtype) + combinestructdef(dtype) end end diff --git a/test/runtests.jl b/test/runtests.jl index 5e65235..a283d66 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -8,9 +8,6 @@ const P = Setfield include("test_core.jl") end -@testset "macrotools" begin - include("test_macrotools.jl") -end @testset "settable" begin include("test_settable.jl") end diff --git a/test/test_macrotools.jl b/test/test_macrotools.jl deleted file mode 100644 index 2915191..0000000 --- a/test/test_macrotools.jl +++ /dev/null @@ -1,46 +0,0 @@ -using MacroTools -using Setfield: splittypedef, combinetypedef - -@testset "combinetypedef, splittypedef" begin - ex = :(struct S end) - @test ex |> splittypedef |> combinetypedef |> Base.remove_linenums! == - :(struct S <: Any end) - - @test splittypedef(ex) == Dict( - :constructors => Any[], - :mutable => false, - :params => Any[], - :name => :S, - :fields => Any[], - :supertype => :Any) - - ex = :(mutable struct T end) - @test splittypedef(ex)[:mutable] === true - @test ex |> splittypedef |> combinetypedef |> Base.remove_linenums! == - :(mutable struct T <: Any end) - - ex = :(struct S{A,B} <: AbstractS{B} - a::A - end) - @test splittypedef(ex) == Dict( - :constructors => Any[], - :mutable => false, - :params => Any[:A, :B], - :name => :S, - :fields => Any[(:a, :A)], - :supertype => :(AbstractS{B}),) - - @test ex |> splittypedef |> combinetypedef |> Base.remove_linenums! == - ex |> Base.remove_linenums! - - ex = :(struct S{A} <: Foo; S(a::A) where {A} = new{A}() end) - @test ex |> splittypedef |> combinetypedef |> - Base.remove_linenums! |> MacroTools.flatten == - ex |> Base.remove_linenums! |> MacroTools.flatten - - constructors = splittypedef(ex)[:constructors] - @test length(constructors) == 1 - @test first(constructors) == - :((S(a::A) where A) = new{A}()) |> MacroTools.flatten - -end diff --git a/test/test_quicktypes.jl b/test/test_quicktypes.jl index ed5a1ca..099e8a9 100644 --- a/test/test_quicktypes.jl +++ b/test/test_quicktypes.jl @@ -1,10 +1,5 @@ module TestQuicktypes - -@static if VERSION < v"0.7-" - using Base.Test -else - using Test -end +using Test import Base: == import MacroTools From 55a030d4b4e26c77a6fd35edc62e16c770932ba6 Mon Sep 17 00:00:00 2001 From: Jan Weidner Date: Wed, 15 Aug 2018 22:28:29 +0200 Subject: [PATCH 5/6] Revert "add MultiProperyLens" This reverts commit d8a873000f8459b73d121b6b70f6cf6f6215c80b. --- src/lens.jl | 33 --------------- test/runtests.jl | 16 +++++++- test/test_core.jl | 102 ++++++++++++++++++++++++++++++---------------- 3 files changed, 82 insertions(+), 69 deletions(-) diff --git a/src/lens.jl b/src/lens.jl index 574e066..eb15367 100644 --- a/src/lens.jl +++ b/src/lens.jl @@ -147,36 +147,3 @@ end get(l::IndexLens, obj) = getindex(obj, l.indices...) set(l::IndexLens, obj, val) = setindex(obj, val, l.indices...) - - -const NNamedTupleLens{N,s} = NamedTuple{s, T} where {T <: NTuple{N, Lens}} -struct MultiPropertyLens{L <: NNamedTupleLens} <: Lens - lenses::L -end - -_keys(::Type{MultiPropertyLens{NamedTuple{s,T}}}) where {s,T} = s -@generated function get(l::MultiPropertyLens, obj) - get_arg(fieldname) = :($fieldname = get(l.lenses.$fieldname, obj.$fieldname)) - args = map(get_arg, _keys(l)) - Expr(:tuple, args...) -end - -@generated function set(l::MultiPropertyLens, obj, val) - T = obj - args = map(fieldnames(T)) do fn - if fn in _keys(l) - quote - obj_inner = obj.$fn - lens_inner = l.lenses.$fn - val_inner = val.$fn - set(lens_inner, obj_inner, val_inner) - end - else - :(obj.$fn) - end - end - Expr(:block, - Expr(:meta, :inline), - Expr(:call, :(constructor_of($T)), args...) - ) -end diff --git a/test/runtests.jl b/test/runtests.jl index a283d66..9711fee 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,8 +1,20 @@ module TestSetfield -using Test +@static if VERSION < v"0.7-" + using Base.Test +else + using Test +end + +macro test_deprecated07(ex) + if VERSION < v"0.7-" + return esc(ex) + else + return esc(:(Test.@test_deprecated $ex)) + end +end + using Setfield -const P = Setfield @testset "core" begin include("test_core.jl") diff --git a/test/test_core.jl b/test/test_core.jl index 7ef06ee..1ffd309 100644 --- a/test/test_core.jl +++ b/test/test_core.jl @@ -114,12 +114,6 @@ end test_getset_laws(lens, obj, val1, val2) test_modify_law(f, lens, obj) end - for (lens, val1, val2) in [ - ((P.MultiPropertyLens((a=@lens(_),))), (a=10,), (a=20,)) - ] - test_getset_laws(lens, obj, val1, val2) - test_modify_law(identity, lens, obj) - end end @testset "type stability" begin @@ -140,7 +134,6 @@ end ((@lens _.b.a.b[i+1] ), 4 ), ((@lens _ ), obj), ((@lens _ ), :xy), - (P.MultiPropertyLens((a=(@lens _), b=(@lens _))), (a=1, b=2)), ] @inferred get(lens, obj) @inferred set(lens, obj, val) @@ -185,36 +178,77 @@ end @test compose(la, id) === la end -struct ABC{A,B,C} - a::A - b::B - c::C -end - -@testset "MultiPropertyLens" begin - x = ABC(1,2,3) - l = P.MultiPropertyLens((a=@lens(_), c=@lens(_))) - @test get(l, x) == (a=1, c=3) - @inferred get(l, x) - - @test set(l,x, (a=10, c=30)) == ABC{Int64,Int64,Int64}(10, 2, 30) - @inferred set(l,x, (a=10, c=30)) - - y = 5 - obj = TT(x, y) - l_nested = P.MultiPropertyLens((a=l,b=@lens(_))) - @test get(l_nested, obj) == (a = (a = 1, c = 3), b = 5) - @inferred get(l_nested, obj) - - @test set(l_nested, obj, (a=(a=10.0, c="twenty"), b=:thirty)) == - TT(ABC(10.0, 2, "twenty"), :thirty) - @inferred set(l_nested, obj, (a=(a=10.0, c="twenty"), b=:thirty)) +# @testset "Mutability" begin +# +# @testset "array" begin +# v_init = [1,2,3] +# v = v_init +# @set! v[1] = 2 +# @test v_init[1] == 2 +# @test v === v_init +# +# # Julia 0.7 with --depwarn=error: +# is_deperror07 = VERSION >= v"0.7-" && Base.JLOptions().depwarn == 2 +# +# v = randn(3) +# # @set! v[:] .= 0 # dot-call not supported +# @test_broken v == [0,0,0.] +# if is_deperror07 +# v[:] .= 1 +# else +# v = @test_deprecated07 (@set! v[:] = 1; v) +# end +# @test v == [1,1,1.] +# if is_deperror07 +# v[2:3] .= 4 +# else +# v = @test_deprecated07 (@set! v[2:3] = 4; v) +# end +# @test v == [1,4,4] +# # @set! v[1:2] .= 5 # dot-call not supported +# @test_broken v == [5,5,4] +# end +# +# @testset "@set vs @set!" begin +# m1 = M(1,2) +# m2 = @set m1.a = 10 +# @test !(m2 === m1) +# @test m1.a === 1 +# @test m2.a === 10 +# m3 = @set! m1.a = 100 +# @test m3 === m1 +# @test m1.a === 100 +# end +# +# @testset "composition only mutates the innermost" begin +# m_init = M(1,2) +# m = m_init +# @set! m.a = 10 +# @test m_init.a == 10 +# @test m === m_init +# m_inner_init = M(1,2) +# m_init = M(m_inner_init, 2) +# m = m_init +# @set! m.a.a = 2 +# @test m.a.a == 2 +# @test m === m_init +# @test m.a === m_inner_init +# end +# +# obj = (1,) +# @set! obj[1] = 2 +# @test obj === (2,) +# end + +struct A{X, Y} + x::X + y::Y end @testset "type change during @set (default constructor_of)" begin - obj = TT(2,3) - obj2 = @set obj.b = :three - @test obj2 === TT(2, :three) + obj = A(2,3) + obj2 = @set obj.y = :three + @test obj2 === A(2, :three) end # https://github.com/tkf/Reconstructables.jl#how-to-use-type-parameters From 837e8c05a5bd77862811582eb75fe49a0f94e483 Mon Sep 17 00:00:00 2001 From: Jan Weidner Date: Wed, 15 Aug 2018 22:38:06 +0200 Subject: [PATCH 6/6] remove commented out tests --- test/test_core.jl | 62 ----------------------------------------------- 1 file changed, 62 deletions(-) diff --git a/test/test_core.jl b/test/test_core.jl index 1ffd309..beea620 100644 --- a/test/test_core.jl +++ b/test/test_core.jl @@ -178,68 +178,6 @@ end @test compose(la, id) === la end -# @testset "Mutability" begin -# -# @testset "array" begin -# v_init = [1,2,3] -# v = v_init -# @set! v[1] = 2 -# @test v_init[1] == 2 -# @test v === v_init -# -# # Julia 0.7 with --depwarn=error: -# is_deperror07 = VERSION >= v"0.7-" && Base.JLOptions().depwarn == 2 -# -# v = randn(3) -# # @set! v[:] .= 0 # dot-call not supported -# @test_broken v == [0,0,0.] -# if is_deperror07 -# v[:] .= 1 -# else -# v = @test_deprecated07 (@set! v[:] = 1; v) -# end -# @test v == [1,1,1.] -# if is_deperror07 -# v[2:3] .= 4 -# else -# v = @test_deprecated07 (@set! v[2:3] = 4; v) -# end -# @test v == [1,4,4] -# # @set! v[1:2] .= 5 # dot-call not supported -# @test_broken v == [5,5,4] -# end -# -# @testset "@set vs @set!" begin -# m1 = M(1,2) -# m2 = @set m1.a = 10 -# @test !(m2 === m1) -# @test m1.a === 1 -# @test m2.a === 10 -# m3 = @set! m1.a = 100 -# @test m3 === m1 -# @test m1.a === 100 -# end -# -# @testset "composition only mutates the innermost" begin -# m_init = M(1,2) -# m = m_init -# @set! m.a = 10 -# @test m_init.a == 10 -# @test m === m_init -# m_inner_init = M(1,2) -# m_init = M(m_inner_init, 2) -# m = m_init -# @set! m.a.a = 2 -# @test m.a.a == 2 -# @test m === m_init -# @test m.a === m_inner_init -# end -# -# obj = (1,) -# @set! obj[1] = 2 -# @test obj === (2,) -# end - struct A{X, Y} x::X y::Y