> the problems were not minor but fundamental, and had to do with C interoperability,
The interoperability problems came from a design choice they made: they wanted to invisibly swap between OS threads if a blocking call was made. That was the wrong design choice for Rust. It is not something green threads require - it's an additional burden they imposed on themselves.
> a fine choice to make in the context of Go,
Correct. It was.
> enable concurrency even on systems where threads do not exist,
And that was their mistake. Green threads are just user space stacks, which any CPU that has a stack pointer can support. They don't need OS threads. But in the initial Rust implementation they added "invisibly supports blocking calls" implementation. That does indeed need full OS thread support, and breaks the C interface.
They could have just abandoned that mistake, implemented pure green threads and they would have been done. But no, they instead they implemented async. So instead we got new keywords, had to wait years for various new language features to stabilise (like pin) and lifetime 'static. I'm sure the language designers spent many happy man months solving the problem "How do we represent a suspended function as a type-safe State Machine?".
What we got for all that effort is something so famously difficult to use, even experienced Rust programmer shy away from async. Whereas with green threads a programmer could just reuse their knowledge and mechanisms Rust has for sharing data across multiple stacks, for async they have now to battle the borrow checker on a new front - the language to absorb their function state into 'static area that has fewer lifetime guarantees. The alternate green thread implementation could have had just two colours - blocking and non-blocking, now we have a colour for every async library. Whereas with green threads they could have stabilised the interface to underlying the event loop, we are now stuck with every library writer having their I/O in their own mini API, which they swap for each async implementation.
And while the type-safe State Machine they did come up with is an engineering marvel, it's very complex and requires data copies under the hood. Green threads just reuse an existing mechanism for saving a function's state - the CPU's IP Address, the registers and the stack. It's so simple anyone can understand it, it isn't something additional to learn because the program's main already uses it, it is very, very fast because it's undergone decades of refinement, and it's also type safe!
But instead in what we got the syntax is a mess, the error messages are incomprehensible, and we re-implemented the CPU's stack management in software (invariably slower) because they didn't want to write the logic to grow a hardware stack.
The language will be better off recognising it was all a huge mistake, and moving towards standardising on a green thread implementation like mioco. Everyone who has to manage 100,000 lightweight processes would be immensely grateful for the simpler, faster API. Some of the truly impressive stuff done for async, like knowing how much stack some function calls can take, would be really useful for green threads. You know the size of the stack you need - to the byte! So it's not a complete loss.