typeof(f(x)) can be evaluated at compile-time, provided the return type of f(x) is inferrable. Why can’t we have a guarantee that this is always the case?
Because the two statement (typeof being statically known and sin call be removed) are unrelated. The code you show is a proof that the compiler knows the return type of sin. It’s making the call only because there can be sideeffect and it is right about that. I believe sin can actually throw so even if the compiler is much smarter it still won’t be able to remove the call.
P.s. please use code_warntype since you seem to be confusing yourself with the llvm code.
Ah right! sin(Inf) throws. However exp(x::Float64) never throws, and there is no side-effect (right?).
In this case the call to exp is not elided either. Why?
julia> f(x) = typeof(exp(x))
f (generic function with 1 method)
julia> @code_llvm debuginfo=:none f(5.0)
define nonnull %jl_value_t addrspace(10)* @julia_f_12336(double) {
top:
%1 = call double @julia_exp_12332(double %0)
ret %jl_value_t addrspace(10)* addrspacecast (%jl_value_t* inttoptr (i64 140549511198736 to %jl_value_t*) to %jl_value_t addrspace(10)*)
}
julia> @code_warntype f(5)
Body::Type{Float64}
1 ─ %1 = (Base.sitofp)(Float64, x)::Float64
│ invoke Base.Math.exp(%1::Float64)
└── return Float64
First of all, you can still see that the call is in the typed last. You don’t need to look at the llvm it.
And that’s why I said in the sin case it is impossible with any compiler improvement. I don’t know if exp can throw but it’s just showing that the compiler can’t proof the side effect.