panstromek
`actix-web` itself should be fine, `sqlx` can be heavy if you use its compile time features, I'd assume `askama` is heavy as well, just based on the description (it generates rust code at compile time).
Otherwise it depends on how the code is structured (e.g. how generic it is, how deep types or complicated futures it creates).
I assume you ask about polymorphization, which is a term used to refer to a specific optimization mentioned in the blog post.
The base version which Rust wants the most makes sense to enable by default for all builds, because it's purely just removing duplicate work - this is for cases like Vec<u64> and Vec<i64>, where we currently emit code for each one separately, even though it's pretty much the same for both.
More general version will make sense for debug builds or in some special cases, like when optimizing for size. I believe people also want to experiment with it for some interop use cases (and for that, it'd be useful to have source level annotation). I think it's too early to tell how all of this is going to look like, though.
Do you have some more info about the codebase, is it public?
It's not directly blocked on the solver, but getting the type system into a better shape definitely helps reasoning about the soundness issues involved.
We have discussed this briefly on last All Hands, the problem will probably be dealing with compiler errors, when they happen in builds that already emitted metadata. I believe this was the reason why it wasn't merged in the first place.
What do you mean by this?
Nevertheless, people in the project are trying to figuring out a way to relax the rule while still maintaining coherence, so this might happen some day.
Various crates have explicit workarounds for these issues as well, typically using Box to avoid deep types, e.g. axum's `.route()` added it explicitly to avoid this, I believe.
For match exhaustivness, there's currently an active discussion on it again, because it comes up in derives for big enums, and we just landed an optimization that avoids it for some derive macros.
In other ecosystems, I remember a talk about avoiding exponential blowup for various constructs in C++ templates. Typescript even has a guide for how to write types to avoid complexity problems. With libriaries like `ArkType`, people hit these issues a quite a bit.
I won't claim that this is the majority of the compile time work, but it's something that comes up often enough that I think it's pretty ridiculous to say "the worst-case just doesn't occur."
> For (1) and (2), the worst-case just doesn't occur.
I don't think 2. is a good example to be honest, It happens quite a lot. At least it's definitely not in the same category as dependency resolution, where people often don't even know that it's NP-hard.
Typescript, Rust or C++ type system complexity is routinely a compile time problem that people have to work around or tackle from both sides (i.e. either changing the compiler or changing the program).
Since you mentioned libc, the likely answer is that nothing gets codegened in downstream crates. But this is only because libc functions are usually not generic or `#[inline]`. Changes to generic or inline functions can dirty downstream codegen units where the function was called. Inside `libc`, the change will trigger recompilation of at least one codegen unit, depending on how the function is used inside libc itself. Single crate is split into 256 units in incremental mode.
Nevertheless, even if the codegen is needed just for the `libc` crate, `libc` will dirty its metadata, which means that downstream crates will still need to recompile the initial steps before incremental kicks in (which is roughly parsing, macro expansion and name resolution). After that, the query system just returns cached results for all the subsequent steps.
There's some work going towards skipping the rustc invocation altogether in those cases (usually referred to as "Relink don't Rebuild" proposal), because even just loading the dependency graph and figuring out that you don't have to do anything can take quite bit of time for larger programs.
> I would also enjoy if recompilation avoidance were to happen at the function level, not the file level.
This sounds like Rust is already doing a lot more incremental then GHC then. Rustc only needs to parse, expand macros and do name resolution. Everything else is incremental after that, on a very granular level.
There's also -Zhint-mostly-unused flag.
The tradeoff is that these functions then have to be encoded in metadata for downstream crates, so it's not necessarily faster.
There's a language called Unison that does that - and the "content" is the AST, so all functions that have the same shape are the same function. It's pretty interesting.
Big insight in that article is also from https://matklad.github.io/2021/08/22/large-rust-workspaces.h... about structuring large rust workspaces as a flat list.