How is `x::T` lowered? (the actual post)

It’s implemented by calling y = convert(T, ...)::T every time you assign to y in the lowered code. The reason for the ::T assertion is to ensure that the compiler gets the correct type of y, in case the convert call is type-unstable (e.g. a buggy convert implementation). In the usual case where the convert call is type-stable and inferred, the ::T assertion is optimized out.

This is clearer if you do multiple assignments to the typed local variable in your function:

julia> function f(x)
           local y::Float64
           y = x
           y = y + x
       end
f (generic function with 1 method)

julia> @code_lowered f(3)
CodeInfo(
1 ─ %1 = x
│   %2 = Base.convert(Main.Float64, %1)
│        y = Core.typeassert(%2, Main.Float64)
│   %4 = y + x
│   %5 = Base.convert(Main.Float64, %4)
│        y = Core.typeassert(%5, Main.Float64)
└──      return %4
)

Note that all of the type assertions are eventually optimized away:

julia> @code_llvm debuginfo=:none f(3)
define double @julia_f_362(i64 signext %0) #0 {
top:
  %1 = sitofp i64 %0 to double
  %2 = fadd double %1, %1
  ret double %2
}
9 Likes