.await generates code that invokes Future::poll. The first parameter has type Pin<&mut Self>. The main characteristic of Pin<P> is that it represents a pointer to a value that is guaranteed to never move after the Pin<P> is created, unless the pointee implements Unpin (which means it doesn't care if it's moved).
Let's first answer: Why is it not necessary to pin a future in order to await it by value? That is, why does this work:
pub async fn foo() {
let fut = async {};
fut.await;
}
It's simple: fut.await consumes fut.
pub async fn foo() {
let fut = async {};
fut.await;
drop(fut); // error[E0382]: use of moved value: `fut`
}
There is no opportunity for us to move fut after fut.await, so there is no way we could violate Pin's rules on fut.
However, if we could .await a reference, then we would be able to move the original value after the .await, and that would be disastrous if fut was self-referential.
The error comes from the compiler failing to find an implementation of Future for the expression &mut fut. There is impl<'_, F> Future for &'_ mut F where F: Future + Unpin + ?Sized in the standard library; however, fut doesn't implement Unpin, so that's what the compiler reports in its error message.
tokio::pin!(fut) first moves fut (this is how the macro can ensure it has ownership of the future), then declares a new variable fut of type Pin<&mut F> (where F is the original fut's type).
Thus, the code following tokio::pin!(fut) that uses fut manipulates a pinned reference to the future, rather than the future value directly. If we try to move fut, then we just move the pinned reference. And if we take a mutable reference to fut, then we end up with a reference to a pinned reference (&mut Pin<&mut F>). This type does implement Future because:
&mut F implements Unpin even if F doesn't implement Unpin
Pin<&mut F> implements Unpin because &mut F implements Unpin
Pin<&mut F> implements Future because F implements Future
&mut Pin<&mut F> implements Future because Pin<&mut F> implements both Future and Unpin