diff --git a/NEWS.md b/NEWS.md index 72b4629fe4174..bc347df0a93d8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -49,6 +49,7 @@ New library functions * `logrange(start, stop; length)` makes a range of constant ratio, instead of constant step ([#39071]) * The new `isfull(c::Channel)` function can be used to check if `put!(c, some_value)` will block. ([#53159]) * `waitany(tasks; throw=false)` and `waitall(tasks; failfast=false, throw=false)` which wait multiple tasks at once ([#53341]). +* `@typeconst x = y` declares the global `x` as being of type `y` ([#54117]). New library features -------------------- diff --git a/base/util.jl b/base/util.jl index 5e86f026f8f9a..497aa0999e71c 100644 --- a/base/util.jl +++ b/base/util.jl @@ -657,6 +657,40 @@ function def_name_defval_from_kwdef_fielddef(kwdef) end end + +function typeconst_ex(ex) + ex isa Expr || return ex + if ex.head === :(=) + quote + local tmp = $(esc(ex.args[2])) + $(esc(ex.args[1]))::typeof(tmp) = tmp + end + elseif ex.head === :block + ex = copy(ex) + for i in eachindex(ex.args) + ex.args[i] = typeconst_ex(ex.args[i]) + end + ex + else + ex + end +end +""" + @typeconst x = y + +Declares the global `x` as being of constant type `y`, and performs the assignment `x = y`. +Equivalent to `tmp = y; x::typeof(tmp) = tmp`. +Typically used to improve the performance of globals. +Can also be used as `@typeconst begin x = 2; y = 3; end` to perform this replacement on several assignments. +""" +macro typeconst(ex) + if !(ex isa Expr && (ex.head in (:block, :(=)))) + throw(ArgumentError("@typeconst: argument must be assignment or `begin` block")) + else + typeconst_ex(ex) + end +end + # testing """