They probably _were_, since lower level code representations often has little notion of complex types and their semantics they could be kept clean and focused on machine code, however type inference in a language like C++ complicates such matters immensly since an assignment can be both a register move and a function call.
Template resolution solved that in the past, but C++ today allows auto in so many places that I'm uncertain that it can be done without some flow based support (if constexpr comes to mind).
I mentioned ClangIR(MLIR) in the sibling comment here, feels like it was built for stuff like this.
> Template resolution solved that in the past, but C++ today allows auto in so many places that I'm uncertain that it can be done without some flow based support (if constexpr comes to mind).
This concern is unfounded. The auto keyword in C++ acts as mere syntactic sugar. It works only when the compiler is able to tell exactly what's the type by evaluating the expression.
The auto keyword is also considered a code smell for the same reason: just because the compiler can tell exactly what the type is expected to be, that does not mean the developer can. Therefore it makes the code harder to reason about.
> Template resolution solved that in the past, but C++ today allows auto in so many places that I'm uncertain that it can be done without some flow based support (if constexpr comes to mind).
C++ requires determining the type of every expression immediately. Even auto doesn't change that: it determines the type of the variable based on the initializer, literally following the same rules as template argument deduction (there's a little bit of patching to tweak the exact expression being used for deduction, but https://eel.is/c++draft/dcl.type.auto.deduct#3 is the core rule here).
ClangIR doesn't necessarily help here, because while it does give a more abstract C abstract machine IR semantics, it's still downstream of things like NRVO decision points--it's still fundamentally past the codegen-the-AST barrier.