There are no shortcuts, no silver bullets when it comes to concurrency. Programmers have to learn about multi-threading and the ways it can go wrong because it's a fundamental thing, not a mere feature you can design your way out of.
But you can identify the opposite of the silver bullet, which is shared mutable state, and then hurry away from it as quickly as possibly.
Rust defaulted to avoiding sharing and Haskell defaulted to avoiding mutability.
For application code, I've yet to see a better concurrency story than 'use pure functions where possible, or use STM when you absolutely need shared mutation'.
You can't get data races, which is what Rust prevents. Rust's async doesn't prevent deadlocks or other kinds of races.
At which point they're not really threads, they're more, well, processes.
> This is what Erlang does.
Exactly.