rust/compiler
Trevor Gross ceae37188b
Rollup merge of #126575 - fmease:update-lint-type_alias_bounds, r=compiler-errors
Make it crystal clear what lint `type_alias_bounds` actually signifies

This is part of my work on https://github.com/rust-lang/rust/labels/F-lazy_type_alias ([tracking issue](#112792)).

---

To recap, the lint `type_alias_bounds` detects bounds on generic parameters and where clauses on (eager) type aliases. These bounds should've never been allowed because they are currently neither enforced[^1] at usage sites of type aliases nor thoroughly checked for correctness at definition sites due to the way type aliases are represented in the compiler. Allowing them was an oversight.

Explicitly label this as a known limitation of the type checker/system and establish the experimental feature `lazy_type_alias` as its eventual proper solution.

Where this becomes a bit tricky (for me as a rustc dev) are the "secondary effects" of these bounds whose existence I sadly can't deny. As a matter of fact, type alias bounds do play some small roles during type checking. However, after a lot of thinking over the last two weeks I've come to the conclusion (not without second-guessing myself though) that these use cases should not trump the fact that these bounds are currently *inherently broken*. Therefore the lint `type_alias_bounds` should and will continue to flag bounds that may have subordinate uses.

The two *known* secondary effects are:

1. They may enable the use of "shorthand" associated type paths `T::Assoc` (as opposed to fully qualified paths `<T as Trait>::Assoc`) where `T` is a type param bounded by some trait `Trait` which defines that assoc ty.
2. They may affect the default lifetime of trait object types passed as a type argument to the type alias. That concept is called (trait) object lifetime default.

The second one is negligible, no question asked. The first one however is actually "kinda nice" (for writability) and comes up in practice from time to time.

So why don't I just special-case trait bounds that "define" shorthand assoc type paths as originally planned in #125709?

1. Starting to permit even a tiny subset of bounds would already be enough to send a signal to users that bounds in type aliases have been legitimized and that they can expect to see type alias bounds in the wild from now on (proliferation). This would be actively misleading and dangerous because those bounds don't behave at all like one would expect, they are *not real*[^2]!
   1. Let's take `type A<T: Trait> = T::Proj;` for example. Everywhere else in the language `T: Trait` means `T: Trait + Sized`. For type aliases, that's not the case though: `T: Trait` and `T: Trait + ?Sized` for that matter do neither mean `T: Trait + Sized` nor `T: Trait + ?Sized` (for both!). Instead, whether `T` requires `Sized` or not entirely depends on the definition of `Trait`[^2]. Namely, whether or not it is bounded by `Sized`.
   2. Given `type A<T: Trait<AssocA = ()>> = T::AssocB;`, while `X: Trait` gets checked given `A<X>` (by virtue of projection wfchecking post alias expansion[^2]), the associated type constraint `AssocA = ()` gets dropped entirely! While we could choose to warn on such cases, it would inevitably lead to a huge pile of special cases.
   3. While it's common knowledge that the body / aliased type / RHS of an (eager) type alias does not get checked for well-formedness, I'm not sure if people would realize that that extends to bounds as well. Namely, `type A<T: Trait<[u8]>> = T::Proj;` compiles even if `Trait`'s generic parameter requires `Sized`. Of course, at usage sites `[u8]: Sized` would still end up getting checked[^2], so it's not a huge problem if you have full control over `A`. However, imagine that `A` was actually part of a public API and was never used inside the defining crate (not unreasonable). In such a scenario, downstream users would be presented with an impossible to use type alias! Remember, bounds may grow arbitrarily complex and nuanced in practice.
   4. Even if we allowed trait bounds that "define" shorthand assoc type paths, we would still need to continue to warn in cases where the assoc ty comes from a supertrait despite the fact that the shorthand syntax can be used: `type A<T: Sub> = T::Assoc;` does compile given `trait Sub: Super {}` and `trait Super { type Assoc; }`. However, `A<X>` does not enforce `X: Sub`, only `X: Super`[^2]. All that to say, type alias bounds are simply not real and we shouldn't pretend they are!
   5. Summarizing the points above, we would be legitimizing bounds that are completely broken!
