There are fundamental restrictions where NativeAOT will never work or be desirable. For example, runtime-compiled regex patterns or any other feature which relies on emitting IL at runtime and creating new members or even assembles and then loading them. Similar applies to compiled expression trees - they are supported in NativeAOT but in the form of falling back onto interpreting them, which has worse performance. Or unbound reflection with patterns that cannot be statically proven and/or analyzed.
Reflection analysis can (and will) be improved but there are hard constraints - a correctly working expression like 'someAssembly.GetType(Console.ReadLine())' by definition would have to root (and force compilation for) every type in the assembly, which is highly undesirable or even sometimes unfeasible for AOT compilation. And there is a lot of code which does exactly this.
The main challenge are packages and frameworks. ASP.NET Core is largely compatible (via minimal API) and so is AvaloniaUI, EF Core has some compatibility assurances and DapperAOT is tailor-made as the name implies, serialization is also a solved problem although you may need to use a different API.
At the end of the day, NativeAOT is not something "to be fully migrated to" because it has fundamental restrictions (some of which also affect other languages like Rust or Go) and having JIT around is a feature for patterns which specifically exploit it but is also a performance optimization (DynamicPGO, better instruction selection especially around SIMD paths, turning static readonly's into JIT constants and apply subsequent optimizations on top of that, this is what makes C# port of Mimalloc so good as it elides dead code with assertions impossible to remove dynamically in C/C++). NativeAOT has its own optimizations, and it will continue to diverge with JIT (e.g. there's a toggle in .NET compiler to repeat some optimization phases, usually it's too expensive for JIT but for AOT it's a good fit, AFAIK there is work to productize this).
The wide perception that JIT-compiled code has to be slower stems from other sources of performance overhead that are typical to languages which happen to use JIT (many of which have "weaker" compilers too), not from the JIT compilation itself. There are technicalities like certain calls have to be indirect in order to support patching the callee address, or inter-procedural analysis which is trivial to prove under AOT may not be so under JIT where new callers/callees may be constructed dynamically or a reJIT invoked which would invalidate the analysis results. JIT also costs additional memory. But it's not a source of worse performance.
Reflection analysis can (and will) be improved but there are hard constraints - a correctly working expression like 'someAssembly.GetType(Console.ReadLine())' by definition would have to root (and force compilation for) every type in the assembly, which is highly undesirable or even sometimes unfeasible for AOT compilation. And there is a lot of code which does exactly this.
The main challenge are packages and frameworks. ASP.NET Core is largely compatible (via minimal API) and so is AvaloniaUI, EF Core has some compatibility assurances and DapperAOT is tailor-made as the name implies, serialization is also a solved problem although you may need to use a different API.
At the end of the day, NativeAOT is not something "to be fully migrated to" because it has fundamental restrictions (some of which also affect other languages like Rust or Go) and having JIT around is a feature for patterns which specifically exploit it but is also a performance optimization (DynamicPGO, better instruction selection especially around SIMD paths, turning static readonly's into JIT constants and apply subsequent optimizations on top of that, this is what makes C# port of Mimalloc so good as it elides dead code with assertions impossible to remove dynamically in C/C++). NativeAOT has its own optimizations, and it will continue to diverge with JIT (e.g. there's a toggle in .NET compiler to repeat some optimization phases, usually it's too expensive for JIT but for AOT it's a good fit, AFAIK there is work to productize this).
The wide perception that JIT-compiled code has to be slower stems from other sources of performance overhead that are typical to languages which happen to use JIT (many of which have "weaker" compilers too), not from the JIT compilation itself. There are technicalities like certain calls have to be indirect in order to support patching the callee address, or inter-procedural analysis which is trivial to prove under AOT may not be so under JIT where new callers/callees may be constructed dynamically or a reJIT invoked which would invalidate the analysis results. JIT also costs additional memory. But it's not a source of worse performance.