rust/compiler
Matthias Krüger 29314e4fca
Rollup merge of #127220 - BoxyUwU:dropck_handle_extra_impl_params, r=compiler-errors
Graciously handle `Drop` impls introducing more generic parameters than the ADT

Follow up to #110577
Fixes #126378
Fixes #126889

## Motivation

A current issue with the way we check drop impls do not specialize any of their generic parameters is that when the `Drop` impl introduces *more* generic parameters than are present on the ADT, we fail to prove any bounds involving those parameters. This can be demonstrated with the following [code on stable](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=139b65e4294634d7286a3282bc61e628) which fails due to the fact that `<T as Trait>::Assoc == U` is not present in `Foo`s `ParamEnv` even though arguably there is no reason it cannot compiler:
```rust
struct Foo<T: Trait>(T);

trait Trait {
    type Assoc;
}

impl<T: Trait<Assoc = U>, U: ?Sized> Drop for Foo<T> {
    //~^ ERROR: `Drop` impl requires `<T as Trait>::Assoc == U` but the struct ...
    fn drop(&mut self) {}
}

fn main() {}
```

I think the motivation for supporting this code is somewhat lacking, it might be useful in practice for deeply nested associated types where you might want to be able to write:
`where T: Trait<Assoc: Other<AnotherAssoc: MoreTrait<YetAnotherAssoc: InnerTrait<Final = U>>>>`
in order to be able to just use `U` in the function body instead of writing out the whole nested associated type. Regardless I don't think there is really any reason to *not* support this code and it is relatively easy to support it.

What I find slightly more compelling is the fact that when defining a const parameter `const N: u8` we desugar that to having a where clause requiring the constant `N` is typed as `u8` (`ClauseKind::ConstArgHasType`). As we *always* desugar const parameters to have these bounds, if we attempt to prove that some const parameter `N` is of type `u8` and there is no bound on `N` in the enviroment that generally indicates usage of an incorrect `ParamEnv` (this has caught a bug already).

Given that, if we write the following code:
```rust
#![feature(associated_const_equality)]
struct Foo<T: Trait>(T);

trait Trait {
    const ASSOC: usize;
}

impl<T: Trait<ASSOC = N>, const N: usize> Drop for Foo<T> {
    fn drop(&mut self) {}
}

fn main() {}
```

The `Drop` impl would have this desugared where clause about `N` being of type `usize`, and if we were to try to prove that where clause in `Foo`'s `ParamEnv` we would ICE as there would not be any `ConstArgHasType` in the environment (which generally indicates improper `ParamEnv` usage. As this is otherwise well formed code (the `T: Trait<ASSOC = N>` causes `N` to be constrained) we have to handle this *somehow* and I believe the only principled way to support this is the changes I have made to `dropck.rs` that would cause these code examples to compiler (Perhaps we could just throw out all `ConstArgHasType` where clauses from the predicates we prove but that makes me nervous even if it might actually be okay).

## The changes

Currently the way `dropck.rs` works is that take the `ParamEnv` of the ADT and instantiate it with the generic arguments used on the self ty of the `impl`. We then instantiate the predicates of the drop impl with the identity params to the impl,  e.g. in the original example `<T as Trait>::Assoc == U` stays as `<T as Trait>::Assoc == U`. We then attempt to prove all the where clauses in the instantiated env of the self type ADT.

This PR changes us to first instantiate the impl with infer vars, then we equate the self type (with infer vars as its generic arguments) with the self type as written by the user. This causes all generic parameters on the impl that are constrained via associated type/const equality bounds to be left as inference variables while all other parameters are still `Ty`/`Const`/`Region`

Finally when instantiating the predicates on the impl, instead of using the identity arguments, we use the list of inference variables of which some have been inferred to the impl parameters. In practice this means that we wind up proving `<T as Trait>::Assoc == ?x` which can succeed just fine. In the const generics example we would wind up trying to prove `ConstArgHasType(?x: usize)` instead of `ConstArgHasType(N: usize)` which avoids the ICE as it is expected to encounter goals of the form `?x: usize`.

