The pretty printer algorithm involves 2 VecDeques: a ring-buffer of
tokens and a deque of ring-buffer indices. Confusingly, those two deques
were being grown in opposite directions for no good reason. Ring-buffer
pushes would go on the "back" of the ring-buffer (i.e. higher indices)
while scan_stack pushes would go on the "front" (i.e. lower indices).
This commit flips the scan_stack accesses to grow the scan_stack and
ring-buffer in the same direction, where push does the same
operation as a Vec push i.e. inserting on the high-index end.
Pretty printer algorithm revamp step 2
This PR follows #92923 as a second chunk of modernizations backported from https://github.com/dtolnay/prettyplease into rustc_ast_pretty.
I've broken this up into atomic commits that hopefully are sensible in isolation. At every commit, the pretty printer is compilable and has runtime behavior that is identical to before and after the PR. None of the refactoring so far changes behavior.
The general theme of this chunk of commits is: the logic in the old pretty printer is doing some very basic things (pushing and popping tokens on a ring buffer) but expressed in a too-low-level way that I found makes it quite complicated/subtle to reason about. There are a number of obvious invariants that are "almost true" -- things like `self.left == self.buf.offset` and `self.right == self.buf.offset + self.buf.data.len()` and `self.right_total == self.left_total + self.buf.data.sum()`. The reason these things are "almost true" is the implementation tends to put updating one side of the invariant unreasonably far apart from updating the other side, leaving the invariant broken while unrelated stuff happens in between. The following code from master is an example of this:
e5e2b0be26/compiler/rustc_ast_pretty/src/pp.rs (L314-L317)
In this code the `advance_right` is reserving an entry into which to write a next token on the right side of the ring buffer, the `check_stack` is doing something totally unrelated to the right boundary of the ring buffer, and the `scan_push` is actually writing the token we previously reserved space for. Much of what this PR is doing is rearranging code to shrink the amount of stuff in between when an invariant is broken to when it is restored, until the whole thing can be factored out into one indivisible method call on the RingBuffer type.
The end state of the PR is that we can entirely eliminate `self.left` (because it's now just equal to `self.buf.offset` always) and `self.right` (because it's equal to `self.buf.offset + self.buf.data.len()` always) and the whole `Token::Eof` state which used to be the value of tokens that have been reserved space for but not yet written.
I found without these changes the pretty printer implementation to be hard to reason about and I wasn't able to confidently introduce improvements like trailing commas in `prettyplease` until after this refactor. The logic here is 43 years old at this point (Graydon translated it as directly as possible from the 1979 pretty printing paper) and while there are advantages to following the paper as closely as possible, in `prettyplease` I decided if we're going to adapt the algorithm to work better for Rust syntax, it was worthwhile making it easier to follow than the original.
mangling_v0: Skip extern blocks during mangling
There's no need to include the dummy `Nt` into the symbol name, items in extern blocks belong to their parent modules for all purposes except for inheriting the ABI and attributes.
Follow up to https://github.com/rust-lang/rust/pull/92032
(There's also a drive-by fix to the `rust-demangler` tool's tests, which don't run on CI, I initially attempted using them for testing this PR.)
Remove some unused ordering derivations based on `DefId`
Like #93018, this removes some unused/unneeded ordering derivations as part of ongoing work on #90317. Here, these changes are aimed at making https://github.com/rust-lang/rust/pull/90749 easier to review, test, and merge.
r? `@cjgillot`
Move expr- and item-related pretty printing functions to modules
Currently *compiler/rustc_ast_pretty/src/pprust/state.rs* is 2976 lines on master. The `tidy` limit is 3000, which is blocking #92243.
This PR adds a `mod expr;` and `mod item;` to move logic related to those AST nodes out of the single huge file.
Use iterator instead of recursion in `codegen_place`
This PR fixes the FIXME in `codegen_place` about using iterator instead of recursion when processing the `projection` field in `mir::PlaceRef`. At the same time, it also reduces the right drift.
Formally implement let chains
## Let chains
My longest and hardest contribution since #64010.
Thanks to `@Centril` for creating the RFC and special thanks to `@matthewjasper` for helping me since the beginning of this journey. In fact, `@matthewjasper` did much of the complicated MIR stuff so it's true to say that this feature wouldn't be possible without him. Thanks again `@matthewjasper!`
With the changes proposed in this PR, it will be possible to chain let expressions along side local variable declarations or ordinary conditional expressions. In other words, do much of what the `if_chain` crate already does.
## Other considerations
* `if let guard` and `let ... else` features need special care and should be handled in a following PR.
* Irrefutable patterns are allowed within a let chain context
* ~~Three Clippy lints were already converted to start dogfooding and help detect possible corner cases~~
cc #53667
Delete pretty printer tracing
These are left over from 2011. I did not find these helpful at all in my work on https://github.com/dtolnay/prettyplease despite doing significant refactors to this code. Learning what these messages all refer to is harder than putting in your own messages to log exactly what is relevant to specifically the thing that you are working on debugging.
Directly use ConstValue for single literals in blocks
Addresses the minimal repro in https://github.com/rust-lang/rust/issues/92186, but doesn't fix the underlying problem (which would be solved by solving the anon subst problem afaict).
I do, however, think that it makes sense in general to treat single literals in anon blocks as const values directly, especially in light of the problem that the issue refers to (anon const evaluation being postponed until infer variables in substs can be resolved, which was introduced by https://github.com/rust-lang/rust/pull/90023), i.e. while we do get warnings for those unnecessary braces, we should try to avoid errors caused by those braces if possible.
Improve SIMD casts
* Allows `simd_cast` intrinsic to take `usize` and `isize`
* Adds `simd_as` intrinsic, which is the same as `simd_cast` except for saturating float-to-int conversions (matching the behavior of `as`).
cc `@workingjubilee`
Let qpath contain NtTy: `<$:ty as $:ty>::…`
Example:
```rust
macro_rules! m {
(<$type:ty as $trait:ty>::$name:ident) => {
<$type as $trait>::$name
};
}
fn main() {
let _: m!(<str as ToOwned>::Owned);
}
```
Previous behavior:
```console
error: expected identifier, found `ToOwned`
--> src/main.rs:3:19
|
3 | <$type as $trait>::$name
| ^^^^^^ expected identifier
...
8 | let _: m!(<str as ToOwned>::Owned);
| ---------------------------
| |
| this macro call doesn't expand to a type
| in this macro invocation
```
The <code>expected identifier, found \`ToOwned\`</code> error is particularly silly. I think it should be fine to accept this code as long as $trait is of the form `TyKind::Path(None, path)`; if it is any other kind of `NtTy`, we'll keep the same behavior as before.
Implement raw-dylib support for windows-gnu
Add support for `#[link(kind = "raw-dylib")]` on windows-gnu targets. Work around binutils's linker's inability to read import libraries produced by LLVM by calling out to the binutils `dlltool` utility to create an import library from a temporary .DEF file; this approach is effectively a slightly refined version of `@mati865's` earlier attempt at this strategy in PR #88801. (In particular, this attempt at this strategy adds support for `#[link_ordinal(...)]` as well.)
In support of #58713.
Avoid unnecessary monomorphization of inline asm related functions
This should reduce build time for codegen backends by avoiding duplicated monomorphization of certain inline asm related functions for each passed in closure type.
Abstract the pretty printer's ringbuffer to be infinitely sized
This PR backports 8e5e83c3ff from the `prettyplease` crate into `rustc_ast_pretty`.
Using a dedicated RingBuffer type with non-wrapping indices, instead of manually `%`-ing indices into a capped sized buffer, unlocks a number of simplifications to the pretty printing algorithm implementation in followup commits such as fcb5968b1e and 4427cedcb8.
This change also greatly reduces memory overhead of the pretty printer. The old implementation always grows its buffer to 205920 bytes even for files without deeply nested code, because it only wraps its indices when they hit the maximum tolerable size of the ring buffer (the size after which the pretty printer will crash if there are that many tokens buffered). In contrast, the new implementation uses memory proportional to the peak number of simultaneously buffered tokens only, not the number of tokens that have ever been in the buffer.
Speaking of crashing the pretty printer and "maximum tolerable size", the constant used for that in the old implementation is a lie:
de9b573eed/compiler/rustc_ast_pretty/src/pp.rs (L227-L228)
It was raised from 3 to 55 in https://github.com/rust-lang/rust/pull/33934 because that was empirically the size that avoided crashing on one particular test crate, but according to https://github.com/rust-lang/rust/pull/33934#issuecomment-226700470 other syntax trees still crash at that size. There is no reason to believe that any particular size is good enough for arbitrary code, and using a large number like 55 adds overhead to inputs that never need close to that much of a buffer. The new implementation eliminates this tradeoff.
Add some more attribute validation
This adds some more validation for the position of attributes:
* `link` is only valid on an `extern` block
* `windows_subsystem` and `no_builtins` are only valid at the crate level
Fix ICEs related to `Deref<Target=[T; N]>` on newtypes
1. Stash a const infer's type into the canonical var during canonicalization, so we can recreate the fresh const infer with that same type.
For example, given `[T; _]` we know `_` is a `usize`. If we go from infer => canonical => infer, we shouldn't forget that variable is a usize.
Fixes#92626Fixes#83704
2. Don't stash the autoderef'd slice type that we get from method lookup, but instead recreate it during method confirmation. We need to do this because the type we receive back after picking the method references a type variable that does not exist after probing is done.
Fixes#92637
... A better solution for the second issue would be to actually _properly_ implement `Deref` for `[T; N]` instead of fixing this autoderef hack to stop leaking inference variables. But I actually looked into this, and there are many complications with const impls.