1
Fork 0

Rollup merge of #139365 - Bryanskiy:leak-perf, r=lcnr

Default auto traits: fix perf

Skip computing `requires_default_supertraits` if `experimental-default-bounds` option is not enabled. Possible perf fix for https://github.com/rust-lang/rust/pull/120706

r? lcnr
This commit is contained in:
Stuart Cook 2025-04-07 22:29:19 +10:00 committed by GitHub
commit f4c429fde5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 51 additions and 35 deletions

View file

@ -172,33 +172,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
}; };
if let Node::TraitItem(item) = node { if let Node::TraitItem(item) = node {
let parent = tcx.local_parent(item.hir_id().owner.def_id); let mut bounds = Vec::new();
let Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else { icx.lowerer().add_default_trait_item_bounds(item, &mut bounds);
unreachable!(); predicates.extend(bounds);
};
let (trait_generics, trait_bounds) = match parent_trait.kind {
hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits),
hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits),
_ => unreachable!(),
};
// Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if
// they are not added as super trait bounds to the trait itself. See comment on
// `requires_default_supertraits` for more details.
if !icx.lowerer().requires_default_supertraits(trait_bounds, trait_generics) {
let mut bounds = Vec::new();
let self_ty_where_predicates = (parent, item.generics.predicates);
icx.lowerer().add_default_traits_with_filter(
&mut bounds,
tcx.types.self_param,
&[],
Some(self_ty_where_predicates),
item.span,
|tr| tr != hir::LangItem::Sized,
);
predicates.extend(bounds);
}
} }
let generics = tcx.generics_of(def_id); let generics = tcx.generics_of(def_id);

View file

@ -43,12 +43,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} }
/// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds /// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds
/// or associative items. /// or associated items.
/// ///
/// To keep backward compatibility with existing code, `experimental_default_bounds` bounds /// To keep backward compatibility with existing code, `experimental_default_bounds` bounds
/// should be added everywhere, including super bounds. However this causes a huge performance /// should be added everywhere, including super bounds. However this causes a huge performance
/// costs. For optimization purposes instead of adding default supertraits, bounds /// costs. For optimization purposes instead of adding default supertraits, bounds
/// are added to the associative items: /// are added to the associated items:
/// ///
/// ```ignore(illustrative) /// ```ignore(illustrative)
/// // Default bounds are generated in the following way: /// // Default bounds are generated in the following way:
@ -81,7 +81,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// ///
/// Therefore, `experimental_default_bounds` are still being added to supertraits if /// Therefore, `experimental_default_bounds` are still being added to supertraits if
/// the `SelfTyParam` or `AssocItemConstraint` were found in a trait header. /// the `SelfTyParam` or `AssocItemConstraint` were found in a trait header.
pub(crate) fn requires_default_supertraits( fn requires_default_supertraits(
&self, &self,
hir_bounds: &'tcx [hir::GenericBound<'tcx>], hir_bounds: &'tcx [hir::GenericBound<'tcx>],
hir_generics: &'tcx hir::Generics<'tcx>, hir_generics: &'tcx hir::Generics<'tcx>,
@ -120,6 +120,43 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
found found
} }
/// Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if
/// they are not added as super trait bounds to the trait itself. See
/// `requires_default_supertraits` for more information.
pub(crate) fn add_default_trait_item_bounds(
&self,
trait_item: &hir::TraitItem<'tcx>,
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
) {
let tcx = self.tcx();
if !tcx.sess.opts.unstable_opts.experimental_default_bounds {
return;
}
let parent = tcx.local_parent(trait_item.hir_id().owner.def_id);
let hir::Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else {
unreachable!();
};
let (trait_generics, trait_bounds) = match parent_trait.kind {
hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits),
hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits),
_ => unreachable!(),
};
if !self.requires_default_supertraits(trait_bounds, trait_generics) {
let self_ty_where_predicates = (parent, trait_item.generics.predicates);
self.add_default_traits_with_filter(
bounds,
tcx.types.self_param,
&[],
Some(self_ty_where_predicates),
trait_item.span,
|tr| tr != hir::LangItem::Sized,
);
}
}
/// Lazily sets `experimental_default_bounds` to true on trait super bounds. /// Lazily sets `experimental_default_bounds` to true on trait super bounds.
/// See `requires_default_supertraits` for more information. /// See `requires_default_supertraits` for more information.
pub(crate) fn add_default_super_traits( pub(crate) fn add_default_super_traits(
@ -130,6 +167,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir_generics: &'tcx hir::Generics<'tcx>, hir_generics: &'tcx hir::Generics<'tcx>,
span: Span, span: Span,
) { ) {
if !self.tcx().sess.opts.unstable_opts.experimental_default_bounds {
return;
}
assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias)); assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias));
if self.requires_default_supertraits(hir_bounds, hir_generics) { if self.requires_default_supertraits(hir_bounds, hir_generics) {
let self_ty_where_predicates = (trait_def_id, hir_generics.predicates); let self_ty_where_predicates = (trait_def_id, hir_generics.predicates);
@ -263,11 +304,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
seen_unbound = true; seen_unbound = true;
} }
let emit_relax_err = || { let emit_relax_err = || {
let unbound_traits = let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds {
match self.tcx().sess.opts.unstable_opts.experimental_default_bounds { true => "`?Sized` and `experimental_default_bounds`",
true => "`?Sized` and `experimental_default_bounds`", false => "`?Sized`",
false => "`?Sized`", };
};
// There was a `?Trait` bound, but it was neither `?Sized` nor `experimental_default_bounds`. // There was a `?Trait` bound, but it was neither `?Sized` nor `experimental_default_bounds`.
tcx.dcx().span_err( tcx.dcx().span_err(
unbound.span, unbound.span,