At a higher level the way I justify/think about this is that as we are proving goals in the environment of the ADT (`Foo` in the above examples), we do not expect to encounter generic parameters from a different environment so we must "deal with them" somehow. In this PR we handle them by replacing them with inference variables as they should either *actually* be unconstrained (and we will error later) or they are constrained to be equal to some associated type/const.

To go along with this it would be nice if we were not instantiating the adt's env with the generic arguments to the ADT in the `Drop` impl as it would make it clearer we are proving bounds in the adt's env instead of the `Drop` impl's. Instead we would map the predicates on the drop impl to be valid in the environment of the adt. In practice this causes diagnostic regressions as all of the generic parameters in errors refer to the ones defined on the adt; attempting to map these back to the ones on the impl, while possible, is involved as writing a `TypeFolder` over `FulfillmentError` is non trivial.

## Edge cases

There are some subtle interactions here:

One is that we should not allow `<T as Trait>::Assoc == U` to be present on the `Drop` if `U` is constrained by the self type of the impl and the bound is not present in the ADT's environment. demonstrated with the [following code](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=af839e2c3e43e03a624825c58af84dff):
```rust
trait Trait {
    type Assoc;
}

struct Foo<T: Trait, U: ?Sized>(T, U);

impl<T: Trait<Assoc = U>, U: ?Sized> Drop for Foo<T, U> {
    //~^ ERROR: `Drop` impl requires `<T as Trait>::Assoc == U`
    fn drop(&mut self) {}
}

fn main() {}
```
This is tested at `tests/ui/dropck/constrained_by_assoc_type_equality_and_self_ty.rs`.

Another weirdness is that we permit the following code to compile now:
```rust
struct Foo<T>(T);

impl<'a, T: 'a> Drop for Foo<T> {
    fn drop(&mut self) {}
}
```
This is caused by the fact that we permit unconstrained lifetime parameters in trait implementations as long as they are not used in associated types (so we do not wind up erroring on this code like we perhaps ought to), combined with the fact that as we are now proving `T: '?x` instead of `T: 'a` which allows proving the bound via `'?x= 'empty` wheras previously it would have failed.

This is tested as part of `tests/ui/dropck/reject-specialized-drops-8142.rs`.

---

