From a57403695e11529e2e4f56793450fbb9171c122d Mon Sep 17 00:00:00 2001 From: Ian <i.r.butterworth@gmail.com> Date: Sun, 7 Aug 2022 15:24:44 -0400 Subject: [PATCH 1/3] make kwdef handle const and atomic fields --- base/util.jl | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/base/util.jl b/base/util.jl index 1dc59e86d7043..12a2f93e08195 100644 --- a/base/util.jl +++ b/base/util.jl @@ -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 @@ -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] From 1afddecd98d2d51351bc442939779cd120fb0ae0 Mon Sep 17 00:00:00 2001 From: Ian <i.r.butterworth@gmail.com> Date: Sun, 7 Aug 2022 15:58:58 -0400 Subject: [PATCH 2/3] add tests --- test/misc.jl | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/misc.jl b/test/misc.jl index bf4b4f2bb41e5..8a0ad13403bcd 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -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 From a39ba06b0b62b831285308c9b9afd449e9eb424a Mon Sep 17 00:00:00 2001 From: Ian Butterworth <i.r.butterworth@gmail.com> Date: Sun, 7 Aug 2022 21:55:54 -0400 Subject: [PATCH 3/3] Update base/util.jl Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> --- base/util.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/util.jl b/base/util.jl index 12a2f93e08195..b824fe1c351dc 100644 --- a/base/util.jl +++ b/base/util.jl @@ -577,9 +577,9 @@ function _kwdef!(blk, params_args, call_args) push!(params_args, ei) push!(call_args, ei) elseif ei isa Expr - is_atomic = ei.head == :atomic + is_atomic = ei.head === :atomic ei = is_atomic ? first(ei.args) : ei # strip "@atomic" and add it back later - is_const = ei.head == :const + 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