Skip to content

Commit

Permalink
@kwdef: handle const and atomic fields (#46276)
Browse files Browse the repository at this point in the history
  • Loading branch information
IanButterworth authored Aug 9, 2022
1 parent 686afd3 commit 70656e2
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 2 deletions.
15 changes: 13 additions & 2 deletions base/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,16 @@ function _kwdef!(blk, params_args, call_args)
push!(params_args, ei)
push!(call_args, ei)
elseif ei isa Expr
if ei.head === :(=)
is_atomic = ei.head === :atomic
ei = is_atomic ? first(ei.args) : ei # strip "@atomic" and add it back later
is_const = ei.head === :const
ei = is_const ? first(ei.args) : ei # strip "const" and add it back later
# Note: `@atomic const ..` isn't valid, but reconstruct it anyway to serve a nice error
if ei isa Symbol
# const var
push!(params_args, ei)
push!(call_args, ei)
elseif ei.head === :(=)
lhs = ei.args[1]
if lhs isa Symbol
# var = defexpr
Expand All @@ -593,7 +602,9 @@ function _kwdef!(blk, params_args, call_args)
defexpr = ei.args[2] # defexpr
push!(params_args, Expr(:kw, var, esc(defexpr)))
push!(call_args, var)
blk.args[i] = lhs
lhs = is_const ? Expr(:const, lhs) : lhs
lhs = is_atomic ? Expr(:atomic, lhs) : lhs
blk.args[i] = lhs # overrides arg
elseif ei.head === :(::) && ei.args[1] isa Symbol
# var::Typ
var = ei.args[1]
Expand Down
31 changes: 31 additions & 0 deletions test/misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,37 @@ const outsidevar = 7
end
@test TestOutsideVar() == TestOutsideVar(7)

@kwdef mutable struct Test_kwdef_const_atomic
a
b::Int
c::Int = 1
const d
const e::Int
const f = 1
const g::Int = 1
@atomic h::Int
end

@testset "const and @atomic fields in @kwdef" begin
x = Test_kwdef_const_atomic(a = 1, b = 1, d = 1, e = 1, h = 1)
for f in fieldnames(Test_kwdef_const_atomic)
@test getfield(x, f) == 1
end
@testset "const fields" begin
@test_throws ErrorException x.d = 2
@test_throws ErrorException x.e = 2
@test_throws MethodError x.e = "2"
@test_throws ErrorException x.f = 2
@test_throws ErrorException x.g = 2
end
@testset "atomic fields" begin
@test_throws ConcurrencyViolationError x.h = 1
@atomic x.h = 1
@test @atomic(x.h) == 1
@atomic x.h = 2
@test @atomic(x.h) == 2
end
end

@testset "exports of modules" begin
for (_, mod) in Base.loaded_modules
Expand Down

0 comments on commit 70656e2

Please sign in to comment.