2. It's infeasible to implement: Due to the lack of `TypeckResults` in `ItemCtxt` (and a way to propagate it to other parts of the compiler), the resolution of type-dependent paths in non-`Body` items (most notably type aliases) is not recoverable from the HIR alone which would be necessary because the information of whether an associated type path (projection) is a shorthand is only present pre&in-HIR and doesn't survive HIR ty lowering. Of course, I could rerun parts of HIR ty lowering inside the lint `type_alias_bounds` (namely, `probe_single_ty_param_bound_for_assoc_ty` which would need to be exposed or alternatively a stripped-down version of it). This likely has a performance impact and introduces complexity. In short, the "benefits" are not worth the costs.

---

* 3rd commit: Update a diagnostic to avoid suggesting type alias bounds
* 4th commit: Flag type alias bounds even if the RHS contains inherent associated types.
  * I started to allow them at some point in the past which was not correct (see commit for details)
* 5th commit: Allow type alias bounds if the RHS contains const projections and GCEs are enabled
  * (and add a `FIXME(generic_const_exprs)` to be revisited before (M)GCE's stabilization)
  * As a matter of fact type alias bounds are enforced in this case because the contained AnonConsts do get checked for well-formedness and crucially they inherit the generics and predicates of their parent item (here: the type alias)
* Remaining commits: Improve the lint `type_alias_bounds` itself

---

Fixes #125789 (sugg diag fix).
Fixes #125709 (wontfix, acknowledgement, sugg diag applic fix).
Fixes #104918 (sugg diag applic fix).
Fixes #100270 (wontfix, acknowledgement, sugg diag applic fix).
Fixes #94398 (true fix).

r? `@compiler-errors` `@oli-obk`

[^1]: From the perspective of the trait solver.
[^2]: Given `type A<T: Trait> = T::Proj;`, the reason why the trait bound "`T: Trait`" gets *seemingly* enforced at usage sites of the type alias `A` is simply because `A<X>` gets expanded to "`<X as Trait>::Proj`" very early on and it's the *expansion* that gets checked for well-formedness, not the type alias reference.
2024-07-26 02:20:28 -04: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 LLVM: LLVM-20.0 removes MMX types 2024-07-25 17:58:37 +00:00
rustc_codegen_ssa LLVM: LLVM-20.0 removes MMX types 2024-07-25 17:58:37 +00:00
rustc_const_eval Rollup merge of #127950 - nnethercote:rustfmt-skip-on-use-decls, r=cuviper 2024-07-26 00:57:21 +02: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 #126575 - fmease:update-lint-type_alias_bounds, r=compiler-errors 2024-07-26 02:20:28 -04: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 #126575 - fmease:update-lint-type_alias_bounds, r=compiler-errors 2024-07-26 02:20:28 -04:00
rustc_lint_defs Mark missing_fragment_specifier as FutureReleaseErrorReportInDeps 2024-07-24 13:16:46 -04:00
rustc_llvm LLVM: LLVM-20.0 removes MMX types 2024-07-25 17:58:37 +00: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 Auto merge of #127042 - GrigorenkoPV:derivative, r=compiler-errors 2024-07-25 22:50:58 +00:00
rustc_mir_build Rollup merge of #128085 - Zalathar:notes, r=Nadrieril 2024-07-26 00:57:22 +02: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 Auto merge of #127042 - GrigorenkoPV:derivative, r=compiler-errors 2024-07-25 22:50:58 +00: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 Auto merge of #127042 - GrigorenkoPV:derivative, r=compiler-errors 2024-07-25 22:50:58 +00: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 Rollup merge of #126575 - fmease:update-lint-type_alias_bounds, r=compiler-errors 2024-07-26 02:20:28 -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