From 3ca752f9798ba49e3e81a94dac66c0a394395552 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 94c15094f525..81efafc2d1dc 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3540,8 +3540,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), @@ -3623,6 +3624,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, @@ -3795,7 +3804,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 { .. }`. @@ -3828,7 +3837,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), @@ -3885,7 +3894,7 @@ impl ItemKind { | Self::Struct(_, generics, _) | Self::Union(_, generics, _) | Self::Trait(box Trait { generics, .. }) - | Self::TraitAlias(_, generics, _) + | Self::TraitAlias(box TraitAlias { generics, .. }) | Self::Impl(Impl { generics, .. }) => Some(generics), _ => None, } @@ -4047,8 +4056,8 @@ mod size_asserts { static_assert_size!(GenericBound, 88); static_assert_size!(Generics, 40); static_assert_size!(Impl, 64); - 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 03e5a6edeece..ed47c5f5274f 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -833,7 +833,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 8527108f7041..56ceeb7ac581 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -415,7 +415,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 341266086340..36f1387d4b08 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -1,7 +1,6 @@ use ast::StaticItem; use itertools::{Itertools, Position}; -use rustc_ast as ast; -use rustc_ast::ModKind; +use rustc_ast::{self as ast, ModKind, TraitAlias}; use rustc_span::Ident; use crate::pp::BoxMarker; @@ -386,7 +385,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 7f643a551bb7..b90abe0a24f1 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -160,7 +160,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 11eae9e2d903..fde98d14ce11 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -955,7 +955,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 88fbc6dcb665..886ffcffbb4d 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -10,7 +10,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, Inline, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias, + ForeignItemKind, Inline, Item, ItemKind, NodeId, StaticItem, StmtKind, TraitAlias, TyAlias, }; use rustc_attr_parsing as attr; use rustc_attr_parsing::AttributeParser; @@ -844,7 +844,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_local(parent, ident, TypeNS, res, vis, sp, expansion); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index fd7ace368aa6..e3051dc38eca 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2645,7 +2645,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, @@ -5164,7 +5164,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { | ItemKind::Union(_, generics, _) | ItemKind::Impl(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 22b74ab16d61..4df1eb508713 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -473,9 +473,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(ast::Impl { generics: lg, diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index a3acbb218ff2..633a17a40108 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 4a73a4747ad0..648f6698073f 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_528 129 +ast-stats Total 7_440 129 ast-stats ================================================================ hir-stats ================================================================ hir-stats HIR STATS: input_stats From 5f6772c2a70180d397226388116a20fa414c556c 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 +- 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_lints/src/item_name_repetitions.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 81efafc2d1dc..6b7c8e6c1940 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3626,6 +3626,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 ed47c5f5274f..d850698f47b0 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -833,8 +833,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 { constness, ident, generics, bounds}) => { + visit_visitable!($($mut)? vis, constness, ident, generics); 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 56ceeb7ac581..177f33c0d8f1 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -415,7 +415,8 @@ 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 { constness, ident, generics, bounds }) => { + let constness = self.lower_constness(*constness); let ident = self.lower_ident(*ident); let (generics, bounds) = self.lower_generics( generics, @@ -429,7 +430,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }, ); - hir::ItemKind::TraitAlias(ident, generics, bounds) + 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 36f1387d4b08..294d03a83b16 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -385,8 +385,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 { constness, ident, generics, bounds }) => { + 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 38cb12cf24bc..31842e2023dc 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4245,8 +4245,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, &Impl<'hir>, ItemKind::Impl(imp), imp; } @@ -4423,7 +4423,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(Impl<'hir>), @@ -4468,7 +4468,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 { .. } @@ -4486,7 +4486,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 dde71e499c47..4ab0500cafbc 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -626,7 +626,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 79aaa0cb7970..65aa19b91342 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -167,7 +167,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)); } _ => {} @@ -654,7 +654,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 8133f9f68234..14e48594c006 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -632,7 +632,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_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index ed5f61b3c69a..f838a592d94e 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -765,8 +765,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 8f2e06dd7127..0ddf5dd47784 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1594,7 +1594,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 52a35c98a98b..1862900077f0 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -863,7 +863,6 @@ parse_too_short_hex_escape = numeric character escape is too short parse_trailing_vert_not_allowed = a trailing `{$token}` is not allowed in an or-pattern 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_trait_impl_modifier_in_inherent_impl = inherent impls cannot be {$modifier_name} diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 6d536aa850b3..a35c5c304d95 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1999,14 +1999,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 fde98d14ce11..4bb0d05c4f37 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -943,9 +943,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 }); } @@ -955,7 +952,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 { constness, ident, generics, bounds }))) } 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 ded5969e83c5..8e4c7cec0dcf 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -476,9 +476,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 4ecc48d6cc40..cd0dbb4d87f9 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -364,7 +364,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, .. }) @@ -444,7 +444,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 finder.can_suggest_bound(generics) => { // Missing generic type parameter bound. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4a95f21a3a5b..7f23023622f6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2828,7 +2828,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_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs index 76f5fdfaa8dc..22767901614e 100644 --- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs +++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs @@ -528,7 +528,7 @@ impl LateLintPass<'_> for ItemNameRepetitions { | ItemKind::Macro(ident, ..) | ItemKind::Static(_, ident, ..) | ItemKind::Trait(_, _, _, ident, ..) - | ItemKind::TraitAlias(ident, ..) + | ItemKind::TraitAlias(_, ident, ..) | ItemKind::TyAlias(ident, ..) | ItemKind::Union(ident, ..) | ItemKind::Use(_, UseKind::Single(ident)) => ident, 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 4df1eb508713..839b46325b5e 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -478,13 +478,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(ast::Impl { generics: lg, diff --git a/tests/ui/consts/trait_alias.fail.stderr b/tests/ui/consts/trait_alias.fail.stderr new file mode 100644 index 000000000000..97eb685b16a9 --- /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 000000000000..00e7e2ca98c7 --- /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 000000000000..945465de2ff8 --- /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 8b122f1e11a0a6bf7447d03e633b553a5c623c8a 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 | 55 ++++++------------- tests/ui/consts/trait_alias.pass.stderr | 43 ++++----------- tests/ui/consts/trait_alias.rs | 5 +- 7 files changed, 47 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 93f8b74ad561..6b218f34363d 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1192,6 +1192,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 89ab710ff821..1386070e3d9b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -847,7 +847,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 65aa19b91342..88deed1be683 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1031,7 +1031,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:?}"), @@ -1143,13 +1144,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 93d0c77c1dae..905874f05628 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2101,7 +2101,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) { @@ -2144,7 +2144,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 97eb685b16a9..e9148f0bfece 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; - | ^^^^^^^ - | - = 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 + --> $DIR/trait_alias.rs:20:11 | LL | x.baz(); | ^^^ -error: aborting due to 5 previous errors +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 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 00e7e2ca98c7..d107ddbf8e45 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 +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` - | -help: mark `Foo` as `const` to allow it to have `const` implementations - | -LL | #[const_trait] const trait Foo = [const] Bar + Baz; - | ++++++++++++++ + | ^^^^^^^^^^^ required by this bound in `foo` -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 +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 945465de2ff8..0755c1126b06 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 544a5a3e0e6d4c69d62b8e331732c896fe3376d0 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 88deed1be683..2eefe1eb3e92 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1031,9 +1031,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:?}"), }, @@ -1090,12 +1092,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 48bd0963c874..c18f22ca0fb1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -196,10 +196,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().into()) + .iter_instantiated(cx, goal.predicate.trait_ref.args) + .map(|p| goal.with(cx, p)); + + let const_conditions = cx + .const_conditions(goal.predicate.def_id().into()) + .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, where_clause_bounds); + 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 e9148f0bfece..bb0a4e22efcf 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 d107ddbf8e45..000000000000 --- 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 0755c1126b06..2496ef609865 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 bc4d612d46f8cfc63a4718109450572b071fb2d8 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 bb0a4e22efcf..8cf9a7c87770 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 000000000000..1a72b9c70de7 --- /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 000000000000..bbd598e80785 --- /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 2496ef609865..4062c19f52d2 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 b9e7cf61bea80490b970ff7429e1fa8acc00f025 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 7f2a9999d646..d2094046ed44 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) } @@ -496,3 +502,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 8cf9a7c87770..16675206a7a4 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 1a72b9c70de7..16675206a7a4 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 bbd598e80785..000000000000 --- 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 4062c19f52d2..3d9a60cefc7c 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 a6ca44cf4092c790664d7218c032ea47ba41f0bc 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 b6db9e1590d4..1970646f7770 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 7f067991b267..cc2b59dc6162 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 000000000000..75c51f8f031b --- /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 ebb249d69e84df66f183b45b45c51e21ad0d0988 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/const_trait.rs | 5 +++++ src/tools/rustfmt/tests/target/trait.rs | 2 +- 4 files changed, 14 insertions(+), 17 deletions(-) create mode 100644 src/tools/rustfmt/tests/target/const_trait.rs diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index a2e89c10a480..ecaa4670f61d 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1375,22 +1375,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 633a17a40108..c521b497a2d9 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/const_trait.rs b/src/tools/rustfmt/tests/target/const_trait.rs new file mode 100644 index 000000000000..c4c88b17fc50 --- /dev/null +++ b/src/tools/rustfmt/tests/target/const_trait.rs @@ -0,0 +1,5 @@ +#![feature(trait_alias, const_trait_impl)] + +const trait Bar {} + +const trait Foo = Bar; diff --git a/src/tools/rustfmt/tests/target/trait.rs b/src/tools/rustfmt/tests/target/trait.rs index cc2b59dc6162..7a65b13d629e 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;