Rollup merge of #144291 - oli-obk:const_trait_alias, r=fee1-dead

Constify trait aliases

Allow `const trait Foo = Bar + [const] Baz;` trait alias declarations. Their rules are the same as with super traits of const traits. So `[const] Baz` or `const Baz` is only required for `[const] Foo` or `const Foo` bounds respectively.

tracking issue rust-lang/rust#41517 (part of the general trait alias feature gate, but I can split it out into a separate const trait alias feature gate. I just assumed that const traits would stabilize before trait aliases, and we'd want to stabilize trait aliases together with const trait aliases at the same time)

r? ``@compiler-errors`` ``@fee1-dead``
This commit is contained in:
Matthias Krüger
2025-10-31 02:39:14 +01:00
committed by GitHub
36 changed files with 280 additions and 100 deletions

View File

@@ -3540,8 +3540,9 @@ impl Item {
ItemKind::Const(i) => Some(&i.generics), ItemKind::Const(i) => Some(&i.generics),
ItemKind::Fn(i) => Some(&i.generics), ItemKind::Fn(i) => Some(&i.generics),
ItemKind::TyAlias(i) => Some(&i.generics), ItemKind::TyAlias(i) => Some(&i.generics),
ItemKind::TraitAlias(_, generics, _) ItemKind::TraitAlias(i) => Some(&i.generics),
| ItemKind::Enum(_, generics, _)
ItemKind::Enum(_, generics, _)
| ItemKind::Struct(_, generics, _) | ItemKind::Struct(_, generics, _)
| ItemKind::Union(_, generics, _) => Some(&generics), | ItemKind::Union(_, generics, _) => Some(&generics),
ItemKind::Trait(i) => Some(&i.generics), ItemKind::Trait(i) => Some(&i.generics),
@@ -3623,6 +3624,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)] #[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct Trait { pub struct Trait {
pub constness: Const, pub constness: Const,
@@ -3798,7 +3808,7 @@ pub enum ItemKind {
/// Trait alias. /// Trait alias.
/// ///
/// E.g., `trait Foo = Bar + Quux;`. /// E.g., `trait Foo = Bar + Quux;`.
TraitAlias(Ident, Generics, GenericBounds), TraitAlias(Box<TraitAlias>),
/// An implementation. /// An implementation.
/// ///
/// E.g., `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`. /// E.g., `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`.
@@ -3831,7 +3841,7 @@ impl ItemKind {
| ItemKind::Struct(ident, ..) | ItemKind::Struct(ident, ..)
| ItemKind::Union(ident, ..) | ItemKind::Union(ident, ..)
| ItemKind::Trait(box Trait { ident, .. }) | ItemKind::Trait(box Trait { ident, .. })
| ItemKind::TraitAlias(ident, ..) | ItemKind::TraitAlias(box TraitAlias { ident, .. })
| ItemKind::MacroDef(ident, _) | ItemKind::MacroDef(ident, _)
| ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident), | ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident),
@@ -3888,7 +3898,7 @@ impl ItemKind {
| Self::Struct(_, generics, _) | Self::Struct(_, generics, _)
| Self::Union(_, generics, _) | Self::Union(_, generics, _)
| Self::Trait(box Trait { generics, .. }) | Self::Trait(box Trait { generics, .. })
| Self::TraitAlias(_, generics, _) | Self::TraitAlias(box TraitAlias { generics, .. })
| Self::Impl(Impl { generics, .. }) => Some(generics), | Self::Impl(Impl { generics, .. }) => Some(generics),
_ => None, _ => None,
} }
@@ -4050,8 +4060,8 @@ mod size_asserts {
static_assert_size!(GenericBound, 88); static_assert_size!(GenericBound, 88);
static_assert_size!(Generics, 40); static_assert_size!(Generics, 40);
static_assert_size!(Impl, 64); static_assert_size!(Impl, 64);
static_assert_size!(Item, 144); static_assert_size!(Item, 136);
static_assert_size!(ItemKind, 80); static_assert_size!(ItemKind, 72);
static_assert_size!(LitKind, 24); static_assert_size!(LitKind, 24);
static_assert_size!(Local, 96); static_assert_size!(Local, 96);
static_assert_size!(MetaItemLit, 40); static_assert_size!(MetaItemLit, 40);

View File

@@ -833,8 +833,8 @@ macro_rules! common_visitor_and_walkers {
visit_visitable!($($mut)? vis, impl_), visit_visitable!($($mut)? vis, impl_),
ItemKind::Trait(trait_) => ItemKind::Trait(trait_) =>
visit_visitable!($($mut)? vis, trait_), visit_visitable!($($mut)? vis, trait_),
ItemKind::TraitAlias(ident, generics, bounds) => { ItemKind::TraitAlias(box TraitAlias { constness, ident, generics, bounds}) => {
visit_visitable!($($mut)? vis, ident, generics); visit_visitable!($($mut)? vis, constness, ident, generics);
visit_visitable_with!($($mut)? vis, bounds, BoundKind::Bound) visit_visitable_with!($($mut)? vis, bounds, BoundKind::Bound)
} }
ItemKind::MacCall(m) => ItemKind::MacCall(m) =>

View File

@@ -415,7 +415,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
); );
hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items) hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items)
} }
ItemKind::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 ident = self.lower_ident(*ident);
let (generics, bounds) = self.lower_generics( let (generics, bounds) = self.lower_generics(
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 }) => { ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => {
let ident = self.lower_ident(*ident); let ident = self.lower_ident(*ident);

View File

@@ -1192,6 +1192,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait); 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) => { ItemKind::Mod(safety, ident, mod_kind) => {
if let &Safety::Unsafe(span) = safety { if let &Safety::Unsafe(span) = safety {
self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" }); self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });

View File

@@ -1,7 +1,6 @@
use ast::StaticItem; use ast::StaticItem;
use itertools::{Itertools, Position}; use itertools::{Itertools, Position};
use rustc_ast as ast; use rustc_ast::{self as ast, ModKind, TraitAlias};
use rustc_ast::ModKind;
use rustc_span::Ident; use rustc_span::Ident;
use crate::pp::BoxMarker; use crate::pp::BoxMarker;
@@ -386,8 +385,11 @@ impl<'a> State<'a> {
let empty = item.attrs.is_empty() && items.is_empty(); let empty = item.attrs.is_empty() && items.is_empty();
self.bclose(item.span, empty, cb); self.bclose(item.span, empty, cb);
} }
ast::ItemKind::TraitAlias(ident, generics, bounds) => { ast::ItemKind::TraitAlias(box TraitAlias { constness, ident, generics, bounds }) => {
let (cb, ib) = self.head(visibility_qualified(&item.vis, "trait")); let (cb, ib) = self.head("");
self.print_visibility(&item.vis);
self.print_constness(*constness);
self.word_nbsp("trait");
self.print_ident(*ident); self.print_ident(*ident);
self.print_generic_params(&generics.params); self.print_generic_params(&generics.params);
self.nbsp(); self.nbsp();

View File

@@ -4151,8 +4151,8 @@ impl<'hir> Item<'hir> {
ItemKind::Trait(constness, is_auto, safety, ident, generics, bounds, items), ItemKind::Trait(constness, is_auto, safety, ident, generics, bounds, items),
(*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>), expect_trait_alias, (Constness, Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
ItemKind::TraitAlias(ident, generics, bounds), (*ident, generics, bounds); ItemKind::TraitAlias(constness, ident, generics, bounds), (*constness, *ident, generics, bounds);
expect_impl, &Impl<'hir>, ItemKind::Impl(imp), imp; expect_impl, &Impl<'hir>, ItemKind::Impl(imp), imp;
} }
@@ -4329,7 +4329,7 @@ pub enum ItemKind<'hir> {
&'hir [TraitItemId], &'hir [TraitItemId],
), ),
/// A trait alias. /// A trait alias.
TraitAlias(Ident, &'hir Generics<'hir>, GenericBounds<'hir>), TraitAlias(Constness, Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
/// An implementation, e.g., `impl<A> Trait for Foo { .. }`. /// An implementation, e.g., `impl<A> Trait for Foo { .. }`.
Impl(Impl<'hir>), Impl(Impl<'hir>),
@@ -4374,7 +4374,7 @@ impl ItemKind<'_> {
| ItemKind::Struct(ident, ..) | ItemKind::Struct(ident, ..)
| ItemKind::Union(ident, ..) | ItemKind::Union(ident, ..)
| ItemKind::Trait(_, _, _, ident, ..) | ItemKind::Trait(_, _, _, ident, ..)
| ItemKind::TraitAlias(ident, ..) => Some(ident), | ItemKind::TraitAlias(_, ident, ..) => Some(ident),
ItemKind::Use(_, UseKind::Glob | UseKind::ListStem) ItemKind::Use(_, UseKind::Glob | UseKind::ListStem)
| ItemKind::ForeignMod { .. } | ItemKind::ForeignMod { .. }
@@ -4392,7 +4392,7 @@ impl ItemKind<'_> {
| ItemKind::Struct(_, generics, _) | ItemKind::Struct(_, generics, _)
| ItemKind::Union(_, generics, _) | ItemKind::Union(_, generics, _)
| ItemKind::Trait(_, _, _, _, generics, _, _) | ItemKind::Trait(_, _, _, _, generics, _, _)
| ItemKind::TraitAlias(_, generics, _) | ItemKind::TraitAlias(_, _, generics, _)
| ItemKind::Impl(Impl { generics, .. }) => generics, | ItemKind::Impl(Impl { generics, .. }) => generics,
_ => return None, _ => return None,
}) })

