Support escape expressions in @kwdef (#53230)
`@kwdef` currently does not handle escaped type names and default values
correctly. This makes it impossible to write a (correctly escaped) macro
that internally uses `@kwdef`:
```julia
julia> module M
macro define_struct(name)
quote
@kwdef struct $(esc(name)) field::Int end
end
end
end;
julia> @macroexpand M.@define_struct(Foo)
ERROR: Invalid usage of @kwdef
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] var"@kwdef"(__source__::LineNumberNode, __module__::Module, expr::Any)
@ Base ./util.jl:603
[3] #macroexpand#66
@ Base ./expr.jl:122 [inlined]
[4] top-level scope
@ REPL[5]:1
```
This PR patches `@kwdef` so various types of escaping are handled
correctly. Specifically, all of the following now works (see new test
case
[here](https://github.com/ettersi/julia/blob/adf7e20378ae7d0c3cf24a2cc3c815e560913b78/test/misc.jl#L1290-L1332)):
```julia
module KwdefWithEsc
const Int1 = Int
const val1 = 42
macro define_struct()
quote
@kwdef struct $(esc(:Struct))
a
b = val1
c::Int1
d::Int1 = val1
$(esc(quote
e
f = val2
g::Int2
h::Int2 = val2
end))
$(esc(:(i = val2)))
$(esc(:(j::Int2)))
$(esc(:(k::Int2 = val2)))
l::$(esc(:Int2))
m::$(esc(:Int2)) = val1
n = $(esc(:val2))
o::Int1 = $(esc(:val2))
$(esc(:p))
$(esc(:q)) = val1
$(esc(:s))::Int1
$(esc(:t))::Int1 = val1
end
end
end
end
module KwdefWithEsc_TestModule
using ..KwdefWithEsc
const Int2 = Int
const val2 = 42
KwdefWithEsc.@define_struct()
end
```
---------
Co-authored-by: inky <git@wo-class.cn>