Sorry, it took a while to create a minimal working code that reproduces the problem. See the following module:

VERSION >= v"0.4.0-dev+6521" && __precompile__()
module TestConst
export test
# Earth Equatorial radius [m].
const R0 = 6378137.0
# Standard gravitational parameter for Earth [m^3/s^2].
const m0 = 3.986004418e14
function test(n::Number, e::Number)
# Check if the arguments are valid.
if (n <= 0)
throw(ArgumentError("The angular velocity must be greater than 0."))
end
if !( 0. <= e < 1. )
throw(ArgumentError("The eccentricity must be within the interval 0 <= e < 1."))
end
# Auxiliary variables.
sqrt_m0 = sqrt(m0)
sqrt_e2 = sqrt(1-e^2)
# Auxiliary constant to compute the functions.
K1 = 3.0*R0^2*sqrt_m0/(4.0*(1-e^2)^2)
# Declare the functions that must solved for 0.
f1(a, i) = ne + 2.0*K1*a^(-3.5)*cos(i)
end
end

The problem is not related with the global constants, but with the internal K1. This other code reproduces the problem as well:

VERSION >= v"0.4.0-dev+6521" && __precompile__()
module TestConst
export test
function test(n::Number, e::Number)
# Check if the arguments are valid.
if (n <= 0)
throw(ArgumentError("The angular velocity must be greater than 0."))
end
# Auxiliary constant to compute the functions.
K1 = 3.0
# Declare the functions that must solved for 0.
f1(a, i) = K1
end
end

Notice that, if I remove the exceptions, then everything is fine:

Variables:
#self# <optimized out>
n <optimized out>
e <optimized out>
K1 <optimized out>
f1::TestConst.#f1#1{Float64}

No. I have the same problem with constants that are used in functions and have concluded that this is due to the closure bug #15276, the single most annoying remaining issue in Julia (in my opinion). If this and absolutely nothing else were miraculously fixed in 1.0 then the release would be marked a success in my book.

No, there isnâ€™t a problem here. Read the whole code, not just the header:

Variables:
#self# <optimized out>
n::Int64
e <optimized out>
K1::Core.Box
f1::#f1#15
Body:
begin
K1::Core.Box = $(Expr(:new, :(Core.Box)))
NewvarNode(:(f1::#f1#15))
unless (Base.sle_int)(n::Int64, 0)::Bool goto 6 # lin
e 139:
(Main.throw)($(Expr(:new, :(Base.ArgumentError), "The
angular velocity must be greater than 0.")))::Union{}
6: # line 143:
(Core.setfield!)(K1::Core.Box, :contents, 3.0)::Float
64 # line 146:
f1::#f1#15 = $(Expr(:new, :(Main.#f1#15), :(K1)))
return f1::#f1#15
end::#f1#15

Core.Box doesnâ€™t mean that thereâ€™s a type instability. It just means the variable gets boxed, here because it might not be needed depending on if thereâ€™s an exception or not. But its result is not type-unstable. In fact,

(Core.setfield!)(K1::Core.Box, :contents, 3.0)::Float64 # line 146:

this line says that it knows that the contents will be Float64, so all of the types in the AST are inferred and everything is fine.

Sorry, it is a part of a bigger code and I maybe misunderstood the real problem. See this other code:

VERSION >= v"0.4.0-dev+6521" && __precompile__()
module TestConst
export test
# Earth Equatorial radius [m].
const R0 = 6378137.0
# Standard gravitational parameter for Earth [m^3/s^2].
const m0 = 3.986004418e14
# Perturbation terms based on EGM-08 standard gravitational model [1, pp. 1039].
const J2 = 1.08262617385222e-3
# Earth's orbit mean motion [rad/s]
const ne = (360.0/365.2421897)*pi/180/86400
function test(n::Number, e::Number)
# Check if the arguments are valid.
if (n <= 0)
throw(ArgumentError("The angular velocity must be greater than 0."))
end
if !( 0. <= e < 1. )
throw(ArgumentError("The eccentricity must be within the interval 0 <= e < 1."))
end
# Auxiliary variables.
sqrt_m0 = sqrt(m0)
sqrt_e2 = sqrt(1-e^2)
# Auxiliary constant to compute the functions.
K1 = 3.0*R0^2*J2*sqrt_m0/(4.0*(1-e^2)^2)
# Declare the functions that must solved for 0.
f1(a, i) = ne + 2.0*K1*a^(-3.5)*cos(i)
a_k::Float64 = (m0/n^2)^(1/3)
i_k::Float64 = acos( -ne*a_k^(3.5)/(2*K1) )
f1(a_k, i_k)
end
end

In this case, it is not correcting guessing the return value:

return $(Expr(:invoke, MethodInstance for (::TestConst.#f1#1)(::Float64, ::Float64), :(f1), SSAValue(1), :(i_k)))
end::Any

On the other hand, if I remove K1 from the function f(a,i), then it works:

return $(Expr(:invoke, MethodInstance for (::TestConst.#f1#1)(::Float64, ::Float64), :(f1), SSAValue(0), SSAValue(1)))
end::Float64

NOTE: I know that I can always do K1::Float64, but I want to avoid that.

Actually, I didnâ€™t apply the let block trick correctly previously. The following doesnâ€™t exhibit the performance problem:

module TestConst
export test
function test(n::Number, e::Number)
# Check if the arguments are valid.
if (n <= 0)
throw(ArgumentError("The angular velocity must be greater than 0."))
end
# Auxiliary constant to compute the functions.
K1 = 3.0
# Declare the functions that must solved for 0.
f1 = let K1 = K1
(a, i) -> K1
end
end
end

This isnâ€™t the basic 15276 because a much fancier optimization is required. Naively, the inner function f is visible and could be called throughout the outer test functionâ€”before or after K0 is defined. In order to correctly implement that, K0 must be boxed so that itâ€™s state can be either unassigned or assigned. The compiler would have to prove that f cannot be called before K0 defined in order to know that it doesnâ€™t need to do any boxing here. Itâ€™s possible but quite tricky. You could try moving the definition of K0 before the error checks or putting the main computation into a separate function body that is called after the checks are done. Itâ€™s also worth filing an issue about this situation since we would ideally like to handle it efficiently.