From 56c97039f37f76854f0b3cb2160aec5e63c09ef0 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Tue, 9 Aug 2022 18:41:30 -0400 Subject: [PATCH] `@kwdef`: handle const and atomic fields (#46276) --- base/util.jl | 15 +++++++++++++-- test/misc.jl | 31 +++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/base/util.jl b/base/util.jl index 1dc59e86d7043..b824fe1c351dc 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] 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