Add new `PatKind::Missing` variants
To avoid some ugly uses of `kw::Empty` when handling "missing" patterns, e.g. in bare fn tys. Helps with #137978. Details in the individual commits.
r? ``@oli-obk``
"Missing" patterns are possible in bare fn types (`fn f(u32)`) and
similar places. Currently these are represented in the AST with
`ast::PatKind::Ident` with no `by_ref`, no `mut`, an empty ident, and no
sub-pattern. This flows through to `{hir,thir}::PatKind::Binding` for
HIR and THIR.
This is a bit nasty. It's very non-obvious, and easy to forget to check
for the exceptional empty identifier case.
This commit adds a new variant, `PatKind::Missing`, to do it properly.
The process I followed:
- Add a `Missing` variant to `{ast,hir,thir}::PatKind`.
- Chang `parse_param_general` to produce `ast::PatKind::Missing`
instead of `ast::PatKind::Missing`.
- Look through `kw::Empty` occurrences to find functions where an
existing empty ident check needs replacing with a `PatKind::Missing`
check: `print_param`, `check_trait_item`, `is_named_param`.
- Add a `PatKind::Missing => unreachable!(),` arm to every exhaustive
match identified by the compiler.
- Find which arms are actually reachable by running the test suite,
changing them to something appropriate, usually by looking at what
would happen to a `PatKind::Ident`/`PatKind::Binding` with no ref, no
`mut`, an empty ident, and no subpattern.
Quite a few of the `unreachable!()` arms were never reached. This makes
sense because `PatKind::Missing` can't happen in every pattern, only
in places like bare fn tys and trait fn decls.
I also tried an alternative approach: modifying `ast::Param::pat` to
hold an `Option<P<Pat>>` instead of a `P<Pat>`, but that quickly turned
into a very large and painful change. Adding `PatKind::Missing` is much
easier.
Consider fields to be inhabited if they are unstable
Fixes#133885 with a simple heuristic
r? Nadrieril
Not totally certain if this needs T-lang approval or a crater run.
A check for `#[non_exhaustive]` is often done in combination with
checking whether the type is local to the crate, in a variety of ways.
Create a helper method and standardize on it as the way to check for
this.
It's similar to the other limits, e.g. obtained via `get_limit`. So it
makes sense to handle it consistently with the other limits. We now use
`Limit`/`usize` in most places instead of `Option<usize>`, so we use
`Limit::new(usize::MAX)`/`usize::MAX` to emulate how `None` used to work.
The commit also adds `Limit::unlimited`.
Point at `const` definition when used instead of a binding in a `let` statement
Modify `PatKind::InlineConstant` to be `ExpandedConstant` standing in not only for inline `const` blocks but also for `const` items. This allows us to track named `const`s used in patterns when the pattern is a single binding. When we detect that there is a refutable pattern involving a `const` that could have been a binding instead, we point at the `const` item, and suggest renaming. We do this for both `let` bindings and `match` expressions missing a catch-all arm if there's at least one single binding pattern referenced.
After:
```
error[E0005]: refutable pattern in local binding
--> $DIR/bad-pattern.rs:19:13
|
LL | const PAT: u32 = 0;
| -------------- missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
...
LL | let PAT = v1;
| ^^^ pattern `1_u32..=u32::MAX` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `u32`
help: introduce a variable instead
|
LL | let PAT_var = v1;
| ~~~~~~~
```
Before:
```
error[E0005]: refutable pattern in local binding
--> $DIR/bad-pattern.rs:19:13
|
LL | let PAT = v1;
| ^^^
| |
| pattern `1_u32..=u32::MAX` not covered
| missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
| help: introduce a variable instead: `PAT_var`
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `u32`
```
CC #132582.
the behavior of the type system not only depends on the current
assumptions, but also the currentnphase of the compiler. This is
mostly necessary as we need to decide whether and how to reveal
opaque types. We track this via the `TypingMode`.
After:
```
error[E0005]: refutable pattern in local binding
--> $DIR/bad-pattern.rs:19:13
|
LL | const PAT: u32 = 0;
| -------------- missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
...
LL | let PAT = v1;
| ^^^
| |
| pattern `1_u32..=u32::MAX` not covered
| help: introduce a variable instead: `PAT_var`
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `u32`
```
Before:
```
error[E0005]: refutable pattern in local binding
--> $DIR/bad-pattern.rs:19:13
|
LL | let PAT = v1;
| ^^^
| |
| pattern `1_u32..=u32::MAX` not covered
| missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
| help: introduce a variable instead: `PAT_var`
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `u32`
```
Depend on rustc_abi in compiler crates that use it indirectly but have
not yet taken on that dependency, and are not entangled in my other PRs.
This leaves an "excise rustc_target" step after the dust settles.
Replace calls to `ty::Const::{try_}eval` in mir build/pattern analysis
We normalize consts in writeback: #130645. This means that consts are gonna be as normalized as they're ever gonna get in MIR building and pattern analysis. Therefore we can just use `try_to_target_usize` rather than calling `eval_target_usize`.
Regarding the `.expect` calls, I'm not totally certain whether they're correct given rigid unevaluated consts. But this PR shouldn't make *more* ICEs occur; we may have to squash these ICEs when mGCE comes around, tho 😺
Remove `print::Pat` from the printing of `WitnessPat`
After the preliminary work done in #128536, we can now get rid of `print::Pat` entirely.
- First, we introduce a variant `PatKind::Print(String)`.
- Then we incrementally remove each other variant of `PatKind`, by having the relevant code produce `PatKind::Print` instead.
- Once `PatKind::Print` is the only remaining variant, it becomes easy to remove `print::Pat` and replace it with `String`.
There is more cleanup that I have in mind, but this seemed like a natural stopping point for one PR.
r? ```@Nadrieril```
Shrink `TyKind::FnPtr`.
By splitting the `FnSig` within `TyKind::FnPtr` into `FnSigTys` and `FnHeader`, which can be packed more efficiently. This reduces the size of the hot `TyKind` type from 32 bytes to 24 bytes on 64-bit platforms. This reduces peak memory usage by a few percent on some benchmarks. It also reduces cache misses and page faults similarly, though this doesn't translate to clear cycles or wall-time improvements on CI.
r? `@compiler-errors`
Preliminary cleanup of `WitnessPat` hoisting/printing
Follow-up to #128430.
The eventual goal is to remove `print::Pat` entirely, but in the course of working towards that I made so many small improvements that it seems wise to let those be reviewed/merged on their own first.
Best reviewed commit-by-commit, most of which should be pretty simple and straightforward.
r? ``@Nadrieril``
By splitting the `FnSig` within `TyKind::FnPtr` into `FnSigTys` and
`FnHeader`, which can be packed more efficiently. This reduces the size
of the hot `TyKind` type from 32 bytes to 24 bytes on 64-bit platforms.
This reduces peak memory usage by a few percent on some benchmarks. It
also reduces cache misses and page faults similarly, though this doesn't
translate to clear cycles or wall-time improvements on CI.
We can replace some tricky iterator-mutation code with a much simpler version
that uses `while let` to shrink a slice.
We also check whether a subpattern would be a wildcard _before_ hoisting it,
which will be very useful when trying to get rid of `print::PatKind` later.
The pattern-analysis code needs to print patterns, as part of its user-visible
diagnostics. But it never actually tries to print "real" patterns! Instead, it
only ever prints synthetic patterns that it has reconstructed from its own
internal represenations.
We can therefore simultaneously remove two obstacles to changing `thir::Pat`,
by having the pattern-analysis code use its own dedicated type for building
printable patterns, and then making `thir::Pat` not printable at all.