diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 97e070958751a..8b0c3c22a8114 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,15 @@ 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)] + pub bounds: GenericBounds, +} + #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct Trait { pub constness: Const, @@ -3889,7 +3899,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 +3932,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 +3989,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 +4151,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..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(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 ddf01b69e7f6a..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(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_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_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 11c97a552c69f..8556a17a89746 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,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(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.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 cc53919626e63..a3949550e7045 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"), }; @@ -1019,7 +1019,10 @@ pub(super) fn const_conditions<'tcx>( hir::ItemKind::Impl(impl_) => (impl_.generics, None, false), hir::ItemKind::Fn { generics, .. } => (generics, None, false), hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { - (generics, Some((item.owner_id.def_id, supertraits)), false) + (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:?}"), }, @@ -1075,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, @@ -1128,13 +1133,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_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_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_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/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/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 b767b0fcf994d..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(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_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/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/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/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 96f0273c43969..a211ac1baa357 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -470,8 +470,24 @@ 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, + constness: lc, + }), + TraitAlias(box ast::TraitAlias { + ident: ri, + generics: rg, + bounds: rb, + constness: rc, + }), + ) => { + 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 { 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 f6a9a3f2cd175..fb34360c6cd0a 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -497,16 +497,9 @@ 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, - &item.vis, - generics, - generic_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/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..7a65b13d629e7 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() {} } + +const trait Foomp = Hash; diff --git a/tests/ui/consts/trait_alias.fail.stderr b/tests/ui/consts/trait_alias.fail.stderr new file mode 100644 index 0000000000000..16675206a7a4b --- /dev/null +++ b/tests/ui/consts/trait_alias.fail.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `T: [const] Baz` is not satisfied + --> $DIR/trait_alias.rs:24: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.next_fail.stderr b/tests/ui/consts/trait_alias.next_fail.stderr new file mode 100644 index 0000000000000..16675206a7a4b --- /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:24: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.rs b/tests/ui/consts/trait_alias.rs new file mode 100644 index 0000000000000..3d9a60cefc7cc --- /dev/null +++ b/tests/ui/consts/trait_alias.rs @@ -0,0 +1,31 @@ +#![feature(trait_alias, const_trait_impl)] +//@ revisions: next_pass next_fail pass fail +//@[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) {} +} +const trait Baz { + fn baz(&self) {} +} + +impl const Bar for () {} +impl const Baz for () {} + +const trait Foo = [const] Bar + Baz; + +const fn foo(x: &T) { + x.bar(); + #[cfg(any(fail, next_fail))] + { + x.baz(); + //[fail,next_fail]~^ ERROR: the trait bound `T: [const] Baz` is not satisfied + } +} + +const _: () = foo(&()); + +fn main() {} 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() {} 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