I think doing it at the time when the variable was defined, like initially requested, is the easy solution:
"""
@var x = rhs
Define `x` to be of fixed type, the type of `rhs`, and assign `rhs` to it.
"""
macro var(ex)
if !(ex isa Expr && ex.head == :(=))
throw(ArgumentError("expression should be of the form `var = value`"))
end
name = ex.args[1]
rhs = ex.args[2]
tmp = gensym(name)
esc(quote
$tmp = $rhs
($name)::typeof($tmp) = $tmp
end)
end
Test
julia> function f(x)
@var y = x
y = 1.2
return y
end
f (generic function with 1 method)
julia> f(1)
ERROR: InexactError: Int64(1.2)
Stacktrace:
[1] Type at ./float.jl:703 [inlined]
[2] convert(::Type{Int64}, ::Float64) at ./number.jl:7
[3] f(::Int64) at ./REPL[2]:3
[4] top-level scope at REPL[3]:1
julia> f(1.3)
1.2