Prune dead regionck code
We never encounter `ObligationCauseCode`s that correspond to region obligations that originate from "within" a body, since we don't do HIR regionck anymore on bodies. So prune some dead code.
fix ICE in layout computation with unnormalizable const
The first commit reverts half of 7a667d206c, where I removed a case from `layout_of` for handling non-generic unevaluated consts in array length, that I incorrectly assumed to be unreachable. This can actually happen with the combination of `feature(generic_const_exprs)` and `feature(trivial_bounds)`, because GCE makes anon consts inherit their parent's predicates and with an impossible predicate like `u8: A` it's possible to have an array whose length is an associated const like `<u8 as A>::B` that is not generic, but also can't be normalized:
```rust
#![feature(generic_const_exprs)]
#![feature(trivial_bounds)]
trait A {
const B: usize;
}
// With GCE + trivial bounds this definition is not a compile error.
// Computing the layout of this type shouldn't ICE.
struct S([u8; <u8 as A>::B])
where
u8: A;
```
---
The first commit also incidentally fixes https://github.com/rust-lang/rust/issues/137308, which also managed to get an unnormalizable assoc const into an array length:
```rust
trait A {
const B: usize;
}
impl<C: ?Sized> A for u8 { //~ ERROR: the type parameter `C` is not constrained
const B: usize = 42;
}
// Computing the layout of this type shouldn't ICE, even with the compile error above.
struct S([u8; <u8 as A>::B]);
```
This happens, because we bail out from `codegen_select_candidate` with an error if the selected impl has unconstrained params to avoid leaking infer vars out of a query. `Instance::try_resolve` will then return `Ok(None)`, which for assoc consts roughly means "this const can't be evaluated in a generic context" and is treated as such: 71e06b9c59/compiler/rustc_middle/src/mir/interpret/queries.rs (L84) (and this can ICE if the const isn't generic: https://github.com/rust-lang/rust/issues/135617).
However, here `<u8 as A>::B` is definitely not "too generic" and also not unresolvable due to an unsatisfiable `u8: A` bound, so I've included the second commit to change the result of `Instance::try_resolve` from `Ok(None)` to `Err(ErrorGuaranteed)` when resolving an assoc item to an impl with unconstrained generic params. This has the effect that `<u8 as A>::B` will now be normalized to `ConstKind::Error` in the example above.
This properly fixes https://github.com/rust-lang/rust/issues/137308, by no longer treating `<u8 as A>::B` as unresolvable even though it clearly has a unique impl that it resolves to. It also has the effect of changing the layout error from `Unknown` ("the type may be valid but has no sensible layout") to `ReferencesError` ("a non-layout error is reported elsewhere") which seems more appropriate.
r? ```@compiler-errors```
Ignore fake borrows for packed field check
We should not emit unaligned packed field reference errors for the fake borrows that we generate during match lowering.
These fake borrows are there to ensure in *borrow-checking* that we don't modify the value being matched (which is why this only occurs when there's a match guard, in this case `if true`), but they are removed after the MIR is processed by `CleanupPostBorrowck`, since they're really just there to cause borrowck errors if necessary.
I modified `PlaceContext::is_borrow` since that's used by the packed field check:
17c1c329a5/compiler/rustc_mir_transform/src/check_packed_ref.rs (L40)
It's only used in one other place, in the SROA optimization (by which fake borrows are removed, so it doesn't matter):
17c1c329a5/compiler/rustc_mir_dataflow/src/value_analysis.rs (L922)
Fixes https://github.com/rust-lang/rust/issues/137250
Do not deduplicate list of associated types provided by dyn principal
## Background
The way that we handle a dyn trait type's projection bounds is very *structural* today. A dyn trait is represented as a list of `PolyExistentialPredicate`s, which in most cases will be a principal trait (like `Iterator`) and a list of projections (like `Item = u32`). Importantly, the list of projections comes from user-written associated type bounds on the type *and* from elaborating the projections from the principal's supertraits.
For example, given a set of traits like:
```rust
trait Foo<T> {
type Assoc;
}
trait Bar<A, B>: Foo<A, Assoc = A> + Foo<B, Assoc = B> {}
```
For the type `dyn Bar<i32, u32>`, the list of projections will be something like `[Foo<i32>::Assoc = i32, Foo<u32>::Assoc = u32]`. We deduplicate these projections when they're identical, so for `dyn Bar<(), ()>` would be something like `[Foo<()>::Assoc = ()]`.
## Shortcomings 1: inference
We face problems when we begin to mix this structural notion of projection bounds with inference and associated type normalization. For example, let's try calling a generic function that takes `dyn Bar<A, B>` with a value of type `dyn Bar<(), ()>`:
```rust
trait Foo<T> {
type Assoc;
}
trait Bar<A, B>: Foo<A, Assoc = A> + Foo<B, Assoc = B> {}
fn call_bar<A, B>(_: &dyn Bar<A, B>) {}
fn test(x: &dyn Bar<(), ()>) {
call_bar(x);
// ^ ERROR mismatched types
}
```
```
error[E0308]: mismatched types
--> /home/mgx/test.rs:10:14
|
10 | call_bar(x);
| -------- ^ expected trait `Bar<_, _>`, found trait `Bar<(), ()>`
```
What's going on here? Well, when calling `call_bar`, the generic signature `&dyn Bar<?A, ?B>` does not unify with `&dyn Bar<(), ()>` because the list of projections differ -- `[Foo<?A>::Assoc = ?A, Foo<?B>::Assoc = ?B]` vs `[Foo<()>::Assoc = ()]`.
A simple solution to this may be to unify the principal traits first, then attempt to deduplicate them after inference. In this case, if we constrain `?A = ?B = ()`, then we would be able to deduplicate those projections in the first list.
However, this idea is still pretty fragile, and it's not a complete solution.
## Shortcomings 2: normalization
Consider a slightly modified example:
```rust
//@ compile-flags: -Znext-solver
trait Mirror {
type Assoc;
}
impl<T> Mirror for T {
type Assoc = T;
}
fn call_bar(_: &dyn Bar<(), <() as Mirror>::Assoc>) {}
fn test(x: &dyn Bar<(), ()>) {
call_bar(x);
}
```
This fails in the new solver. In this example, we try to unify `dyn Bar<(), ()>` and `dyn Bar<(), <() as Mirror>::Assoc>`. We are faced with the same problem even though there are no inference variables, and making this work relies on eagerly and deeply normalizing all projections so that they can be structurally deduplicated.
This is incompatible with how we handle associated types in the new trait solver, and while we could perhaps support it with some major gymnastics in the new solver, it suggests more fundamental shortcomings with how we deal with projection bounds in the new solver.
## Shortcomings 3: redundant projections
Consider a final example:
```rust
trait Foo {
type Assoc;
}
trait Bar: Foo<Assoc = ()> {}
fn call_bar1(_: &dyn Bar) {}
fn call_bar2(_: &dyn Bar<Assoc = ()>) {}
fn main() {
let x: &dyn Bar<Assoc = _> = todo!();
call_bar1(x);
//~^ ERROR mismatched types
call_bar2(x);
//~^ ERROR mismatched types
}
```
In this case, we have a user-written associated type bound (`Assoc = _`) which overlaps the bound that comes from the supertrait projection of `Bar` (namely, `Foo<Assoc = ()>`). In a similar way to the two examples above, this causes us to have a projection list mismatch that the compiler is not able to deduplicate.
## Solution
### Do not deduplicate after elaborating projections when lowering `dyn` types
The root cause of this issue has to do with mismatches of the deduplicated projection list before and after substitution or inference. This PR aims to avoid these issues by *never* deduplicating the projection list after elaborating the list of projections from the *identity* substituted principal trait ref.
For example,
```rust
trait Foo<T> {
type Assoc;
}
trait Bar<A, B>: Foo<A, Assoc = A> + Foo<B, Assoc = B> {}
```
When computing the projections for `dyn Bar<(), ()>`, before this PR we'd elaborate `Bar<(), ()>` to find a (deduplicated) projection list of `[Foo<()>::Assoc = ()]`.
After this PR, we take the principal trait and use its *identity* substitutions `Bar<A, B>` during elaboration, giving us projections `[Foo<A>::Assoc = A, Foo<B>::Assoc = B]`. Only after this elaboration do we substitute `A = (), B = ()` to get `[Foo<()>::Assoc = (), Foo<()>::Assoc = ()]`. This allows the type to be unified with the projections for `dyn Bar<?A, ?B>`, which are `[Foo<?A>::Assoc = ?A, Foo<?B>::Assoc = ?B]`.
This helps us avoid shorcomings 1 noted above.
### Do not deduplicate projections when relating `dyn` types
Similarly, we also do not call deduplicate when relating dyn types. This means that the list of projections does not differ depending on if the type has been normalized or not, which should avoid shortcomings 2 noted above.
Following from the example above, when relating projection lists like `[Foo<()>::Assoc = (), Foo<()>::Assoc = ()]` and `[Foo<?A>::Assoc = ?A, Foo<?B>::Assoc = ?B]`, the latter won't be deduplicated to a list of length 1 which would immediately fail to relate to the latter which is a list of length 2.
### Implement proper precedence between supertrait and user-written projection bounds when lowering `dyn` types
```rust
trait Foo {
type Assoc;
}
trait Bar: Foo<Assoc = ()> {}
```
Given a type like `dyn Foo<Assoc = _>`, we used to previously include *both* the supertrait and user-written associated type bounds in the projection list, giving us `[Foo::Assoc = (), Foo::Assoc = _]`. This would never unify with `dyn Foo`. However, this PR implements a strategy which overwrites the supertrait associated type bound with the one provided by the user, giving us a projection list of `[Foo::Assoc = _]`.
Why is this OK? Well, if a user wrote an associated type bound that is unsatisfiable (e.g. `dyn Bar<Assoc = i32>`) then the dyn type would never implement `Bar` or `Foo` anyways. If the user wrote something that is either structurally equal or equal modulo normalization to the supertrait bound, then it should be unaffected. And if the user wrote something that needs inference guidance (e.g. `dyn Bar<Assoc = _>`), then it'll be constrained when proving `dyn Bar<Assoc = _>: Bar`.
Importantly, this differs from the strategy in https://github.com/rust-lang/rust/pull/133397, which preferred the *supertrait* bound and ignored the user-written bound. While that's also theoretically justifiable in its own way, it does lead to code which does not (and probably should not) compile either today or after this PR, like:
```rust
trait IteratorOfUnit: Iterator<Item = ()> {}
impl<T> IteratorOfUnit for T where T: Iterator<Item = ()> {}
fn main() {
let iter = [()].into_iter();
let iter: &dyn IteratorOfUnit<Item = i32> = &iter;
}
```
### Conclusion
This is a far less invasive change compared to #133397, and doesn't necessarily necessitate the addition of new lints or any breakage of existing code. While we could (and possibly should) eventually introduce lints to warn users of redundant or mismatched associated type bounds, we don't *need* to do so as part of fixing this unsoundness, which leads me to believe this is a much safer solution.
Simplify `Postorder` customization.
`Postorder` has a `C: Customization<'tcx>` parameter, that gives it flexibility about how it computes successors. But in practice, there are only two `impls` of `Customization`, and one is for the unit type.
This commit simplifies things by removing the generic parameter and replacing it with an `Option`.
r? ````@saethlin````
The comments didn't make much sense to me. I asked Matthew Jasper on
Zulip about it and they said:
> I think that at the time I wanted to replace all (or most of) this
> with a reference to the HIR Id of the variable. I'll give this a look
> to see if it's still a reasonable idea, but removing the comments is
> fine.
and then:
> I don't think that changing this to an HirId would be better,
> recovering the information from the HIR seems like too much effort in
> exchange for making the MIR a little smaller.
`Postorder` has a `C: Customization<'tcx>` parameter, that gives it
flexibility about how it computes successors. But in practice, there are
only two `impls` of `Customization`, and one is for the unit type.
This commit simplifies things by removing the generic parameter and
replacing it with an `Option`.
Make fewer crates depend on `rustc_ast_ir`
I think it simplifies the crate graph and also exposes people less to confusion if downstream crates don't interact with `rustc_ast_ir` directly and instead just use its functionality reexported through more familiar paths.
r? oli-obk since you introduced ast-ir
The only visible change is to the filenames produce by `-Zdump-mir`.
E.g. before and after:
```
h.main.003-000.analysis-post-cleanup.after.mir
h.main.2-2-000.analysis-post-cleanup.after.mir
```
It also fixes a FIXME comment.
rustfmt doesn't touch it because it's a macro body, but it's large
enough that the misformatting is annoying. This commit improves it. The
most common problems fixed:
- Unnecessary multi-line patterns reduced to one line.
- Multi-line function headers adjusted so the parameter indentation
doesn't depend on the length of the function name. (This is Rust code,
not C.)
- `|` used at the start of lines, not the end.
- More consistent formatting of empty function bodies.
- Overly long lines are broken.
The `MirVisitable` trait is just a complicated way to visit either a
statement or a terminator. (And its impl for `Terminator` is unused.) It
has a single use.
This commit removes it, replacing it with an if/else, which is shorter
and simpler.
`visit_local` is the only method that doesn't call a corresponding
`super_local` method. This is valid, because `super_local` would be
empty. But it's inconsistent with every other case; we have multiple
other empty `super` methods: `super_span`, `super_ty`, etc.
This commit adds an empty `super_local` and makes `visit_local` call it.
Emit dropck normalization errors in borrowck
Borrowck generally assumes that any queries it runs for type checking will succeed, thinking that HIR typeck will have errored first if there was a problem. However as of #98641, dropck isn't run on HIR, so there's no direct guarantee that it doesn't error. While a type being well-formed might be expected to ensure that its fields are well-formed, this is not the case for types containing a type projection:
```rust
pub trait AuthUser {
type Id;
}
pub trait AuthnBackend {
type User: AuthUser;
}
pub struct AuthSession<Backend: AuthnBackend> {
data: Option<<<Backend as AuthnBackend>::User as AuthUser>::Id>,
}
pub trait Authz: Sized {
type AuthnBackend: AuthnBackend<User = Self>;
}
pub fn run_query<User: Authz>(auth: AuthSession<User::AuthnBackend>) {}
// ^ No User: AuthUser bound is required or inferred.
```
While improvements to trait solving might fix this in the future, for now we go for a pragmatic solution of emitting an error from borrowck (by rerunning dropck outside of a query) and making drop elaboration check if an error has been emitted previously before panicking for a failed normalization.
Closes#103899Closes#135039
r? `@compiler-errors` (feel free to re-assign)
Remove `rustc_middle::mir::tcx` module.
This is a really weird module. For example, what does `tcx` in `rustc_middle::mir::tcx::PlaceTy` mean? The answer is "not much".
The top-level module comment says:
> Methods for the various MIR types. These are intended for use after
> building is complete.
Awfully broad for a module that has a handful of impl blocks for some MIR types, none of which really relates to `TyCtxt`. `git blame` indicates the comment is ancient, from 2015, and made sense then.
This module is now vestigial. This commit removes it and moves all the code within into `rustc_middle::mir::statement`. Some specifics:
- `Place`, `PlaceRef`, `Rvalue`, `Operand`, `BorrowKind`: they all have `impl` blocks in both the `tcx` and `statement` modules. The commit merges the former into the latter.
- `BinOp`, `UnOp`: they only have `impl` blocks in `tcx`. The commit moves these into `statement`.
- `PlaceTy`, `RvalueInitializationState`: they are defined in `tcx`. This commit moves them into `statement` *and* makes them available in `mir::*`, like many other MIR types.
r? `@tmandry`
This is a really weird module. For example, what does `tcx` in
`rustc_middle::mir::tcx::PlaceTy` mean? The answer is "not much".
The top-level module comment says:
> Methods for the various MIR types. These are intended for use after
> building is complete.
Awfully broad for a module that has a handful of impl blocks for some
MIR types, none of which really relates to `TyCtxt`. `git blame`
indicates the comment is ancient, from 2015, and made sense then.
This module is now vestigial. This commit removes it and moves all the
code within into `rustc_middle::mir::statement`. Some specifics:
- `Place`, `PlaceRef`, `Rvalue`, `Operand`, `BorrowKind`: they all have `impl`
blocks in both the `tcx` and `statement` modules. The commit merges
the former into the latter.
- `BinOp`, `UnOp`: they only have `impl` blocks in `tcx`. The commit
moves these into `statement`.
- `PlaceTy`, `RvalueInitializationState`: they are defined in `tcx`.
This commit moves them into `statement` *and* makes them available in
`mir::*`, like many other MIR types.