View File

@@ -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_param_bound, bounds);
walk_list!(visitor, visit_trait_item_ref, trait_item_refs); 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_ident(ident));
try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_param_bound, bounds);

View File

@@ -847,7 +847,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
hir::ItemKind::Trait(constness, is_auto, safety, ..) => { hir::ItemKind::Trait(constness, is_auto, safety, ..) => {
(constness, false, is_auto == hir::IsAuto::Yes, 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"), _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
}; };

View File

@@ -167,7 +167,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
} }
} }
ItemKind::Trait(_, _, _, _, _, self_bounds, ..) ItemKind::Trait(_, _, _, _, _, self_bounds, ..)
| ItemKind::TraitAlias(_, _, self_bounds) => { | ItemKind::TraitAlias(_, _, _, self_bounds) => {
is_trait = Some((self_bounds, item.span)); 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 { let (generics, superbounds) = match item.kind {
hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits), 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"), _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
}; };
@@ -1032,7 +1032,10 @@ pub(super) fn const_conditions<'tcx>(
hir::ItemKind::Impl(impl_) => (impl_.generics, None, false), hir::ItemKind::Impl(impl_) => (impl_.generics, None, false),
hir::ItemKind::Fn { generics, .. } => (generics, None, false), hir::ItemKind::Fn { generics, .. } => (generics, None, false),
hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { 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:?}"), _ => bug!("const_conditions called on wrong item: {def_id:?}"),
}, },
@@ -1089,12 +1092,14 @@ pub(super) fn const_conditions<'tcx>(
} }
if let Some((def_id, supertraits)) = trait_def_id_and_supertraits { if let Some((def_id, supertraits)) = trait_def_id_and_supertraits {
// We've checked above that the trait is conditionally const. if let Some(def_id) = def_id {
bounds.push(( // We've checked above that the trait is conditionally const.
ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())) bounds.push((
.to_host_effect_clause(tcx, ty::BoundConstness::Maybe), ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id()))
DUMMY_SP, .to_host_effect_clause(tcx, ty::BoundConstness::Maybe),
)); DUMMY_SP,
));
}
icx.lowerer().lower_bounds( icx.lowerer().lower_bounds(
tcx.types.self_param, tcx.types.self_param,
@@ -1143,13 +1148,14 @@ pub(super) fn explicit_implied_const_bounds<'tcx>(
span_bug!(tcx.def_span(def_id), "RPITIT in impl should not have item bounds") 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) { None => match tcx.hir_node_by_def_id(def_id) {
Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => { Node::Item(hir::Item {
implied_predicates_with_filter( kind: hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..),
tcx, ..
def_id.to_def_id(), }) => implied_predicates_with_filter(
PredicateFilter::SelfConstIfConst, tcx,
) def_id.to_def_id(),
} PredicateFilter::SelfConstIfConst,
),
Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. })
| Node::OpaqueTy(_) => { | Node::OpaqueTy(_) => {
explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst) explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst)

