Skip to content

Commit 47abf2e

Browse files
committed
trait_sel: extend fast path with sized hierarchy
Extend the fast path for `Sized` traits to include constness and `MetaSized`.
1 parent 1834582 commit 47abf2e

File tree

6 files changed

+47
-23
lines changed

6 files changed

+47
-23
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
2222
use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM;
2323
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
2424
use rustc_middle::ty::{
25-
self, AdtKind, CanonicalUserType, GenericArgsRef, GenericParamDefKind, IsIdentity, Ty, TyCtxt,
26-
TypeFoldable, TypeVisitable, TypeVisitableExt, UserArgs, UserSelfTy,
25+
self, AdtKind, CanonicalUserType, GenericArgsRef, GenericParamDefKind, IsIdentity,
26+
SizedTraitKind, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt, UserArgs,
27+
UserSelfTy,
2728
};
2829
use rustc_middle::{bug, span_bug};
2930
use rustc_session::lint;
@@ -439,7 +440,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
439440
|| {},
440441
);
441442
// Sized types have static alignment, and so do slices.
442-
if tail.is_trivially_sized(self.tcx) || matches!(tail.kind(), ty::Slice(..)) {
443+
if tail.has_trivial_sizedness(self.tcx, SizedTraitKind::Sized)
444+
|| matches!(tail.kind(), ty::Slice(..))
445+
{
443446
// Nothing else is required here.
444447
} else {
445448
// We can't be sure, let's required full `Sized`.

compiler/rustc_middle/src/ty/sty.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_hir::def_id::DefId;
1515
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension};
1616
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
1717
use rustc_type_ir::TyKind::*;
18+
use rustc_type_ir::solve::SizedTraitKind;
1819
use rustc_type_ir::walk::TypeWalker;
1920
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, TypeVisitableExt, elaborate};
2021
use tracing::instrument;
@@ -1677,7 +1678,7 @@ impl<'tcx> Ty<'tcx> {
16771678
let Some(pointee_ty) = self.builtin_deref(true) else {
16781679
bug!("Type {self:?} is not a pointer or reference type")
16791680
};
1680-
if pointee_ty.is_trivially_sized(tcx) {
1681+
if pointee_ty.has_trivial_sizedness(tcx, SizedTraitKind::Sized) {
16811682
tcx.types.unit
16821683
} else {
16831684
match pointee_ty.ptr_metadata_ty_or_tail(tcx, |x| x) {
@@ -1778,17 +1779,17 @@ impl<'tcx> Ty<'tcx> {
17781779
}
17791780
}
17801781

1781-
/// Fast path helper for testing if a type is `Sized`.
1782+
/// Fast path helper for testing if a type is `Sized` or `MetaSized`.
17821783
///
1783-
/// Returning true means the type is known to implement `Sized`. Returning `false` means
1784-
/// nothing -- could be sized, might not be.
1784+
/// Returning true means the type is known to implement the sizedness trait. Returning `false`
1785+
/// means nothing -- could be sized, might not be.
17851786
///
17861787
/// Note that we could never rely on the fact that a type such as `[_]` is trivially `!Sized`
17871788
/// because we could be in a type environment with a bound such as `[_]: Copy`. A function with
17881789
/// such a bound obviously never can be called, but that doesn't mean it shouldn't typecheck.
17891790
/// This is why this method doesn't return `Option<bool>`.
17901791
#[instrument(skip(tcx), level = "debug")]
1791-
pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool {
1792+
pub fn has_trivial_sizedness(self, tcx: TyCtxt<'tcx>, sizedness: SizedTraitKind) -> bool {
17921793
match self.kind() {
17931794
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
17941795
| ty::Uint(_)
@@ -1811,13 +1812,20 @@ impl<'tcx> Ty<'tcx> {
18111812
| ty::Error(_)
18121813
| ty::Dynamic(_, _, ty::DynStar) => true,
18131814

1814-
ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false,
1815+
ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) => match sizedness {
1816+
SizedTraitKind::Sized => false,
1817+
SizedTraitKind::MetaSized => true,
1818+
},
1819+
1820+
ty::Foreign(..) => match sizedness {
1821+
SizedTraitKind::Sized | SizedTraitKind::MetaSized => false,
1822+
},
18151823

1816-
ty::Tuple(tys) => tys.last().is_none_or(|ty| ty.is_trivially_sized(tcx)),
1824+
ty::Tuple(tys) => tys.last().is_none_or(|ty| ty.has_trivial_sizedness(tcx, sizedness)),
18171825

18181826
ty::Adt(def, args) => def
1819-
.sizedness_constraint(tcx, ty::SizedTraitKind::Sized)
1820-
.is_none_or(|ty| ty.instantiate(tcx, args).is_trivially_sized(tcx)),
1827+
.sizedness_constraint(tcx, sizedness)
1828+
.is_none_or(|ty| ty.instantiate(tcx, args).has_trivial_sizedness(tcx, sizedness)),
18211829

18221830
ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false,
18231831

compiler/rustc_middle/src/ty/util.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_index::bit_set::GrowableBitSet;
1616
use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
1717
use rustc_session::Limit;
1818
use rustc_span::sym;
19+
use rustc_type_ir::solve::SizedTraitKind;
1920
use smallvec::{SmallVec, smallvec};
2021
use tracing::{debug, instrument};
2122

@@ -1132,7 +1133,8 @@ impl<'tcx> Ty<'tcx> {
11321133
/// strange rules like `<T as Foo<'static>>::Bar: Sized` that
11331134
/// actually carry lifetime requirements.
11341135
pub fn is_sized(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
1135-
self.is_trivially_sized(tcx) || tcx.is_sized_raw(typing_env.as_query_input(self))
1136+
self.has_trivial_sizedness(tcx, SizedTraitKind::Sized)
1137+
|| tcx.is_sized_raw(typing_env.as_query_input(self))
11361138
}
11371139

11381140
/// Checks whether values of this type `T` implement the `Freeze`

compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ fn attempt_dyn_to_enum_suggestion(
556556
let Some(impl_type) = tcx.type_of(*impl_id).no_bound_vars() else { return None };
557557

558558
// Obviously unsized impl types won't be usable in an enum.
559-
// Note: this doesn't use `Ty::is_trivially_sized` because that function
559+
// Note: this doesn't use `Ty::has_trivial_sizedness` because that function
560560
// defaults to assuming that things are *not* sized, whereas we want to
561561
// fall back to assuming that things may be sized.
562562
match impl_type.kind() {

compiler/rustc_trait_selection/src/solve/delegate.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_infer::traits::solve::Goal;
1212
use rustc_middle::traits::query::NoSolution;
1313
use rustc_middle::traits::solve::Certainty;
1414
use rustc_middle::ty::{
15-
self, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt as _, TypingMode,
15+
self, SizedTraitKind, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt as _, TypingMode,
1616
};
1717
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
1818

@@ -79,7 +79,14 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
7979
Some(LangItem::Sized)
8080
if self
8181
.resolve_vars_if_possible(trait_pred.self_ty().skip_binder())
82-
.is_trivially_sized(self.0.tcx) =>
82+
.has_trivial_sizedness(self.0.tcx, SizedTraitKind::Sized) =>
83+
{
84+
return Some(Certainty::Yes);
85+
}
86+
Some(LangItem::MetaSized)
87+
if self
88+
.resolve_vars_if_possible(trait_pred.self_ty().skip_binder())
89+
.has_trivial_sizedness(self.0.tcx, SizedTraitKind::MetaSized) =>
8390
{
8491
return Some(Certainty::Yes);
8592
}

compiler/rustc_trait_selection/src/traits/util.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_infer::infer::InferCtxt;
77
pub use rustc_infer::traits::util::*;
88
use rustc_middle::bug;
99
use rustc_middle::ty::{
10-
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
10+
self, SizedTraitKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
1111
};
1212
pub use rustc_next_trait_solver::placeholder::BoundVarReplacer;
1313
use rustc_span::Span;
@@ -362,15 +362,19 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
362362
}
363363

364364
pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>) -> bool {
365-
// Proving `Sized` very often on "obviously sized" types like `&T`, accounts for about 60%
366-
// percentage of the predicates we have to prove. No need to canonicalize and all that for
367-
// such cases.
365+
// Proving `Sized`/`MetaSized`, very often on "obviously sized" types like
366+
// `&T`, accounts for about 60% percentage of the predicates we have to prove. No need to
367+
// canonicalize and all that for such cases.
368368
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) =
369369
predicate.kind().skip_binder()
370370
{
371-
if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized)
372-
&& trait_ref.self_ty().is_trivially_sized(tcx)
373-
{
371+
let sizedness = match tcx.as_lang_item(trait_ref.def_id()) {
372+
Some(LangItem::Sized) => SizedTraitKind::Sized,
373+
Some(LangItem::MetaSized) => SizedTraitKind::MetaSized,
374+
_ => return false,
375+
};
376+
377+
if trait_ref.self_ty().has_trivial_sizedness(tcx, sizedness) {
374378
debug!("fast path -- trivial sizedness");
375379
return true;
376380
}

0 commit comments

Comments
 (0)