Yeah, move
shouldn't have any runtime effect at all on its own; it should only have the compile-time effect of taking the moved variable out of scope, and as a side effect of that, allowing the bound value's lifetime to shrink to the new end of scope. That compile-time-only transparency should avoid pitfalls like the one @allevato mentioned of std::move
in C++ occasionally defeating last-use optimizations if used improperly.
That's a fair concern. Our hope is that the lexical lifetime rules strike a balance where obvious code like this still does the right thing without explicit moves, so move
(or however we end up spelling the operation) will still be something most Swift developers don't normally have to think about. But at the same time, performance-constrained developers who must get hard guarantees of their code's behavior really need something that will make the compiler raise diagnostics if those guarantees can't be met, for the reasons Andy laid out.
I think we will need move-only types to be able to fully compose types with move-only properties on the level of Rust. These proposals will get us closer to that point, at least, and many of them would be required to work with values and parts of structs and classes without requiring copies anyway, but the full composability in the type system won't be there yet.
I think this capability will be a natural outgrowth of compile-time constant values. Once we've established what a compile-time-constant expression is, then it would be a natural next step to be able to annotate an initializer expression as being required to be a constant expression.
It is my hope that Swift will still be able to continue to "do the right thing" by default in most situations. As I noted above, our design for move
should hopefully avoid the pitfalls of move
in C++ being able to accidentally defeat the desired optimization. It could well be in practice, people end up spraying move
everywhere out of an abundance of caution, but I hope that they won't need to.

My mental model thus far has been that a value’s lifetime may end starting when it is last referenced. Is it correct to say that that is still true, but has been joined by a guarantee that it will end when the scope is exited?
In practice, the guarantee that it will end before or at the point the scope exits has always been there. We are planning to introduce new barriers that limit how far back a value's lifetime may end, so that it not only includes the final use in source code, but also things like weak reference loads and memory accesses through UnsafePointer that tend to rely on the lifetime of other variables to get correct behavior.