A good point, quite a few people in the Rust community (me included) tend to fall prey to “perfect is the enemy of good” 
In terms of implementation strategy? More or less, sure.
However, implementation strategies matter insofar that if no possible implementations strategy for upcasting is acceptable, then we’ll probably never have upcasts for multi-trait objects, period. If true (and it looks more and more true to me the longer I think about it) that has implications for the language design. “We’ll accept this subset of the feature and work out the generalization later” is quite different from “we let you do this thing but the natural generalization will never be possible, sorry”.
See https://github.com/rust-lang/rust/issues/46139 – QoI issue, currently we don’t deduplicate (at least not perfectly), and there are no guarantees.
I think it will be quite common to hold a trait object with a bunch of different traits, then upcast to one specific trait to interact with a library that only needs that one trait.
That still requires analyzing the whole program when you create the vtable at the end. And it assumes there is a unique place to do that – in the usual work flow that’s the leaf binary/staticlib, but AFAICT it doesn’t play nice with dylibs, where one library’s compilation artifact can be used from multiple binaries. (dylibs are Terrible for many reasons, but we need to keep them at least functional.)
Not all trait objects use Box. &Trait is a thing, for example. It works perfectly fine without any heap allocation.
Also, Box<Struct> -> Box<Trait> performs no heap allocation, it just reuses the heap allocation for the object and adds a vtable pointer “externally”. With your strategy, there’s a heap allocation any time a trait object pointer is created or upcasted.
Isn’t that exactly the “fat pointer with many vtable pointers” approach I described at the start?
(Which isn’t blocked on const generics because it’s compiler built-in.)