View File

@@ -632,7 +632,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
| hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Struct(_, generics, _)
| hir::ItemKind::Union(_, generics, _) | hir::ItemKind::Union(_, generics, _)
| hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::Trait(_, _, _, _, generics, ..)
| hir::ItemKind::TraitAlias(_, generics, ..) | hir::ItemKind::TraitAlias(_, _, generics, ..)
| hir::ItemKind::Impl(hir::Impl { generics, .. }) => { | hir::ItemKind::Impl(hir::Impl { generics, .. }) => {
// These kinds of items have only early-bound lifetime parameters. // These kinds of items have only early-bound lifetime parameters.
self.visit_early(item.hir_id(), generics, |this| intravisit::walk_item(this, item)); self.visit_early(item.hir_id(), generics, |this| intravisit::walk_item(this, item));

View File

@@ -765,8 +765,10 @@ impl<'a> State<'a> {
} }
self.bclose(item.span, cb); self.bclose(item.span, cb);
} }
hir::ItemKind::TraitAlias(ident, generics, bounds) => { hir::ItemKind::TraitAlias(constness, ident, generics, bounds) => {
let (cb, ib) = self.head("trait"); let (cb, ib) = self.head("");
self.print_constness(constness);
self.word_nbsp("trait");
self.print_ident(ident); self.print_ident(ident);
self.print_generic_params(generics.params); self.print_generic_params(generics.params);
self.nbsp(); self.nbsp();

View File

@@ -1596,7 +1596,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Node::Item(hir::Item { Node::Item(hir::Item {
kind: kind:
hir::ItemKind::Trait(_, _, _, ident, ..) hir::ItemKind::Trait(_, _, _, ident, ..)
| hir::ItemKind::TraitAlias(ident, ..), | hir::ItemKind::TraitAlias(_, ident, ..),
.. ..
}) })
// We may also encounter unsatisfied GAT or method bounds // We may also encounter unsatisfied GAT or method bounds

View File

@@ -160,7 +160,9 @@ impl EarlyLintPass for NonCamelCaseTypes {
ast::ItemKind::Trait(box ast::Trait { ident, .. }) => { ast::ItemKind::Trait(box ast::Trait { ident, .. }) => {
self.check_case(cx, "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 // 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. // trait impls where we should have warned for the trait definition already.

View File

@@ -2101,7 +2101,7 @@ impl<'tcx> TyCtxt<'tcx> {
DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => { DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => {
self.constness(def_id) == hir::Constness::Const 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 => { DefKind::AssocTy => {
let parent_def_id = self.parent(def_id); let parent_def_id = self.parent(def_id);
match self.def_kind(parent_def_id) { match self.def_kind(parent_def_id) {
@@ -2144,7 +2144,6 @@ impl<'tcx> TyCtxt<'tcx> {
| DefKind::Variant | DefKind::Variant
| DefKind::TyAlias | DefKind::TyAlias
| DefKind::ForeignTy | DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::TyParam | DefKind::TyParam
| DefKind::Const | DefKind::Const
| DefKind::ConstParam | DefKind::ConstParam

View File

@@ -196,10 +196,35 @@ where
} }
fn consider_trait_alias_candidate( fn consider_trait_alias_candidate(
_ecx: &mut EvalCtxt<'_, D>, ecx: &mut EvalCtxt<'_, D>,
_goal: Goal<I, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> { ) -> Result<Candidate<I>, 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( fn consider_builtin_sizedness_candidates(

View File

@@ -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_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_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_alias_cannot_be_unsafe = trait aliases cannot be `unsafe`
parse_trait_impl_modifier_in_inherent_impl = inherent impls cannot be {$modifier_name} parse_trait_impl_modifier_in_inherent_impl = inherent impls cannot be {$modifier_name}

View File

@@ -1999,14 +1999,6 @@ pub(crate) struct TraitAliasCannotBeAuto {
pub span: Span, 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)] #[derive(Diagnostic)]
#[diag(parse_trait_alias_cannot_be_unsafe)] #[diag(parse_trait_alias_cannot_be_unsafe)]
pub(crate) struct TraitAliasCannotBeUnsafe { pub(crate) struct TraitAliasCannotBeUnsafe {

View File

@@ -943,9 +943,6 @@ impl<'a> Parser<'a> {
self.expect_semi()?; self.expect_semi()?;
let whole_span = lo.to(self.prev_token.span); 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 { if is_auto == IsAuto::Yes {
self.dcx().emit_err(errors::TraitAliasCannotBeAuto { span: whole_span }); 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); self.psess.gated_spans.gate(sym::trait_alias, whole_span);
Ok(ItemKind::TraitAlias(ident, generics, bounds)) Ok(ItemKind::TraitAlias(Box::new(TraitAlias { constness, ident, generics, bounds })))
} else { } else {
// It's a normal trait. // It's a normal trait.
generics.where_clause = self.parse_where_clause()?; generics.where_clause = self.parse_where_clause()?;

View File

@@ -10,7 +10,7 @@ use std::sync::Arc;
use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind}; use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind};
use rustc_ast::{ use rustc_ast::{
self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, Fn, ForeignItem, 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 as attr;
use rustc_attr_parsing::AttributeParser; use rustc_attr_parsing::AttributeParser;
@@ -844,7 +844,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
} }
// These items live in the type namespace. // 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); self.r.define_local(parent, ident, TypeNS, res, vis, sp, expansion);
} }

View File

@@ -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. // Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib( self.with_generic_param_rib(
&generics.params, &generics.params,
@@ -5164,7 +5164,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
| ItemKind::Union(_, generics, _) | ItemKind::Union(_, generics, _)
| ItemKind::Impl(Impl { generics, .. }) | ItemKind::Impl(Impl { generics, .. })
| ItemKind::Trait(box Trait { generics, .. }) | ItemKind::Trait(box Trait { generics, .. })
| ItemKind::TraitAlias(_, generics, _) => { | ItemKind::TraitAlias(box TraitAlias { generics, .. }) => {
if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind { if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind {
self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs); self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs);
} }

View File

@@ -476,9 +476,8 @@ pub fn report_dyn_incompatibility<'tcx>(
let trait_str = tcx.def_path_str(trait_def_id); 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 { let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node {
hir::Node::Item(item) => match item.kind { hir::Node::Item(item) => match item.kind {
hir::ItemKind::Trait(_, _, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => { hir::ItemKind::Trait(_, _, _, ident, ..)
Some(ident.span) | hir::ItemKind::TraitAlias(_, ident, _, _) => Some(ident.span),
}
_ => unreachable!(), _ => unreachable!(),
}, },
_ => None, _ => None,

View File

@@ -364,7 +364,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
| hir::ItemKind::Fn { generics, .. } | hir::ItemKind::Fn { generics, .. }
| hir::ItemKind::TyAlias(_, generics, _) | hir::ItemKind::TyAlias(_, generics, _)
| hir::ItemKind::Const(_, generics, _, _) | hir::ItemKind::Const(_, generics, _, _)
| hir::ItemKind::TraitAlias(_, generics, _), | hir::ItemKind::TraitAlias(_, _, generics, _),
.. ..
}) })
| hir::Node::TraitItem(hir::TraitItem { generics, .. }) | hir::Node::TraitItem(hir::TraitItem { generics, .. })
@@ -444,7 +444,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
| hir::ItemKind::Fn { generics, .. } | hir::ItemKind::Fn { generics, .. }
| hir::ItemKind::TyAlias(_, generics, _) | hir::ItemKind::TyAlias(_, generics, _)
| hir::ItemKind::Const(_, generics, _, _) | hir::ItemKind::Const(_, generics, _, _)
| hir::ItemKind::TraitAlias(_, generics, _), | hir::ItemKind::TraitAlias(_, _, generics, _),
.. ..
}) if finder.can_suggest_bound(generics) => { }) if finder.can_suggest_bound(generics) => {
// Missing generic type parameter bound. // Missing generic type parameter bound.

View File

@@ -69,6 +69,12 @@ pub fn evaluate_host_effect_obligation<'tcx>(
Err(EvaluationFailure::NoSolution) => {} 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) Err(EvaluationFailure::NoSolution)
} }
@@ -593,3 +599,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<ThinVec<PredicateObligation<'tcx>>, 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())
}

View File

@@ -2827,7 +2827,7 @@ fn clean_maybe_renamed_item<'tcx>(
variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(), variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(),
generics: clean_generics(generics, cx), generics: clean_generics(generics, cx),
}), }),
ItemKind::TraitAlias(_, generics, bounds) => TraitAliasItem(TraitAlias { ItemKind::TraitAlias(_, _, generics, bounds) => TraitAliasItem(TraitAlias {
generics: clean_generics(generics, cx), generics: clean_generics(generics, cx),
bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
}), }),

View File

@@ -528,7 +528,7 @@ impl LateLintPass<'_> for ItemNameRepetitions {
| ItemKind::Macro(ident, ..) | ItemKind::Macro(ident, ..)
| ItemKind::Static(_, ident, ..) | ItemKind::Static(_, ident, ..)
| ItemKind::Trait(_, _, _, ident, ..) | ItemKind::Trait(_, _, _, ident, ..)
| ItemKind::TraitAlias(ident, ..) | ItemKind::TraitAlias(_, ident, ..)
| ItemKind::TyAlias(ident, ..) | ItemKind::TyAlias(ident, ..)
| ItemKind::Union(ident, ..) | ItemKind::Union(ident, ..)
| ItemKind::Use(_, UseKind::Single(ident)) => ident, | ItemKind::Use(_, UseKind::Single(ident)) => ident,

View File

@@ -473,8 +473,24 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
&& over(lb, rb, eq_generic_bound) && over(lb, rb, eq_generic_bound)
&& over(lis, ris, |l, r| eq_item(l, r, eq_assoc_item_kind)) && 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(ast::Impl { Impl(ast::Impl {

View File

@@ -1375,22 +1375,21 @@ impl<'a> Rewrite for TraitAliasBounds<'a> {
pub(crate) fn format_trait_alias( pub(crate) fn format_trait_alias(
context: &RewriteContext<'_>, context: &RewriteContext<'_>,
ident: symbol::Ident, ta: &ast::TraitAlias,
vis: &ast::Visibility, vis: &ast::Visibility,
generics: &ast::Generics,
generic_bounds: &ast::GenericBounds,
shape: Shape, shape: Shape,
) -> Option<String> { ) -> Option<String> {
let alias = rewrite_ident(context, ident); let alias = rewrite_ident(context, ta.ident);
// 6 = "trait ", 2 = " =" // 6 = "trait ", 2 = " ="
let g_shape = shape.offset_left(6)?.sub_width(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 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 = ";" // 1 = ";"
let trait_alias_bounds = TraitAliasBounds { let trait_alias_bounds = TraitAliasBounds {
generic_bounds, generic_bounds: &ta.bounds,
generics, generics: &ta.generics,
}; };
rewrite_assign_rhs( rewrite_assign_rhs(
context, context,

View File

@@ -497,16 +497,9 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
let rw = self.with_context(|ctx| format_trait(ctx, item, block_indent)); let rw = self.with_context(|ctx| format_trait(ctx, item, block_indent));
self.push_rewrite(item.span, rw); 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 shape = Shape::indented(self.block_indent, self.config);
let rw = format_trait_alias( let rw = format_trait_alias(&self.get_context(), ta, &item.vis, shape);
&self.get_context(),
ident,
&item.vis,
generics,
generic_bounds,
shape,
);
self.push_rewrite(item.span, rw); self.push_rewrite(item.span, rw);
} }
ast::ItemKind::ExternCrate(..) => { ast::ItemKind::ExternCrate(..) => {

View File

@@ -181,3 +181,5 @@ trait Visible {
pub fn f(); pub fn f();
pub fn g() {} pub fn g() {}
} }
const trait Foomp = Hash;

View File

@@ -0,0 +1,5 @@
#![feature(trait_alias, const_trait_impl)]
const trait Bar {}
const trait Foo = Bar;

View File

@@ -218,3 +218,5 @@ trait Visible {
pub fn f(); pub fn f();
pub fn g() {} pub fn g() {}
} }
const trait Foomp = Hash;

View File

@@ -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`.

View File

@@ -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`.

View File

@@ -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<T: [const] 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() {}

View File

@@ -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() {}

View File

@@ -2,14 +2,14 @@ ast-stats ================================================================
ast-stats POST EXPANSION AST STATS: input_stats ast-stats POST EXPANSION AST STATS: input_stats
ast-stats Name Accumulated Size Count Item Size ast-stats Name Accumulated Size Count Item Size
ast-stats ---------------------------------------------------------------- ast-stats ----------------------------------------------------------------
ast-stats Item 1_584 (NN.N%) 11 144 ast-stats Item 1_496 (NN.N%) 11 136
ast-stats - Enum 144 (NN.N%) 1 ast-stats - Enum 136 (NN.N%) 1
ast-stats - ExternCrate 144 (NN.N%) 1 ast-stats - ExternCrate 136 (NN.N%) 1
ast-stats - ForeignMod 144 (NN.N%) 1 ast-stats - ForeignMod 136 (NN.N%) 1
ast-stats - Impl 144 (NN.N%) 1 ast-stats - Impl 136 (NN.N%) 1
ast-stats - Trait 144 (NN.N%) 1 ast-stats - Trait 136 (NN.N%) 1
ast-stats - Fn 288 (NN.N%) 2 ast-stats - Fn 272 (NN.N%) 2
ast-stats - Use 576 (NN.N%) 4 ast-stats - Use 544 (NN.N%) 4
ast-stats Ty 896 (NN.N%) 14 64 ast-stats Ty 896 (NN.N%) 14 64
ast-stats - Ptr 64 (NN.N%) 1 ast-stats - Ptr 64 (NN.N%) 1
ast-stats - Ref 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 - AngleBracketed 40 (NN.N%) 1
ast-stats Crate 40 (NN.N%) 1 40 ast-stats Crate 40 (NN.N%) 1 40
ast-stats ---------------------------------------------------------------- ast-stats ----------------------------------------------------------------
ast-stats Total 7_528 129 ast-stats Total 7_440 129
ast-stats ================================================================ ast-stats ================================================================
hir-stats ================================================================ hir-stats ================================================================
hir-stats HIR STATS: input_stats hir-stats HIR STATS: input_stats