r? `@compiler-errors`
2024-07-26 00:57:21 +02:00
..
rustc The rustc crate feature is called jemalloc 2024-07-15 13:01:20 -04:00
rustc_abi Rollup merge of #127769 - compiler-errors:ed-2024-dep, r=oli-obk 2024-07-17 16:22:31 +02:00
rustc_arena Use tidy to sort crate attributes for all compiler crates. 2024-06-12 15:49:10 +10:00
rustc_ast Auto merge of #128195 - matthiaskrgr:rollup-195dfdf, r=matthiaskrgr 2024-07-25 18:05:00 +00:00
rustc_ast_ir Use dep: for crate dependencies 2024-07-15 12:40:10 -04:00
rustc_ast_lowering Gate AsyncFn* under async_closure feature 2024-07-23 19:56:06 -04:00
rustc_ast_passes Rollup merge of #127054 - compiler-errors:bound-ordering, r=fmease 2024-07-25 04:43:18 +02:00
rustc_ast_pretty centralize turning asm flags into human readable names 2024-07-24 15:27:18 +02:00
rustc_attr Use a dedicated type instead of a reference for the diagnostic context 2024-06-18 15:42:11 +00:00
rustc_baked_icu_data Use tidy to sort crate attributes for all compiler crates. 2024-06-12 15:49:10 +10:00
rustc_borrowck Don't ICE if HIR and middle types disagree in borrowck error reporting 2024-07-24 23:36:47 -04:00
rustc_builtin_macros Use Cow<'static, str> for InlineAsmTemplatePiece::String 2024-07-24 21:11:55 +01:00
rustc_codegen_cranelift Use Cow<'static, str> for InlineAsmTemplatePiece::String 2024-07-24 21:11:55 +01:00
rustc_codegen_gcc Format cg_gcc with same formatting parameters 2024-07-17 20:22:07 +02:00
rustc_codegen_llvm Auto merge of #127995 - workingjubilee:say-turings-prayer, r=BoxyUwU 2024-07-25 07:52:31 +00:00
rustc_codegen_ssa Auto merge of #127995 - workingjubilee:say-turings-prayer, r=BoxyUwU 2024-07-25 07:52:31 +00:00
rustc_const_eval Do not try to reveal hidden types when trying to prove Freeze in the defining scope 2024-07-24 16:00:48 +00:00
rustc_data_structures Use dep: for crate dependencies 2024-07-15 12:40:10 -04:00
rustc_driver Use tidy to sort crate attributes for all compiler crates. 2024-06-12 15:49:10 +10:00
rustc_driver_impl Move codegen_and_build_linker from Queries to Linker 2024-07-01 11:00:49 +00:00
rustc_error_codes Rollup merge of #126994 - Alexendoo:explain-markdown, r=tgross35 2024-07-23 19:42:35 +02:00
rustc_error_messages Use tidy to sort crate attributes for all compiler crates. 2024-06-12 15:49:10 +10:00
rustc_errors Rollup merge of #127528 - estebank:ascii-control-chars, r=oli-obk 2024-07-25 04:43:19 +02:00
rustc_expand Rollup merge of #128133 - nnethercote:fix-cfg_attr-spans, r=petrochenkov 2024-07-24 18:00:41 +02:00
rustc_feature Rollup merge of #127506 - liushuyu:s390x-target-features, r=davidtwco 2024-07-22 11:40:19 -05:00
rustc_fluent_macro Avoid ref when using format! in compiler 2024-07-19 14:52:07 -04:00
rustc_fs_util Remove useless tidy-alphabetical markers. 2024-06-20 09:23:20 +10:00
rustc_graphviz Use tidy to sort crate attributes for all compiler crates. 2024-06-12 15:49:10 +10:00
rustc_hir Rollup merge of #127717 - gurry:127441-stray-impl-sugg, r=compiler-errors 2024-07-24 22:22:16 +02:00
rustc_hir_analysis Rollup merge of #127220 - BoxyUwU:dropck_handle_extra_impl_params, r=compiler-errors 2024-07-26 00:57:21 +02:00
rustc_hir_pretty Rollup merge of #128138 - folkertdev:asm-option-allowlist, r=lcnr 2024-07-25 16:48:20 +02:00
rustc_hir_typeck Rollup merge of #128140 - veera-sivarajan:remove-ident-to-str-conversions, r=compiler-errors 2024-07-24 22:22:18 +02:00
rustc_incremental Use tidy to sort crate attributes for all compiler crates. 2024-06-12 15:49:10 +10:00
rustc_index Fix feature gating on rustc_index to not use implicit features 2024-07-15 12:44:24 -04:00
rustc_index_macros Remove usage of specialization from newtype_index! 2024-06-30 16:42:53 +00:00
rustc_infer Get rid of can_eq_shallow 2024-07-22 13:54:48 -04:00
rustc_interface Use dep: for crate dependencies 2024-07-15 12:40:10 -04:00
rustc_lexer Use tidy to sort crate attributes for all compiler crates. 2024-06-12 15:49:10 +10:00
rustc_lint Rollup merge of #121364 - Urgau:unary_precedence, r=compiler-errors 2024-07-25 16:48:17 +02:00
rustc_lint_defs Mark missing_fragment_specifier as FutureReleaseErrorReportInDeps 2024-07-24 13:16:46 -04:00
rustc_llvm Rollup merge of #124033 - bjorn3:ar_archive_writer_0_3_0, r=davidtwco 2024-07-16 16:15:13 -05:00
rustc_log Bump tracing-tree and allow rendering lines again 2024-06-12 10:11:41 +00:00
rustc_macros lift_to_tcx -> lift_to_interner 2024-07-17 10:46:10 -04:00
rustc_metadata Rollup merge of #127528 - estebank:ascii-control-chars, r=oli-obk 2024-07-25 04:43:19 +02:00
rustc_middle Rollup merge of #127717 - gurry:127441-stray-impl-sugg, r=compiler-errors 2024-07-24 22:22:16 +02:00
rustc_mir_build Turn an unreachable code path into an ICE 2024-07-25 15:33:34 +00:00
rustc_mir_dataflow Avoid ref when using format! in compiler 2024-07-19 14:52:07 -04:00
rustc_mir_transform Move all error reporting into rustc_trait_selection 2024-07-21 22:34:35 -04:00
rustc_monomorphize Move compiler_builtin check to the use case 2024-07-15 23:43:52 +00:00
rustc_next_trait_solver Use dep: for crate dependencies 2024-07-15 12:40:10 -04:00
rustc_parse Fix a span error when parsing a wrong param of function. 2024-07-25 22:33:45 +08:00
rustc_parse_format Use tidy to sort crate attributes for all compiler crates. 2024-06-12 15:49:10 +10:00
rustc_passes Rollup merge of #128138 - folkertdev:asm-option-allowlist, r=lcnr 2024-07-25 16:48:20 +02:00
rustc_pattern_analysis Auto merge of #128015 - Nadrieril:two-step-or-expansion, r=compiler-errors 2024-07-23 06:35:42 +00:00
rustc_privacy Do not ICE in privacy when type inference fails. 2024-06-17 10:09:27 +00:00
rustc_query_impl Allow tracing through item_bounds query invocations on opaques 2024-06-19 08:47:55 +00:00
rustc_query_system Be more accurate about calculating display_col from a BytePos 2024-07-18 20:08:38 +00:00
rustc_resolve Do not use question as label 2024-07-24 21:03:27 +00:00
rustc_sanitizers Rollup merge of #127980 - nyurik:compiler-refs, r=oli-obk 2024-07-20 07:13:45 +02:00
rustc_serialize chore: remove duplicate words 2024-07-02 11:25:31 +08:00
rustc_session Auto merge of #127670 - compiler-errors:no-type-length-limit, r=jackh726 2024-07-14 12:44:07 +00:00
rustc_smir Avoid comments that describe multiple use items. 2024-07-17 08:02:46 +10:00
rustc_span Rollup merge of #127528 - estebank:ascii-control-chars, r=oli-obk 2024-07-25 04:43:19 +02:00
rustc_symbol_mangling Fix FnMut/Fn shim for coroutine-closures that capture references 2024-06-29 17:38:02 -04:00
rustc_target Auto merge of #127755 - no1wudi:master, r=michaelwoerister 2024-07-23 09:45:28 +00:00
rustc_trait_selection Rollup merge of #126090 - compiler-errors:supertrait-assoc-ty-unsoundness, r=lcnr 2024-07-26 00:57:20 +02:00
rustc_traits Move all error reporting into rustc_trait_selection 2024-07-21 22:34:35 -04:00
rustc_transmute Use dep: for crate dependencies 2024-07-15 12:40:10 -04:00
rustc_ty_utils Make sure that args are compatible in resolve_associated_item 2024-07-24 22:59:57 -04:00
rustc_type_ir Avoid ref when using format! in compiler 2024-07-19 14:52:07 -04:00
rustc_type_ir_macros lift_to_tcx -> lift_to_interner 2024-07-17 10:46:10 -04:00
stable_mir Auto merge of #126963 - runtimeverification:smir_serde_derive, r=celinval 2024-07-25 20:27:51 +00:00