Forbid usage of `hir` `Infer` const/ty variants in ambiguous contexts
The feature `generic_arg_infer` allows providing `_` as an argument to const generics in order to infer them. This introduces a syntactic ambiguity as to whether generic arguments are type or const arguments. In order to get around this we introduced a fourth `GenericArg` variant, `Infer` used to represent `_` as an argument to generic parameters when we don't know if its a type or a const argument.
This made hir visitors that care about `TyKind::Infer` or `ConstArgKind::Infer` very error prone as checking for `TyKind::Infer`s in `visit_ty` would find *some* type infer arguments but not *all* of them as they would sometimes be lowered to `GenericArg::Infer` instead.
Additionally the `visit_infer` method would previously only visit `GenericArg::Infer` not *all* infers (e.g. `TyKind::Infer`), this made it very easy to override `visit_infer` and expect it to visit all infers when in reality it would only visit *some* infers.
---
This PR aims to fix those issues by making the `TyKind` and `ConstArgKind` types generic over whether the infer types/consts are represented by `Ty/ConstArgKind::Infer` or out of line (e.g. by a `GenericArg::Infer` or accessible by overiding `visit_infer`). We then make HIR Visitors convert all const args and types to the versions where infer vars are stored out of line and call `visit_infer` in cases where a `Ty`/`Const` would previously have had a `Ty/ConstArgKind::Infer` variant:
API Summary
```rust
enum AmbigArg {}
enum Ty/ConstArgKind<Unambig = ()> {
...
Infer(Unambig),
}
impl Ty/ConstArg {
fn try_as_ambig_ty/ct(self) -> Option<Ty/ConstArg<AmbigArg>>;
}
impl Ty/ConstArg<AmbigArg> {
fn as_unambig_ty/ct(self) -> Ty/ConstArg;
}
enum InferKind {
Ty(Ty),
Const(ConstArg),
Ambig(InferArg),
}
trait Visitor {
...
fn visit_ty/const_arg(&mut self, Ty/ConstArg<AmbigArg>) -> Self::Result;
fn visit_infer(&mut self, id: HirId, sp: Span, kind: InferKind) -> Self::Result;
}
// blanket impl'd, not meant to be overriden
trait VisitorExt {
fn visit_ty/const_arg_unambig(&mut self, Ty/ConstArg) -> Self::Result;
}
fn walk_unambig_ty/const_arg(&mut V, Ty/ConstArg) -> Self::Result;
fn walk_ty/const_arg(&mut V, Ty/ConstArg<AmbigArg>) -> Self::Result;
```
The end result is that `visit_infer` visits *all* infer args and is also the *only* way to visit an infer arg, `visit_ty` and `visit_const_arg` can now no longer encounter a `Ty/ConstArgKind::Infer`. Representing this in the type system means that it is now very difficult to mess things up, either accessing `TyKind::Infer` "just works" and you won't miss *some* type infers- or it doesn't work and you have to look at `visit_infer` or some `GenericArg::Infer` which forces you to think about the full complexity involved.
Unfortunately there is no lint right now about explicitly matching on uninhabited variants, I can't find the context for why this is the case 🤷♀️
I'm not convinced the framing of un/ambig ty/consts is necessarily the right one but I'm not sure what would be better. I somewhat like calling them full/partial types based on the fact that `Ty<Partial>`/`Ty<Full>` directly specifies how many of the type kinds are actually represented compared to `Ty<Ambig>` which which leaves that to the reader to figure out based on the logical consequences of it the type being in an ambiguous position.
---
tool changes have been modified in their own commits for easier reviewing by anyone getting cc'd from subtree changes. I also attempted to split out "bug fixes arising from the refactoring" into their own commit so they arent lumped in with a big general refactor commit
Fixes#112110
Rollup of 8 pull requests
Successful merges:
- #133605 (Add extensive set of drop order tests)
- #135489 (remove pointless allowed_through_unstable_modules on TryFromSliceError)
- #135757 (Add NuttX support for AArch64 and ARMv7-A targets)
- #135799 (rustdoc-json: Rename `Path::name` to `path`, and give it the path again.)
- #135865 (For E0223, suggest associated functions that are similar to the path, even if the base type has multiple inherent impl blocks.)
- #135890 (Implement `VecDeque::pop_front_if` & `VecDeque::pop_back_if`)
- #135914 (Remove usages of `QueryNormalizer` in the compiler)
- #135936 (fix reify-intrinsic test)
r? `@ghost`
`@rustbot` modify labels: rollup
Remove usages of `QueryNormalizer` in the compiler
I want to get rid of the `QueryNormalizer`, possibly changing it to be special cased just for normalizing erasing regions, or perhaps adapting `normalize_erasing_regions` to use the assoc type normalizer if caching is sufficient and removing it altogther.
This removes the last two usages of `.query_normalize` in the *compiler*. There are a few usages left in rustdoc and clippy, which exist only because the query normalizer is more resilient to errors and non-well-formed alias types. I will remove those next.
r? lcnr or reassign
For E0223, suggest associated functions that are similar to the path, even if the base type has multiple inherent impl blocks.
Currently, the "help: there is an associated function with a similar name `from_utf8`" suggestion for `String::from::utf8` is only given if `String` has exactly one inherent `impl` item. This PR makes the suggestion be emitted even if the base type has multiple inherent `impl` items.
Example:
```rust
struct Foo;
impl Foo {
fn bar_baz() {}
}
impl Foo {} // load-bearing
fn main() {
Foo::bar::baz;
}
```
Nightly/stable output:
```rust
error[E0223]: ambiguous associated type
--> f.rs:7:5
|
7 | Foo::bar::baz;
| ^^^^^^^^
|
help: if there were a trait named `Example` with associated type `bar` implemented for `Foo`, you could use the fully-qualified path
|
7 | <Foo as Example>::bar::baz;
| ~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0223`.
```
Output with this PR, or without the load-bearing empty impl on nightly/stable:
```rust
error[E0223]: ambiguous associated type
--> f.rs:7:5
|
7 | Foo::bar::baz;
| ^^^^^^^^
|
help: there is an associated function with a similar name: `bar_baz`
|
7 | Foo::bar_baz;
| ~~~~~~~
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0223`.
```
Ideally, this suggestion would also work for non-ADT types like ~~`str::char::indices`~~ (edit: latest commit makes this work with primitives) or `<dyn Any>::downcast::mut_unchecked`, but that seemed to be a harder change.
`@rustbot` label +A-diagnostics
Add NuttX support for AArch64 and ARMv7-A targets
This patch adds tier 3 support for AArch64 and ARMv7-A targets in NuttX, including:
- AArch64 target: aarch64-unknown-nuttx
- ARMv7-A target: armv7a-nuttx-eabi, armv7a-nuttx-eabihf
- Thumbv7-A target: thumbv7a-nuttx-eabi, thumbv7a-nuttx-eabihf
Rollup of 7 pull requests
Successful merges:
- #135366 (Enable `unreachable_pub` lint in `test` and `proc_macro` crates)
- #135638 (Make it possible to build GCC on CI)
- #135648 (support wasm inline assembly in `naked_asm!`)
- #135827 (CI: free disk with in-tree script instead of GitHub Action)
- #135855 (Only assert the `Parser` size on specific arches)
- #135878 (ci: use 8 core arm runner for dist-aarch64-linux)
- #135905 (Enable kernel sanitizers for aarch64-unknown-none-softfloat)
r? `@ghost`
`@rustbot` modify labels: rollup
Skip `if-let-rescope` lint unless requested by migration
Tracked by #124085
Related to https://github.com/rust-lang/rust/pull/131984#issuecomment-2448329667
Given that `if-let-rescope` is a lint to be enabled globally by an edition migration, there is no point in extracting the precise lint level on the HIR expression. This mitigates the performance regression discovered by the earlier perf-run.
cc `@Kobzol` `@rylev` `@traviscross` I propose a `rust-timer` run to measure how much performance that we can recover from the mitigation. 🙇
Enable kernel sanitizers for aarch64-unknown-none-softfloat
We want kernels to be able to use this bare metal target, so let's enable the sanitizers that kernels want to use.
cc ```@rcvalle``` ```@ojeda``` ```@maurer```
Only assert the `Parser` size on specific arches
The size of this struct depends on the alignment of `u128`, for example
powerpc64le and s390x have align-8 and end up with only 280 bytes. Our
64-bit tier-1 arches are the same though, so let's just assert on those.
r? nnethercote
support wasm inline assembly in `naked_asm!`
fixes https://github.com/rust-lang/rust/issues/135518
Webassembly was overlooked previously, but now `naked_asm!` and `#[naked]` functions work on the webassembly targets.
Or, they almost do right now. I guess this is no surprise, but the `wasm32-unknown-unknown` target causes me some trouble. I'll add some inline comments with more details.
r? ```````@bjorn3```````
cc ```````@daxpedda,``````` ```````@tgross35```````
Allow `arena_cache` queries to return `Option<&'tcx T>`
Currently, `arena_cache` queries always have to return `&'tcx T`[^deref]. This means that if an arena-cached query wants to return an optional value, it has to return `&'tcx Option<T>`, which has a few negative consequences:
- It goes against normal Rust style, where `Option<&T>` is preferred over `&Option<T>`.
- Callers that actually want an `Option<&T>` have to manually call `.as_ref()` on the query result.
- When the query result is `None`, a full-sized `Option<T>` still needs to be stored in the arena.
This PR solves that problem by introducing a helper trait `ArenaCached` that is implemented for both `&T` and `Option<&T>`, and takes care of bridging between the provided type, the arena-allocated type, and the declared query return type.
---
To demonstrate that this works, I have converted the two existing arena-cached queries that currently return `&Option<T>`: `mir_coroutine_witnesses` and `diagnostic_hir_wf_check`. Only the query declarations need to be modified; existing providers and callers continue to work with the new query return type.
(My real goal is to apply this to `coverage_ids_info`, which will return Option as of #135873, but that PR hasn't landed yet.)
[^deref]: Technically they could return other types that implement `Deref`, but it's hard to imagine this working well with anything other than `&T`.
rustc_codegen_llvm: remove outdated asm-to-obj codegen note
Remove comment about missing integrated assembler handling, which was removed in commit 02840ca.
Get rid of RunCompiler
The various `set_*` methods that have been removed can be replaced by setting the respective fields in the `Callbacks::config` implementation. `set_using_internal_features` was often forgotten and it's equivalent is now done automatically.
handle global trait bounds defining assoc types
This also fixes the compare-mode for
- tests/ui/coherence/coherent-due-to-fulfill.rs
- tests/ui/codegen/mono-impossible-2.rs
- tests/ui/trivial-bounds/trivial-bounds-inconsistent-projection.rs
- tests/ui/nll/issue-61320-normalize.rs
I first considered the alternative to always prefer where-bounds during normalization, regardless of how the trait goal has been proven by changing `fn merge_candidates` instead. ecda83b30f/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs (L785)
This approach is more restrictive than behavior of the old solver to avoid mismatches between trait and normalization goals. This may be breaking in case the where-bound adds unnecessary region constraints and we currently don't ever try to normalize an associated type. I would like to detect these cases and change the approach to exactly match the old solver if required. I want to minimize cases where attempting to normalize in more places causes code to break.
r? `@compiler-errors`
Add missing check for async body when suggesting await on futures.
Currently the compiler suggests adding `.await` to resolve some type conflicts without checking if the conflict happens in an async context. This can lead to the compiler suggesting `.await` in function signatures where it is invalid. Example:
```rs
trait A {
fn a() -> impl Future<Output = ()>;
}
struct B;
impl A for B {
fn a() -> impl Future<Output = impl Future<Output = ()>> {
async { async { () } }
}
}
```
```
error[E0271]: expected `impl Future<Output = impl Future<Output = ()>>` to be a future that resolves to `()`, but it resolves to `impl Future<Output = ()>`
--> bug.rs:6:15
|
6 | fn a() -> impl Future<Output = impl Future<Output = ()>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found future
|
note: calling an async function returns a future
--> bug.rs:6:15
|
6 | fn a() -> impl Future<Output = impl Future<Output = ()>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `A::{synthetic#0}`
--> bug.rs:2:27
|
2 | fn a() -> impl Future<Output = ()>;
| ^^^^^^^^^^^ required by this bound in `A::{synthetic#0}`
help: consider `await`ing on the `Future`
|
6 | fn a() -> impl Future<Output = impl Future<Output = ()>>.await {
| ++++++
```
The documentation of suggest_await_on_expect_found (`compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs:156`) even mentions such a check but does not actually implement it.
This PR adds that check to ensure `.await` is only suggested within async blocks.
There were 3 unit tests whose expected output needed to be changed because they had the suggestion outside of async. One of them (`tests/ui/async-await/dont-suggest-missing-await.rs`) actually tests that exact problem but expects it to be present.
Thanks to `@llenck` for initially noticing the bug and helping with fixing it
Update windows-gnu targets to set `DebuginfoKind::DWARF`
These targets have always used DWARF debuginfo and not CodeView/PDB debuginfo like the MSVC Windows targets. However, their target definitions claim to use `DebuginfoKind::PDB` probably to ensure that we do not try to allow the use of split-DWARF debuginfo.
This does not appear to be necessary since the targets set their supported split debug info to `Off`. I've looked at all of the uses of these properties and this patch does not appear to cause any functional changes in compiler behavior. I also added UI tests to attempt to validate there is no change in the behavior of these options on stable compilers.
cc ````@mati865```` since you mentioned this in #135739
cc ````@davidtwco```` for split-dwarf
[AIX] Lint on structs that have a different alignment in AIX's C ABI
This PR adds a linting diagnostic on AIX for repr(C) structs that are required to follow
the power alignment rule. A repr(C) struct needs to follow the power alignment rule if
the struct:
- Has a floating-point data type (greater than 4-bytes) as its first member, or
- The first member of the struct is an aggregate, whose recursively first member is a
floating-point data type (greater than 4-bytes).
The power alignment rule for eligible structs is currently unimplemented, so a linting
diagnostic is produced when such a struct is encountered.
Always lower to `GenericArg::Infer`
Update `PlaceholderCollector`
Update closure lifetime binder infer var visitor
Fallback visitor handle ambig infer args
Ensure type infer args have their type recorded
Misc. `rustc_resolve` cleanups
Hopefully this PR should make `rustc_resolve` a bit cleaner.
Each commit here stands on its own. I tried to only include changes that are easy to review, and are a clear improvement. (but I'll be happy to revert any changes that turn out to be more controversial than I'd thought)
Best viewed with whitespace ignored 😁 (especially [these two commits](a93616acf3..ae87d005bc?diff=unified&w=1))
Detect missing fields with default values and suggest `..`
When a struct ctor use has missing fields, if all those missing fields have defaults, suggest `..`:
```
error[E0063]: missing fields `field1` and `field2` in initializer of `S`
--> $DIR/non-exhaustive-ctor.rs:16:13
|
LL | let _ = S { field: () };
| ^ missing `field1` and `field2`
|
help: all remaining fields have default values, you can use those values with `..`
|
LL | let _ = S { field: (), .. };
| ++++
```
Properly note when query stack is being cut off
cc #70953
also, i'm not certain whether we should even limit this at all. i don't see the problem with printing the full query stack, apparently it was limited b/c we used to ICE? but we're already printing the full stack to disk since #108714.
r? oli-obk
Point at invalid utf-8 span on user's source code
```
error: couldn't read `$DIR/not-utf8-bin-file.rs`: stream did not contain valid UTF-8
--> $DIR/not-utf8-2.rs:6:5
|
LL | include!("not-utf8-bin-file.rs");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: byte `193` is not valid utf-8
--> $DIR/not-utf8-bin-file.rs:2:14
|
LL | let _ = "�|�␂!5�cc␕␂��";
| ^
= note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
```
When we attempt to load a Rust source code file, if there is a OS file failure we try reading the file as bytes. If that succeeds we try to turn it into UTF-8. If *that* fails, we provide additional context about *where* the file has the first invalid UTF-8 character.
Fix#76869.
Fix ICE-133117: multiple never-pattern arm doesn't have false_edge_start_block
Fixes#133117 , and close fixes#133063 , fixes#130779
In order to fix ICE-133117, at first I needed to tackle to ICE-133063 (this fixed 130779 as well).
### ICE-133063 and ICE-130779
This ICE is caused by those steps:
1. An arm has or-pattern, and all of the sub-candidates are never-pattern
2. In that case, all sub-candidates are removed in remove_never_subcandidates(). So the arm (candidate) has no sub-candidate.
3. In the current implementation, if there is no sub-candidate, the function assigns `pre_binding_block` into the candidate ([here](https://github.com/rust-lang/rust/blob/master/compiler/rustc_mir_build/src/builder/matches/mod.rs#L2002-L2004)). However, otherwise_block should be assigned to the candidate as well, because the otherwise_block is unwrapped in multiple place (like in lower_match_tree()). As a result, it causes the panic.
I simply added the same block as pre_binding_block into otherwise_block, but I'm wondering if there is a better block to assign to otherwise_block (is it ok to assign the same block into pre_binding and otherwise?)
### ICE-133117
This is caused by those steps:
1. There are two arms, both are or-pattern and each has one match-pair (in the test code, both are `(!|!)`), and the second arm has a guard.
2. In match_candidate() for the first arm, it expands the second arm’s sub-candidates as well ([here](https://github.com/rust-lang/rust/blob/master/compiler/rustc_mir_build/src/builder/matches/mod.rs#L1800-L1805)). As a result, the root candidate of the second arm is not evaluated/modified in match_candidate(). So a false_edge_start_block is not assigned to the candidate.
3. merge_trivial_subcandidates() is called against the candidate for the second arm. It just returns immediately because the candidate has a guard. So a flase_edge_start_block is not assigned to the candidate also in this function.
4. remove_never_subcandidates() is called against the candidate. Since all sub-candidates are never-pattern. they are removed.
5. In lower_match_tree(), since there is no sub-candidate for the candidate, the candidate itself is evaluated in visit_leave_rev ([here](https://github.com/rust-lang/rust/blob/master/compiler/rustc_mir_build/src/builder/matches/mod.rs#L1532)). Because the candidate has no false_edge_start_block, it causes the panic.
So I modified the order of if blocks in merge_trivial_subcandidates() to assign a false_edge_start_block if the candidate doesn't have.