From a7890c11025502e2abe8e8ec44b4b7ef1a9f3bec Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 21 Jul 2025 10:07:35 +0000 Subject: [PATCH 1/8] Trait aliases are rare large ast nodes, box them --- compiler/rustc_ast/src/ast.rs | 23 +++++++++++++------ compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 2 +- .../rustc_ast_pretty/src/pprust/state/item.rs | 5 ++-- compiler/rustc_lint/src/nonstandard_style.rs | 4 +++- compiler/rustc_parse/src/parser/item.rs | 2 +- .../rustc_resolve/src/build_reduced_graph.rs | 5 ++-- compiler/rustc_resolve/src/late.rs | 4 ++-- .../clippy/clippy_utils/src/ast_utils/mod.rs | 15 +++++++++--- src/tools/rustfmt/src/visitor.rs | 8 +++---- tests/ui/stats/input-stats.stderr | 18 +++++++-------- 11 files changed, 54 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 97e070958751a..00e8781d0f317 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3590,8 +3590,9 @@ impl Item { ItemKind::Const(i) => Some(&i.generics), ItemKind::Fn(i) => Some(&i.generics), ItemKind::TyAlias(i) => Some(&i.generics), - ItemKind::TraitAlias(_, generics, _) - | ItemKind::Enum(_, generics, _) + ItemKind::TraitAlias(i) => Some(&i.generics), + + ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _) | ItemKind::Union(_, generics, _) => Some(&generics), ItemKind::Trait(i) => Some(&i.generics), @@ -3698,6 +3699,14 @@ impl Default for FnHeader { } } +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub struct TraitAlias { + pub ident: Ident, + pub generics: Generics, + #[visitable(extra = BoundKind::Bound)] + pub bounds: GenericBounds, +} + #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct Trait { pub constness: Const, @@ -3889,7 +3898,7 @@ pub enum ItemKind { /// Trait alias. /// /// E.g., `trait Foo = Bar + Quux;`. - TraitAlias(Ident, Generics, GenericBounds), + TraitAlias(Box), /// An implementation. /// /// E.g., `impl Foo { .. }` or `impl Trait for Foo { .. }`. @@ -3922,7 +3931,7 @@ impl ItemKind { | ItemKind::Struct(ident, ..) | ItemKind::Union(ident, ..) | ItemKind::Trait(box Trait { ident, .. }) - | ItemKind::TraitAlias(ident, ..) + | ItemKind::TraitAlias(box TraitAlias { ident, .. }) | ItemKind::MacroDef(ident, _) | ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident), @@ -3979,7 +3988,7 @@ impl ItemKind { | Self::Struct(_, generics, _) | Self::Union(_, generics, _) | Self::Trait(box Trait { generics, .. }) - | Self::TraitAlias(_, generics, _) + | Self::TraitAlias(box TraitAlias { generics, .. }) | Self::Impl(box Impl { generics, .. }) => Some(generics), _ => None, } @@ -4141,8 +4150,8 @@ mod size_asserts { static_assert_size!(GenericBound, 88); static_assert_size!(Generics, 40); static_assert_size!(Impl, 136); - static_assert_size!(Item, 144); - static_assert_size!(ItemKind, 80); + static_assert_size!(Item, 136); + static_assert_size!(ItemKind, 72); static_assert_size!(LitKind, 24); static_assert_size!(Local, 96); static_assert_size!(MetaItemLit, 40); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ab15cb28fa12d..bace40f599197 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -836,7 +836,7 @@ macro_rules! common_visitor_and_walkers { visit_visitable!($($mut)? vis, impl_), ItemKind::Trait(trait_) => visit_visitable!($($mut)? vis, trait_), - ItemKind::TraitAlias(ident, generics, bounds) => { + ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds }) => { visit_visitable!($($mut)? vis, ident, generics); visit_visitable_with!($($mut)? vis, bounds, BoundKind::Bound) } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ddf01b69e7f6a..adb0046b6f729 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -444,7 +444,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items) } - ItemKind::TraitAlias(ident, generics, bounds) => { + ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds }) => { let ident = self.lower_ident(*ident); let (generics, bounds) = self.lower_generics( generics, diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 11c97a552c69f..46e5743b0a22b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -1,8 +1,7 @@ use ast::StaticItem; use itertools::{Itertools, Position}; -use rustc_ast as ast; -use rustc_ast::ModKind; use rustc_ast::ptr::P; +use rustc_ast::{self as ast, ModKind, TraitAlias}; use rustc_span::Ident; use crate::pp::BoxMarker; @@ -387,7 +386,7 @@ impl<'a> State<'a> { let empty = item.attrs.is_empty() && items.is_empty(); self.bclose(item.span, empty, cb); } - ast::ItemKind::TraitAlias(ident, generics, bounds) => { + ast::ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds }) => { let (cb, ib) = self.head(visibility_qualified(&item.vis, "trait")); self.print_ident(*ident); self.print_generic_params(&generics.params); diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index db89396d1dc23..ff8f709005f08 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -183,7 +183,9 @@ impl EarlyLintPass for NonCamelCaseTypes { ast::ItemKind::Trait(box ast::Trait { ident, .. }) => { self.check_case(cx, "trait", ident) } - ast::ItemKind::TraitAlias(ident, _, _) => self.check_case(cx, "trait alias", ident), + ast::ItemKind::TraitAlias(box ast::TraitAlias { ident, .. }) => { + self.check_case(cx, "trait alias", ident) + } // N.B. This check is only for inherent associated types, so that we don't lint against // trait impls where we should have warned for the trait definition already. diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index b767b0fcf994d..39f0f8f48384b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -928,7 +928,7 @@ impl<'a> Parser<'a> { self.psess.gated_spans.gate(sym::trait_alias, whole_span); - Ok(ItemKind::TraitAlias(ident, generics, bounds)) + Ok(ItemKind::TraitAlias(Box::new(TraitAlias { ident, generics, bounds }))) } else { // It's a normal trait. generics.where_clause = self.parse_where_clause()?; diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index fe7fa71a7fcb8..e63e1dc314247 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -11,7 +11,7 @@ use std::sync::Arc; use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind}; use rustc_ast::{ self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, Fn, ForeignItem, - ForeignItemKind, Impl, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias, + ForeignItemKind, Impl, Item, ItemKind, NodeId, StaticItem, StmtKind, TraitAlias, TyAlias, }; use rustc_attr_data_structures::{AttributeKind, MacroUseArgs}; use rustc_attr_parsing as attr; @@ -790,7 +790,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } // These items live in the type namespace. - ItemKind::TyAlias(box TyAlias { ident, .. }) | ItemKind::TraitAlias(ident, ..) => { + ItemKind::TyAlias(box TyAlias { ident, .. }) + | ItemKind::TraitAlias(box TraitAlias { ident, .. }) => { self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index a3a770502ded1..206c04e80c22c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2678,7 +2678,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); } - ItemKind::TraitAlias(_, ref generics, ref bounds) => { + ItemKind::TraitAlias(box TraitAlias { ref generics, ref bounds, .. }) => { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, @@ -5193,7 +5193,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { | ItemKind::Union(_, generics, _) | ItemKind::Impl(box Impl { generics, .. }) | ItemKind::Trait(box Trait { generics, .. }) - | ItemKind::TraitAlias(_, generics, _) => { + | ItemKind::TraitAlias(box TraitAlias { generics, .. }) => { if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind { self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs); } diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 96f0273c43969..9ae72b8aad7a7 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -470,9 +470,18 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { && over(lb, rb, eq_generic_bound) && over(lis, ris, |l, r| eq_item(l, r, eq_assoc_item_kind)) }, - (TraitAlias(li, lg, lb), TraitAlias(ri, rg, rb)) => { - eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound) - }, + ( + TraitAlias(box ast::TraitAlias { + ident: li, + generics: lg, + bounds: lb, + }), + TraitAlias(box ast::TraitAlias { + ident: ri, + generics: rg, + bounds: rb, + }), + ) => eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound), ( Impl(box ast::Impl { safety: lu, diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index f6a9a3f2cd175..f07fc8ca83bc6 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -497,14 +497,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let rw = self.with_context(|ctx| format_trait(ctx, item, block_indent)); self.push_rewrite(item.span, rw); } - ast::ItemKind::TraitAlias(ident, ref generics, ref generic_bounds) => { + ast::ItemKind::TraitAlias(ref ta) => { let shape = Shape::indented(self.block_indent, self.config); let rw = format_trait_alias( &self.get_context(), - ident, + ta.ident, &item.vis, - generics, - generic_bounds, + &ta.generics, + &ta.bounds, shape, ); self.push_rewrite(item.span, rw); diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index 72a9820bb6431..a40889ad12396 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -2,14 +2,14 @@ ast-stats ================================================================ ast-stats POST EXPANSION AST STATS: input_stats ast-stats Name Accumulated Size Count Item Size ast-stats ---------------------------------------------------------------- -ast-stats Item 1_584 (NN.N%) 11 144 -ast-stats - Enum 144 (NN.N%) 1 -ast-stats - ExternCrate 144 (NN.N%) 1 -ast-stats - ForeignMod 144 (NN.N%) 1 -ast-stats - Impl 144 (NN.N%) 1 -ast-stats - Trait 144 (NN.N%) 1 -ast-stats - Fn 288 (NN.N%) 2 -ast-stats - Use 576 (NN.N%) 4 +ast-stats Item 1_496 (NN.N%) 11 136 +ast-stats - Enum 136 (NN.N%) 1 +ast-stats - ExternCrate 136 (NN.N%) 1 +ast-stats - ForeignMod 136 (NN.N%) 1 +ast-stats - Impl 136 (NN.N%) 1 +ast-stats - Trait 136 (NN.N%) 1 +ast-stats - Fn 272 (NN.N%) 2 +ast-stats - Use 544 (NN.N%) 4 ast-stats Ty 896 (NN.N%) 14 64 ast-stats - Ptr 64 (NN.N%) 1 ast-stats - Ref 64 (NN.N%) 1 @@ -57,7 +57,7 @@ ast-stats GenericArgs 40 (NN.N%) 1 40 ast-stats - AngleBracketed 40 (NN.N%) 1 ast-stats Crate 40 (NN.N%) 1 40 ast-stats ---------------------------------------------------------------- -ast-stats Total 7_472 129 +ast-stats Total 7_384 129 ast-stats ================================================================ hir-stats ================================================================ hir-stats HIR STATS: input_stats From 6de4d4166709943dba6fc5153b918cbc26c517a0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 21 Jul 2025 10:04:10 +0000 Subject: [PATCH 2/8] Constify trait aliases --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast/src/visit.rs | 4 +- compiler/rustc_ast_lowering/src/item.rs | 5 +- .../rustc_ast_pretty/src/pprust/state/item.rs | 7 ++- compiler/rustc_hir/src/hir.rs | 10 ++-- compiler/rustc_hir/src/intravisit.rs | 2 +- .../src/collect/predicates_of.rs | 4 +- .../src/collect/resolve_bound_vars.rs | 2 +- .../src/hir_ty_lowering/bounds.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 6 ++- .../rustc_hir_typeck/src/method/suggest.rs | 2 +- compiler/rustc_parse/messages.ftl | 1 - compiler/rustc_parse/src/errors.rs | 8 ---- compiler/rustc_parse/src/parser/item.rs | 5 +- .../src/error_reporting/traits/mod.rs | 5 +- .../src/error_reporting/traits/suggestions.rs | 4 +- src/librustdoc/clean/mod.rs | 2 +- .../clippy/clippy_utils/src/ast_utils/mod.rs | 9 +++- tests/ui/consts/trait_alias.fail.stderr | 46 +++++++++++++++++++ tests/ui/consts/trait_alias.pass.stderr | 40 ++++++++++++++++ tests/ui/consts/trait_alias.rs | 31 +++++++++++++ 21 files changed, 157 insertions(+), 39 deletions(-) create mode 100644 tests/ui/consts/trait_alias.fail.stderr create mode 100644 tests/ui/consts/trait_alias.pass.stderr create mode 100644 tests/ui/consts/trait_alias.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 00e8781d0f317..8b0c3c22a8114 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3701,6 +3701,7 @@ impl Default for FnHeader { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct TraitAlias { + pub constness: Const, pub ident: Ident, pub generics: Generics, #[visitable(extra = BoundKind::Bound)] diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index bace40f599197..279ac2b7736dc 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -836,8 +836,8 @@ macro_rules! common_visitor_and_walkers { visit_visitable!($($mut)? vis, impl_), ItemKind::Trait(trait_) => visit_visitable!($($mut)? vis, trait_), - ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds }) => { - visit_visitable!($($mut)? vis, ident, generics); + ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds, constness}) => { + visit_visitable!($($mut)? vis, ident, generics, constness); visit_visitable_with!($($mut)? vis, bounds, BoundKind::Bound) } ItemKind::MacCall(m) => diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index adb0046b6f729..9522a6e0fdf02 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -444,7 +444,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items) } - ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds }) => { + ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds, constness }) => { let ident = self.lower_ident(*ident); let (generics, bounds) = self.lower_generics( generics, @@ -458,7 +458,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }, ); - hir::ItemKind::TraitAlias(ident, generics, bounds) + let constness = self.lower_constness(*constness); + hir::ItemKind::TraitAlias(constness, ident, generics, bounds) } ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => { let ident = self.lower_ident(*ident); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 46e5743b0a22b..8556a17a89746 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -386,8 +386,11 @@ impl<'a> State<'a> { let empty = item.attrs.is_empty() && items.is_empty(); self.bclose(item.span, empty, cb); } - ast::ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds }) => { - let (cb, ib) = self.head(visibility_qualified(&item.vis, "trait")); + ast::ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds, constness }) => { + let (cb, ib) = self.head(""); + self.print_visibility(&item.vis); + self.print_constness(*constness); + self.word_nbsp("trait"); self.print_ident(*ident); self.print_generic_params(&generics.params); self.nbsp(); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e83f6a1df720d..7e2cbfca3d630 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4175,8 +4175,8 @@ impl<'hir> Item<'hir> { ItemKind::Trait(constness, is_auto, safety, ident, generics, bounds, items), (*constness, *is_auto, *safety, *ident, generics, bounds, items); - expect_trait_alias, (Ident, &'hir Generics<'hir>, GenericBounds<'hir>), - ItemKind::TraitAlias(ident, generics, bounds), (*ident, generics, bounds); + expect_trait_alias, (Constness, Ident, &'hir Generics<'hir>, GenericBounds<'hir>), + ItemKind::TraitAlias(constness, ident, generics, bounds), (*constness, *ident, generics, bounds); expect_impl, &'hir Impl<'hir>, ItemKind::Impl(imp), imp; } @@ -4353,7 +4353,7 @@ pub enum ItemKind<'hir> { &'hir [TraitItemId], ), /// A trait alias. - TraitAlias(Ident, &'hir Generics<'hir>, GenericBounds<'hir>), + TraitAlias(Constness, Ident, &'hir Generics<'hir>, GenericBounds<'hir>), /// An implementation, e.g., `impl Trait for Foo { .. }`. Impl(&'hir Impl<'hir>), @@ -4396,7 +4396,7 @@ impl ItemKind<'_> { | ItemKind::Struct(ident, ..) | ItemKind::Union(ident, ..) | ItemKind::Trait(_, _, _, ident, ..) - | ItemKind::TraitAlias(ident, ..) => Some(ident), + | ItemKind::TraitAlias(_, ident, ..) => Some(ident), ItemKind::Use(_, UseKind::Glob | UseKind::ListStem) | ItemKind::ForeignMod { .. } @@ -4414,7 +4414,7 @@ impl ItemKind<'_> { | ItemKind::Struct(_, generics, _) | ItemKind::Union(_, generics, _) | ItemKind::Trait(_, _, _, _, generics, _, _) - | ItemKind::TraitAlias(_, generics, _) + | ItemKind::TraitAlias(_, _, generics, _) | ItemKind::Impl(Impl { generics, .. }) => generics, _ => return None, }) diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index f33915d5b0773..38873a4041109 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -632,7 +632,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_trait_item_ref, trait_item_refs); } - ItemKind::TraitAlias(ident, ref generics, bounds) => { + ItemKind::TraitAlias(_constness, ident, ref generics, bounds) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index cc53919626e63..297ad89b4e732 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -164,7 +164,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } } ItemKind::Trait(_, _, _, _, _, self_bounds, ..) - | ItemKind::TraitAlias(_, _, self_bounds) => { + | ItemKind::TraitAlias(_, _, _, self_bounds) => { is_trait = Some((self_bounds, item.span)); } _ => {} @@ -656,7 +656,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>( let (generics, superbounds) = match item.kind { hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits), - hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits), + hir::ItemKind::TraitAlias(_, _, generics, supertraits) => (generics, supertraits), _ => span_bug!(item.span, "super_predicates invoked on non-trait"), }; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index eb3492f5de6e7..4dc2d6b577a92 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -635,7 +635,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { | hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Union(_, generics, _) | hir::ItemKind::Trait(_, _, _, _, generics, ..) - | hir::ItemKind::TraitAlias(_, generics, ..) + | hir::ItemKind::TraitAlias(_, _, generics, ..) | hir::ItemKind::Impl(&hir::Impl { generics, .. }) => { // These kinds of items have only early-bound lifetime parameters. self.visit_early(item.hir_id(), generics, |this| intravisit::walk_item(this, item)); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index d7a827c649ddc..26965fe2ab61a 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -330,7 +330,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let (trait_generics, trait_bounds) = match parent_trait.kind { hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => (generics, supertraits), - hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits), + hir::ItemKind::TraitAlias(_, _, generics, supertraits) => (generics, supertraits), _ => unreachable!(), }; diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index bda02042aa66b..1a38e9e4efef9 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -760,8 +760,10 @@ impl<'a> State<'a> { } self.bclose(item.span, cb); } - hir::ItemKind::TraitAlias(ident, generics, bounds) => { - let (cb, ib) = self.head("trait"); + hir::ItemKind::TraitAlias(constness, ident, generics, bounds) => { + let (cb, ib) = self.head(""); + self.print_constness(constness); + self.word_nbsp("trait"); self.print_ident(ident); self.print_generic_params(generics.params); self.nbsp(); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index dbfa7e6273c85..1931876262da1 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1202,7 +1202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Node::Item(hir::Item { kind: hir::ItemKind::Trait(_, _, _, ident, ..) - | hir::ItemKind::TraitAlias(ident, ..), + | hir::ItemKind::TraitAlias(_, ident, ..), .. }) // We may also encounter unsatisfied GAT or method bounds diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 859118a4adee5..af9f873554919 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -855,7 +855,6 @@ parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern .suggestion = remove the `{$token}` parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto` -parse_trait_alias_cannot_be_const = trait aliases cannot be `const` parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe` parse_transpose_dyn_or_impl = `for<...>` expected after `{$kw}`, not before diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 4aaaba01faeb3..7f1b0991f0c89 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1961,14 +1961,6 @@ pub(crate) struct TraitAliasCannotBeAuto { pub span: Span, } -#[derive(Diagnostic)] -#[diag(parse_trait_alias_cannot_be_const)] -pub(crate) struct TraitAliasCannotBeConst { - #[primary_span] - #[label(parse_trait_alias_cannot_be_const)] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(parse_trait_alias_cannot_be_unsafe)] pub(crate) struct TraitAliasCannotBeUnsafe { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 39f0f8f48384b..4fb6a2f5687ec 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -916,9 +916,6 @@ impl<'a> Parser<'a> { self.expect_semi()?; let whole_span = lo.to(self.prev_token.span); - if let Const::Yes(_) = constness { - self.dcx().emit_err(errors::TraitAliasCannotBeConst { span: whole_span }); - } if is_auto == IsAuto::Yes { self.dcx().emit_err(errors::TraitAliasCannotBeAuto { span: whole_span }); } @@ -928,7 +925,7 @@ impl<'a> Parser<'a> { self.psess.gated_spans.gate(sym::trait_alias, whole_span); - Ok(ItemKind::TraitAlias(Box::new(TraitAlias { ident, generics, bounds }))) + Ok(ItemKind::TraitAlias(Box::new(TraitAlias { ident, generics, bounds, constness }))) } else { // It's a normal trait. generics.where_clause = self.parse_where_clause()?; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 1d8b934cef3f0..66abf39a75231 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -453,9 +453,8 @@ pub fn report_dyn_incompatibility<'tcx>( let trait_str = tcx.def_path_str(trait_def_id); let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node { hir::Node::Item(item) => match item.kind { - hir::ItemKind::Trait(_, _, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => { - Some(ident.span) - } + hir::ItemKind::Trait(_, _, _, ident, ..) + | hir::ItemKind::TraitAlias(_, ident, _, _) => Some(ident.span), _ => unreachable!(), }, _ => None, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index bf7d4257b6269..e1fa59e72518c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -360,7 +360,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Fn { generics, .. } | hir::ItemKind::TyAlias(_, generics, _) | hir::ItemKind::Const(_, generics, _, _) - | hir::ItemKind::TraitAlias(_, generics, _), + | hir::ItemKind::TraitAlias(_, _, generics, _), .. }) | hir::Node::TraitItem(hir::TraitItem { generics, .. }) @@ -420,7 +420,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Fn { generics, .. } | hir::ItemKind::TyAlias(_, generics, _) | hir::ItemKind::Const(_, generics, _, _) - | hir::ItemKind::TraitAlias(_, generics, _), + | hir::ItemKind::TraitAlias(_, _, generics, _), .. }) if !param_ty => { // Missing generic type parameter bound. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1265a39d27ba8..2296d24cde88c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2843,7 +2843,7 @@ fn clean_maybe_renamed_item<'tcx>( variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(), generics: clean_generics(generics, cx), }), - ItemKind::TraitAlias(_, generics, bounds) => TraitAliasItem(TraitAlias { + ItemKind::TraitAlias(_, _, generics, bounds) => TraitAliasItem(TraitAlias { generics: clean_generics(generics, cx), bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), }), diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 9ae72b8aad7a7..a211ac1baa357 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -475,13 +475,20 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { ident: li, generics: lg, bounds: lb, + constness: lc, }), TraitAlias(box ast::TraitAlias { ident: ri, generics: rg, bounds: rb, + constness: rc, }), - ) => eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound), + ) => { + matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No) + && eq_id(*li, *ri) + && eq_generics(lg, rg) + && over(lb, rb, eq_generic_bound) + }, ( Impl(box ast::Impl { safety: lu, diff --git a/tests/ui/consts/trait_alias.fail.stderr b/tests/ui/consts/trait_alias.fail.stderr new file mode 100644 index 0000000000000..97eb685b16a90 --- /dev/null +++ b/tests/ui/consts/trait_alias.fail.stderr @@ -0,0 +1,46 @@ +error: `[const]` is not allowed here + --> $DIR/trait_alias.rs:14:19 + | +LL | const trait Foo = [const] Bar + Baz; + | ^^^^^^^ + | + = note: this item cannot have `[const]` trait bounds + +error: `[const]` can only be applied to `const` traits + --> $DIR/trait_alias.rs:17:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^^ can't be applied to `Foo` + | +help: mark `Foo` as `const` to allow it to have `const` implementations + | +LL | #[const_trait] const trait Foo = [const] Bar + Baz; + | ++++++++++++++ + +error: `[const]` can only be applied to `const` traits + --> $DIR/trait_alias.rs:17:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^^ can't be applied to `Foo` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `const` to allow it to have `const` implementations + | +LL | #[const_trait] const trait Foo = [const] Bar + Baz; + | ++++++++++++++ + +error[E0277]: the trait bound `T: [const] Bar` is not satisfied + --> $DIR/trait_alias.rs:20:7 + | +LL | x.bar(); + | ^^^ + +error[E0277]: the trait bound `T: [const] Baz` is not satisfied + --> $DIR/trait_alias.rs:24:11 + | +LL | x.baz(); + | ^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.pass.stderr b/tests/ui/consts/trait_alias.pass.stderr new file mode 100644 index 0000000000000..00e7e2ca98c75 --- /dev/null +++ b/tests/ui/consts/trait_alias.pass.stderr @@ -0,0 +1,40 @@ +error: `[const]` is not allowed here + --> $DIR/trait_alias.rs:14:19 + | +LL | const trait Foo = [const] Bar + Baz; + | ^^^^^^^ + | + = note: this item cannot have `[const]` trait bounds + +error: `[const]` can only be applied to `const` traits + --> $DIR/trait_alias.rs:17:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^^ can't be applied to `Foo` + | +help: mark `Foo` as `const` to allow it to have `const` implementations + | +LL | #[const_trait] const trait Foo = [const] Bar + Baz; + | ++++++++++++++ + +error: `[const]` can only be applied to `const` traits + --> $DIR/trait_alias.rs:17:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^^ can't be applied to `Foo` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `const` to allow it to have `const` implementations + | +LL | #[const_trait] const trait Foo = [const] Bar + Baz; + | ++++++++++++++ + +error[E0277]: the trait bound `T: [const] Bar` is not satisfied + --> $DIR/trait_alias.rs:20:7 + | +LL | x.bar(); + | ^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.rs b/tests/ui/consts/trait_alias.rs new file mode 100644 index 0000000000000..945465de2ff8c --- /dev/null +++ b/tests/ui/consts/trait_alias.rs @@ -0,0 +1,31 @@ +#![feature(trait_alias, const_trait_impl)] +//@ revisions: pass fail + +const trait Bar { + fn bar(&self) {} +} +const trait Baz { + fn baz(&self) {} +} + +impl const Bar for () {} +impl const Baz for () {} + +const trait Foo = [const] Bar + Baz; +//~^ ERROR: `[const]` is not allowed here + +const fn foo(x: &T) { + //~^ ERROR: `[const]` can only be applied to `const` traits + //~| ERROR: `[const]` can only be applied to `const` traits + x.bar(); + //~^ ERROR: the trait bound `T: [const] Bar` is not satisfied + #[cfg(fail)] + { + x.baz(); + //[fail]~^ ERROR: the trait bound `T: [const] Baz` is not satisfied + } +} + +const _: () = foo(&()); + +fn main() {} From 904a23e4f4a0028a58296cc3eea40ea3016be131 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 21 Jul 2025 11:35:45 +0000 Subject: [PATCH 3/8] Generate const predicates for const trait aliases --- .../rustc_ast_passes/src/ast_validation.rs | 8 +++ compiler/rustc_hir_analysis/src/collect.rs | 2 +- .../src/collect/predicates_of.rs | 18 ++++--- compiler/rustc_middle/src/ty/mod.rs | 3 +- tests/ui/consts/trait_alias.fail.stderr | 51 +++++-------------- tests/ui/consts/trait_alias.pass.stderr | 43 ++++------------ tests/ui/consts/trait_alias.rs | 5 +- 7 files changed, 45 insertions(+), 85 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index a08dae1115307..d4a86831c98c9 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1163,6 +1163,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait); }); } + ItemKind::TraitAlias(box TraitAlias { constness, generics, bounds, .. }) => { + let disallowed = matches!(constness, ast::Const::No) + .then(|| TildeConstReason::Trait { span: item.span }); + self.with_tilde_const(disallowed, |this| { + this.visit_generics(generics); + walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) + }); + } ItemKind::Mod(safety, ident, mod_kind) => { if let &Safety::Unsafe(span) = safety { self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" }); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 0728b24eb1425..3ef76c8171fae 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -848,7 +848,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { hir::ItemKind::Trait(constness, is_auto, safety, ..) => { (constness, false, is_auto == hir::IsAuto::Yes, safety) } - hir::ItemKind::TraitAlias(..) => (hir::Constness::NotConst, true, false, hir::Safety::Safe), + hir::ItemKind::TraitAlias(constness, ..) => (constness, true, false, hir::Safety::Safe), _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"), }; diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 297ad89b4e732..e25d452554e48 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1018,7 +1018,8 @@ pub(super) fn const_conditions<'tcx>( Node::Item(item) => match item.kind { hir::ItemKind::Impl(impl_) => (impl_.generics, None, false), hir::ItemKind::Fn { generics, .. } => (generics, None, false), - hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { + hir::ItemKind::TraitAlias(_, _, generics, supertraits) + | hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { (generics, Some((item.owner_id.def_id, supertraits)), false) } _ => bug!("const_conditions called on wrong item: {def_id:?}"), @@ -1128,13 +1129,14 @@ pub(super) fn explicit_implied_const_bounds<'tcx>( span_bug!(tcx.def_span(def_id), "RPITIT in impl should not have item bounds") } None => match tcx.hir_node_by_def_id(def_id) { - Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => { - implied_predicates_with_filter( - tcx, - def_id.to_def_id(), - PredicateFilter::SelfConstIfConst, - ) - } + Node::Item(hir::Item { + kind: hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..), + .. + }) => implied_predicates_with_filter( + tcx, + def_id.to_def_id(), + PredicateFilter::SelfConstIfConst, + ), Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) | Node::OpaqueTy(_) => { explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a7cde2ad48547..71bee7909a4f6 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2109,7 +2109,7 @@ impl<'tcx> TyCtxt<'tcx> { DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => { self.constness(def_id) == hir::Constness::Const } - DefKind::Trait => self.is_const_trait(def_id), + DefKind::TraitAlias | DefKind::Trait => self.is_const_trait(def_id), DefKind::AssocTy => { let parent_def_id = self.parent(def_id); match self.def_kind(parent_def_id) { @@ -2152,7 +2152,6 @@ impl<'tcx> TyCtxt<'tcx> { | DefKind::Variant | DefKind::TyAlias | DefKind::ForeignTy - | DefKind::TraitAlias | DefKind::TyParam | DefKind::Const | DefKind::ConstParam diff --git a/tests/ui/consts/trait_alias.fail.stderr b/tests/ui/consts/trait_alias.fail.stderr index 97eb685b16a90..e9148f0bfece2 100644 --- a/tests/ui/consts/trait_alias.fail.stderr +++ b/tests/ui/consts/trait_alias.fail.stderr @@ -1,46 +1,23 @@ -error: `[const]` is not allowed here - --> $DIR/trait_alias.rs:14:19 - | -LL | const trait Foo = [const] Bar + Baz; - | ^^^^^^^ +error[E0277]: the trait bound `T: [const] Baz` is not satisfied + --> $DIR/trait_alias.rs:20:11 | - = note: this item cannot have `[const]` trait bounds +LL | x.baz(); + | ^^^ -error: `[const]` can only be applied to `const` traits - --> $DIR/trait_alias.rs:17:17 +error[E0277]: the trait bound `(): const Foo` is not satisfied + --> $DIR/trait_alias.rs:25:19 | -LL | const fn foo(x: &T) { - | ^^^^^^^ can't be applied to `Foo` - | -help: mark `Foo` as `const` to allow it to have `const` implementations +LL | const _: () = foo(&()); + | --- ^^^ + | | + | required by a bound introduced by this call | -LL | #[const_trait] const trait Foo = [const] Bar + Baz; - | ++++++++++++++ - -error: `[const]` can only be applied to `const` traits - --> $DIR/trait_alias.rs:17:17 +note: required by a bound in `foo` + --> $DIR/trait_alias.rs:16:17 | LL | const fn foo(x: &T) { - | ^^^^^^^ can't be applied to `Foo` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `const` to allow it to have `const` implementations - | -LL | #[const_trait] const trait Foo = [const] Bar + Baz; - | ++++++++++++++ - -error[E0277]: the trait bound `T: [const] Bar` is not satisfied - --> $DIR/trait_alias.rs:20:7 - | -LL | x.bar(); - | ^^^ - -error[E0277]: the trait bound `T: [const] Baz` is not satisfied - --> $DIR/trait_alias.rs:24:11 - | -LL | x.baz(); - | ^^^ + | ^^^^^^^^^^^ required by this bound in `foo` -error: aborting due to 5 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.pass.stderr b/tests/ui/consts/trait_alias.pass.stderr index 00e7e2ca98c75..d107ddbf8e457 100644 --- a/tests/ui/consts/trait_alias.pass.stderr +++ b/tests/ui/consts/trait_alias.pass.stderr @@ -1,40 +1,17 @@ -error: `[const]` is not allowed here - --> $DIR/trait_alias.rs:14:19 +error[E0277]: the trait bound `(): const Foo` is not satisfied + --> $DIR/trait_alias.rs:25:19 | -LL | const trait Foo = [const] Bar + Baz; - | ^^^^^^^ +LL | const _: () = foo(&()); + | --- ^^^ + | | + | required by a bound introduced by this call | - = note: this item cannot have `[const]` trait bounds - -error: `[const]` can only be applied to `const` traits - --> $DIR/trait_alias.rs:17:17 - | -LL | const fn foo(x: &T) { - | ^^^^^^^ can't be applied to `Foo` - | -help: mark `Foo` as `const` to allow it to have `const` implementations - | -LL | #[const_trait] const trait Foo = [const] Bar + Baz; - | ++++++++++++++ - -error: `[const]` can only be applied to `const` traits - --> $DIR/trait_alias.rs:17:17 +note: required by a bound in `foo` + --> $DIR/trait_alias.rs:16:17 | LL | const fn foo(x: &T) { - | ^^^^^^^ can't be applied to `Foo` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `const` to allow it to have `const` implementations - | -LL | #[const_trait] const trait Foo = [const] Bar + Baz; - | ++++++++++++++ - -error[E0277]: the trait bound `T: [const] Bar` is not satisfied - --> $DIR/trait_alias.rs:20:7 - | -LL | x.bar(); - | ^^^ + | ^^^^^^^^^^^ required by this bound in `foo` -error: aborting due to 4 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.rs b/tests/ui/consts/trait_alias.rs index 945465de2ff8c..0755c1126b06b 100644 --- a/tests/ui/consts/trait_alias.rs +++ b/tests/ui/consts/trait_alias.rs @@ -12,13 +12,9 @@ impl const Bar for () {} impl const Baz for () {} const trait Foo = [const] Bar + Baz; -//~^ ERROR: `[const]` is not allowed here const fn foo(x: &T) { - //~^ ERROR: `[const]` can only be applied to `const` traits - //~| ERROR: `[const]` can only be applied to `const` traits x.bar(); - //~^ ERROR: the trait bound `T: [const] Bar` is not satisfied #[cfg(fail)] { x.baz(); @@ -27,5 +23,6 @@ const fn foo(x: &T) { } const _: () = foo(&()); +//~^ ERROR: `(): const Foo` is not satisfied fn main() {} From c30bc7746a9d8d85dedf05543fb450439b41ab5d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 21 Jul 2025 13:57:44 +0000 Subject: [PATCH 4/8] Make const trait aliases work in next solver --- .../src/collect/predicates_of.rs | 22 +++++++------ .../src/solve/effect_goals.rs | 31 +++++++++++++++++-- tests/ui/consts/trait_alias.fail.stderr | 18 ++--------- tests/ui/consts/trait_alias.pass.stderr | 17 ---------- tests/ui/consts/trait_alias.rs | 3 +- 5 files changed, 45 insertions(+), 46 deletions(-) delete mode 100644 tests/ui/consts/trait_alias.pass.stderr diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index e25d452554e48..a3949550e7045 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1018,9 +1018,11 @@ pub(super) fn const_conditions<'tcx>( Node::Item(item) => match item.kind { hir::ItemKind::Impl(impl_) => (impl_.generics, None, false), hir::ItemKind::Fn { generics, .. } => (generics, None, false), - hir::ItemKind::TraitAlias(_, _, generics, supertraits) - | hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { - (generics, Some((item.owner_id.def_id, supertraits)), false) + hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { + (generics, Some((Some(item.owner_id.def_id), supertraits)), false) + } + hir::ItemKind::TraitAlias(_, _, generics, supertraits) => { + (generics, Some((None, supertraits)), false) } _ => bug!("const_conditions called on wrong item: {def_id:?}"), }, @@ -1076,12 +1078,14 @@ pub(super) fn const_conditions<'tcx>( } if let Some((def_id, supertraits)) = trait_def_id_and_supertraits { - // We've checked above that the trait is conditionally const. - bounds.push(( - ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())) - .to_host_effect_clause(tcx, ty::BoundConstness::Maybe), - DUMMY_SP, - )); + if let Some(def_id) = def_id { + // We've checked above that the trait is conditionally const. + bounds.push(( + ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())) + .to_host_effect_clause(tcx, ty::BoundConstness::Maybe), + DUMMY_SP, + )); + } icx.lowerer().lower_bounds( tcx.types.self_param, diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 61f3f9367f040..62833b3be6903 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -191,10 +191,35 @@ where } fn consider_trait_alias_candidate( - _ecx: &mut EvalCtxt<'_, D>, - _goal: Goal, + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, ) -> Result, NoSolution> { - unreachable!("trait aliases are never const") + let cx = ecx.cx(); + + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + let where_clause_bounds = cx + .predicates_of(goal.predicate.def_id()) + .iter_instantiated(cx, goal.predicate.trait_ref.args) + .map(|p| goal.with(cx, p)); + ecx.add_goals(GoalSource::Misc, where_clause_bounds); + + let const_conditions = cx + .const_conditions(goal.predicate.def_id()) + .iter_instantiated(cx, goal.predicate.trait_ref.args) + .map(|bound_trait_ref| { + goal.with( + cx, + bound_trait_ref.to_host_effect_clause(cx, goal.predicate.constness), + ) + }); + // While you could think of trait aliases to have a single builtin impl + // which uses its implied trait bounds as where-clauses, using + // `GoalSource::ImplWhereClause` here would be incorrect, as we also + // impl them, which means we're "stepping out of the impl constructor" + // again. To handle this, we treat these cycles as ambiguous for now. + ecx.add_goals(GoalSource::Misc, const_conditions); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } fn consider_builtin_sizedness_candidates( diff --git a/tests/ui/consts/trait_alias.fail.stderr b/tests/ui/consts/trait_alias.fail.stderr index e9148f0bfece2..bb0a4e22efcf3 100644 --- a/tests/ui/consts/trait_alias.fail.stderr +++ b/tests/ui/consts/trait_alias.fail.stderr @@ -1,23 +1,9 @@ error[E0277]: the trait bound `T: [const] Baz` is not satisfied - --> $DIR/trait_alias.rs:20:11 + --> $DIR/trait_alias.rs:22:11 | LL | x.baz(); | ^^^ -error[E0277]: the trait bound `(): const Foo` is not satisfied - --> $DIR/trait_alias.rs:25:19 - | -LL | const _: () = foo(&()); - | --- ^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `foo` - --> $DIR/trait_alias.rs:16:17 - | -LL | const fn foo(x: &T) { - | ^^^^^^^^^^^ required by this bound in `foo` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.pass.stderr b/tests/ui/consts/trait_alias.pass.stderr deleted file mode 100644 index d107ddbf8e457..0000000000000 --- a/tests/ui/consts/trait_alias.pass.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0277]: the trait bound `(): const Foo` is not satisfied - --> $DIR/trait_alias.rs:25:19 - | -LL | const _: () = foo(&()); - | --- ^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `foo` - --> $DIR/trait_alias.rs:16:17 - | -LL | const fn foo(x: &T) { - | ^^^^^^^^^^^ required by this bound in `foo` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.rs b/tests/ui/consts/trait_alias.rs index 0755c1126b06b..2496ef609865a 100644 --- a/tests/ui/consts/trait_alias.rs +++ b/tests/ui/consts/trait_alias.rs @@ -1,5 +1,7 @@ #![feature(trait_alias, const_trait_impl)] //@ revisions: pass fail +//@ compile-flags: -Znext-solver +//@[pass] check-pass const trait Bar { fn bar(&self) {} @@ -23,6 +25,5 @@ const fn foo(x: &T) { } const _: () = foo(&()); -//~^ ERROR: `(): const Foo` is not satisfied fn main() {} From c392f0df8aebe5ee28f63f82c53870113cafd565 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 21 Jul 2025 14:10:20 +0000 Subject: [PATCH 5/8] Prepare test for old solver --- tests/ui/consts/trait_alias.fail.stderr | 18 ++++++++++++++++-- tests/ui/consts/trait_alias.next_fail.stderr | 9 +++++++++ tests/ui/consts/trait_alias.pass.stderr | 17 +++++++++++++++++ tests/ui/consts/trait_alias.rs | 12 +++++++----- 4 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 tests/ui/consts/trait_alias.next_fail.stderr create mode 100644 tests/ui/consts/trait_alias.pass.stderr diff --git a/tests/ui/consts/trait_alias.fail.stderr b/tests/ui/consts/trait_alias.fail.stderr index bb0a4e22efcf3..8cf9a7c877702 100644 --- a/tests/ui/consts/trait_alias.fail.stderr +++ b/tests/ui/consts/trait_alias.fail.stderr @@ -1,9 +1,23 @@ error[E0277]: the trait bound `T: [const] Baz` is not satisfied - --> $DIR/trait_alias.rs:22:11 + --> $DIR/trait_alias.rs:23:11 | LL | x.baz(); | ^^^ -error: aborting due to 1 previous error +error[E0277]: the trait bound `(): const Foo` is not satisfied + --> $DIR/trait_alias.rs:28:19 + | +LL | const _: () = foo(&()); + | --- ^^^ + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/trait_alias.rs:19:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.next_fail.stderr b/tests/ui/consts/trait_alias.next_fail.stderr new file mode 100644 index 0000000000000..1a72b9c70de79 --- /dev/null +++ b/tests/ui/consts/trait_alias.next_fail.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `T: [const] Baz` is not satisfied + --> $DIR/trait_alias.rs:23:11 + | +LL | x.baz(); + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.pass.stderr b/tests/ui/consts/trait_alias.pass.stderr new file mode 100644 index 0000000000000..bbd598e80785e --- /dev/null +++ b/tests/ui/consts/trait_alias.pass.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `(): const Foo` is not satisfied + --> $DIR/trait_alias.rs:28:19 + | +LL | const _: () = foo(&()); + | --- ^^^ + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/trait_alias.rs:19:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.rs b/tests/ui/consts/trait_alias.rs index 2496ef609865a..4062c19f52d22 100644 --- a/tests/ui/consts/trait_alias.rs +++ b/tests/ui/consts/trait_alias.rs @@ -1,7 +1,8 @@ #![feature(trait_alias, const_trait_impl)] -//@ revisions: pass fail -//@ compile-flags: -Znext-solver -//@[pass] check-pass +//@ revisions: next_pass next_fail pass fail +//@[next_pass] compile-flags: -Znext-solver +//@[next_fail] compile-flags: -Znext-solver +//@[next_pass] check-pass const trait Bar { fn bar(&self) {} @@ -17,13 +18,14 @@ const trait Foo = [const] Bar + Baz; const fn foo(x: &T) { x.bar(); - #[cfg(fail)] + #[cfg(any(fail, next_fail))] { x.baz(); - //[fail]~^ ERROR: the trait bound `T: [const] Baz` is not satisfied + //[fail,next_fail]~^ ERROR: the trait bound `T: [const] Baz` is not satisfied } } const _: () = foo(&()); +//[fail,pass]~^ ERROR: `(): const Foo` is not satisfied fn main() {} From 9925b88c4b90cb4b7c779c89c139970d3f95dda1 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 22 Jul 2025 07:23:33 +0000 Subject: [PATCH 6/8] Make const trait aliases work in the old solver --- .../src/traits/effects.rs | 40 +++++++++++++++++++ tests/ui/consts/trait_alias.fail.stderr | 18 +-------- tests/ui/consts/trait_alias.next_fail.stderr | 2 +- tests/ui/consts/trait_alias.pass.stderr | 17 -------- tests/ui/consts/trait_alias.rs | 2 +- 5 files changed, 44 insertions(+), 35 deletions(-) delete mode 100644 tests/ui/consts/trait_alias.pass.stderr diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index d694a092853af..bcea25fc3d0f5 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -69,6 +69,12 @@ pub fn evaluate_host_effect_obligation<'tcx>( Err(EvaluationFailure::NoSolution) => {} } + match evaluate_host_effect_from_trait_alias(selcx, obligation) { + Ok(result) => return Ok(result), + Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), + Err(EvaluationFailure::NoSolution) => {} + } + Err(EvaluationFailure::NoSolution) } @@ -498,3 +504,37 @@ fn evaluate_host_effect_from_selection_candidate<'tcx>( } }) } + +fn evaluate_host_effect_from_trait_alias<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result>, EvaluationFailure> { + let tcx = selcx.tcx(); + let def_id = obligation.predicate.def_id(); + if !tcx.trait_is_alias(def_id) { + return Err(EvaluationFailure::NoSolution); + } + + Ok(tcx + .const_conditions(def_id) + .instantiate(tcx, obligation.predicate.trait_ref.args) + .into_iter() + .map(|(trait_ref, span)| { + Obligation::new( + tcx, + obligation.cause.clone().derived_host_cause( + ty::Binder::dummy(obligation.predicate), + |derived| { + ObligationCauseCode::ImplDerivedHost(Box::new(ImplDerivedHostCause { + derived, + impl_def_id: def_id, + span, + })) + }, + ), + obligation.param_env, + trait_ref.to_host_effect_clause(tcx, obligation.predicate.constness), + ) + }) + .collect()) +} diff --git a/tests/ui/consts/trait_alias.fail.stderr b/tests/ui/consts/trait_alias.fail.stderr index 8cf9a7c877702..16675206a7a4b 100644 --- a/tests/ui/consts/trait_alias.fail.stderr +++ b/tests/ui/consts/trait_alias.fail.stderr @@ -1,23 +1,9 @@ error[E0277]: the trait bound `T: [const] Baz` is not satisfied - --> $DIR/trait_alias.rs:23:11 + --> $DIR/trait_alias.rs:24:11 | LL | x.baz(); | ^^^ -error[E0277]: the trait bound `(): const Foo` is not satisfied - --> $DIR/trait_alias.rs:28:19 - | -LL | const _: () = foo(&()); - | --- ^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `foo` - --> $DIR/trait_alias.rs:19:17 - | -LL | const fn foo(x: &T) { - | ^^^^^^^^^^^ required by this bound in `foo` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.next_fail.stderr b/tests/ui/consts/trait_alias.next_fail.stderr index 1a72b9c70de79..16675206a7a4b 100644 --- a/tests/ui/consts/trait_alias.next_fail.stderr +++ b/tests/ui/consts/trait_alias.next_fail.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `T: [const] Baz` is not satisfied - --> $DIR/trait_alias.rs:23:11 + --> $DIR/trait_alias.rs:24:11 | LL | x.baz(); | ^^^ diff --git a/tests/ui/consts/trait_alias.pass.stderr b/tests/ui/consts/trait_alias.pass.stderr deleted file mode 100644 index bbd598e80785e..0000000000000 --- a/tests/ui/consts/trait_alias.pass.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0277]: the trait bound `(): const Foo` is not satisfied - --> $DIR/trait_alias.rs:28:19 - | -LL | const _: () = foo(&()); - | --- ^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `foo` - --> $DIR/trait_alias.rs:19:17 - | -LL | const fn foo(x: &T) { - | ^^^^^^^^^^^ required by this bound in `foo` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.rs b/tests/ui/consts/trait_alias.rs index 4062c19f52d22..3d9a60cefc7cc 100644 --- a/tests/ui/consts/trait_alias.rs +++ b/tests/ui/consts/trait_alias.rs @@ -3,6 +3,7 @@ //@[next_pass] compile-flags: -Znext-solver //@[next_fail] compile-flags: -Znext-solver //@[next_pass] check-pass +//@[pass] check-pass const trait Bar { fn bar(&self) {} @@ -26,6 +27,5 @@ const fn foo(x: &T) { } const _: () = foo(&()); -//[fail,pass]~^ ERROR: `(): const Foo` is not satisfied fn main() {} From 32239817d3e5cd83083f2c7fb37ff79cb4b39d9b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 22 Jul 2025 08:11:23 +0000 Subject: [PATCH 7/8] Add more tests --- src/tools/rustfmt/tests/source/trait.rs | 2 ++ src/tools/rustfmt/tests/target/trait.rs | 2 ++ tests/ui/consts/trait_alias_method_call.rs | 31 ++++++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 tests/ui/consts/trait_alias_method_call.rs diff --git a/src/tools/rustfmt/tests/source/trait.rs b/src/tools/rustfmt/tests/source/trait.rs index b6db9e1590d41..1970646f7770c 100644 --- a/src/tools/rustfmt/tests/source/trait.rs +++ b/src/tools/rustfmt/tests/source/trait.rs @@ -181,3 +181,5 @@ trait Visible { pub fn f(); pub fn g() {} } + +const trait Foomp = Hash; \ No newline at end of file diff --git a/src/tools/rustfmt/tests/target/trait.rs b/src/tools/rustfmt/tests/target/trait.rs index 7f067991b267b..cc2b59dc61629 100644 --- a/src/tools/rustfmt/tests/target/trait.rs +++ b/src/tools/rustfmt/tests/target/trait.rs @@ -218,3 +218,5 @@ trait Visible { pub fn f(); pub fn g() {} } + +trait Foomp = Hash; diff --git a/tests/ui/consts/trait_alias_method_call.rs b/tests/ui/consts/trait_alias_method_call.rs new file mode 100644 index 0000000000000..75c51f8f031b1 --- /dev/null +++ b/tests/ui/consts/trait_alias_method_call.rs @@ -0,0 +1,31 @@ +//! Test that we do not need to handle host effects in `expand_trait_aliases` + +#![feature(trait_alias, const_trait_impl)] +//@ check-pass + +mod foo { + pub const trait Bar { + fn bar(&self) {} + } + pub const trait Baz { + fn baz(&self) {} + } + + impl const Bar for () {} + impl const Baz for () {} + + pub const trait Foo = [const] Bar + Baz; +} + +use foo::Foo as _; + + +const _: () = { + // Ok via `[const] Bar` on `Foo` + ().bar(); + // Also works, because everything is fully concrete, so we're ignoring that + // `Baz` is not a const trait bound of `Foo`. + ().baz(); +}; + +fn main() {} From 5d3eb69d7825b811d5f2b67ed9b97425d5f81c5c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 23 Jul 2025 14:29:01 +0000 Subject: [PATCH 8/8] Fix formatting of const trait aliases --- src/tools/rustfmt/src/items.rs | 15 +++++++-------- src/tools/rustfmt/src/visitor.rs | 9 +-------- src/tools/rustfmt/tests/target/trait.rs | 2 +- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 7084639aca9a9..1b94114a6b03f 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1387,22 +1387,21 @@ impl<'a> Rewrite for TraitAliasBounds<'a> { pub(crate) fn format_trait_alias( context: &RewriteContext<'_>, - ident: symbol::Ident, + ta: &ast::TraitAlias, vis: &ast::Visibility, - generics: &ast::Generics, - generic_bounds: &ast::GenericBounds, shape: Shape, ) -> Option { - let alias = rewrite_ident(context, ident); + let alias = rewrite_ident(context, ta.ident); // 6 = "trait ", 2 = " =" let g_shape = shape.offset_left(6)?.sub_width(2)?; - let generics_str = rewrite_generics(context, alias, generics, g_shape).ok()?; + let generics_str = rewrite_generics(context, alias, &ta.generics, g_shape).ok()?; let vis_str = format_visibility(context, vis); - let lhs = format!("{vis_str}trait {generics_str} ="); + let constness = format_constness(ta.constness); + let lhs = format!("{vis_str}{constness}trait {generics_str} ="); // 1 = ";" let trait_alias_bounds = TraitAliasBounds { - generic_bounds, - generics, + generic_bounds: &ta.bounds, + generics: &ta.generics, }; rewrite_assign_rhs( context, diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index f07fc8ca83bc6..fb34360c6cd0a 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -499,14 +499,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { } ast::ItemKind::TraitAlias(ref ta) => { let shape = Shape::indented(self.block_indent, self.config); - let rw = format_trait_alias( - &self.get_context(), - ta.ident, - &item.vis, - &ta.generics, - &ta.bounds, - shape, - ); + let rw = format_trait_alias(&self.get_context(), ta, &item.vis, shape); self.push_rewrite(item.span, rw); } ast::ItemKind::ExternCrate(..) => { diff --git a/src/tools/rustfmt/tests/target/trait.rs b/src/tools/rustfmt/tests/target/trait.rs index cc2b59dc61629..7a65b13d629e7 100644 --- a/src/tools/rustfmt/tests/target/trait.rs +++ b/src/tools/rustfmt/tests/target/trait.rs @@ -219,4 +219,4 @@ trait Visible { pub fn g() {} } -trait Foomp = Hash; +const trait Foomp = Hash;