They simulate concurrency with coroutines because due to design all code that uses the engine functions should run in main thread, so you can't use Tasks or Threads.
The threading thing is a common requirement for game engines, though. Unreal also assumes engine functions are called only on the game thread (unless they're specifically marked otherwise).
ValueTasks help but they can only be awaited once. The Unity runtime knows how to handles the same IEnumerator yielded by multiple parent routines.
Cancellation is another gotcha with Tasks. The main way to cancel tasks is to use exceptions as control flow. This causes cancellation to be very expensive. You can still use cancellation tokens and check for IsCancelled and finish your task cooperatively but then you're kind of doing thinks in an non-canononical way.
Unity also hasn't done the work to make cheap unity lifecycle delay calls such as Task wait for end of frame, (although they could). The work arounds are expensive.