What you're describing is exactly correct - you need a more robust "typestate" system (I call them "annotations"). Most languages have typestates - where you can, for example, declare a variable without immediately assigning it a value, but that variable remains write-only until it is assigned to.
But these typestate systems aren't very elaborate usually. I've recently been doing research on the (hypothetical) design of a language which has typestates that can cross function boundaries - you can call a function that annotates that it uninitializes one of its arguments, and then that reference you passed in is now considered uninitialized in your local scope.
But these typestate systems aren't very elaborate usually. I've recently been doing research on the (hypothetical) design of a language which has typestates that can cross function boundaries - you can call a function that annotates that it uninitializes one of its arguments, and then that reference you passed in is now considered uninitialized in your local scope.