diff options
| author | David Wood <david.wood2@arm.com> | 2025-04-09 17:07:45 +0000 |
|---|---|---|
| committer | David Wood <david.wood2@arm.com> | 2025-06-16 23:04:35 +0000 |
| commit | 47abf2e144e26e3a4d4f445b8c27a3fd73768e9d (patch) | |
| tree | 63447667ac4f76b0442dfea7a46149c6334ee6c1 | |
| parent | 183458263b0aea42a6ea8b8417117abcae178679 (diff) | |
| download | rust-47abf2e144e26e3a4d4f445b8c27a3fd73768e9d.tar.gz rust-47abf2e144e26e3a4d4f445b8c27a3fd73768e9d.zip | |
trait_sel: extend fast path with sized hierarchy
Extend the fast path for `Sized` traits to include constness and `MetaSized`.
| -rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/sty.rs | 26 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/util.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/solve/delegate.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/util.rs | 18 |
6 files changed, 47 insertions, 23 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index a43449a8f99..2df19cb21d5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -22,8 +22,9 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{ - self, AdtKind, CanonicalUserType, GenericArgsRef, GenericParamDefKind, IsIdentity, Ty, TyCtxt, - TypeFoldable, TypeVisitable, TypeVisitableExt, UserArgs, UserSelfTy, + self, AdtKind, CanonicalUserType, GenericArgsRef, GenericParamDefKind, IsIdentity, + SizedTraitKind, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt, UserArgs, + UserSelfTy, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -439,7 +440,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || {}, ); // Sized types have static alignment, and so do slices. - if tail.is_trivially_sized(self.tcx) || matches!(tail.kind(), ty::Slice(..)) { + if tail.has_trivial_sizedness(self.tcx, SizedTraitKind::Sized) + || matches!(tail.kind(), ty::Slice(..)) + { // Nothing else is required here. } else { // We can't be sure, let's required full `Sized`. diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 2adda8263a1..58829f72a72 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -15,6 +15,7 @@ use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension}; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use rustc_type_ir::TyKind::*; +use rustc_type_ir::solve::SizedTraitKind; use rustc_type_ir::walk::TypeWalker; use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, TypeVisitableExt, elaborate}; use tracing::instrument; @@ -1677,7 +1678,7 @@ impl<'tcx> Ty<'tcx> { let Some(pointee_ty) = self.builtin_deref(true) else { bug!("Type {self:?} is not a pointer or reference type") }; - if pointee_ty.is_trivially_sized(tcx) { + if pointee_ty.has_trivial_sizedness(tcx, SizedTraitKind::Sized) { tcx.types.unit } else { match pointee_ty.ptr_metadata_ty_or_tail(tcx, |x| x) { @@ -1778,17 +1779,17 @@ impl<'tcx> Ty<'tcx> { } } - /// Fast path helper for testing if a type is `Sized`. + /// Fast path helper for testing if a type is `Sized` or `MetaSized`. /// - /// Returning true means the type is known to implement `Sized`. Returning `false` means - /// nothing -- could be sized, might not be. + /// Returning true means the type is known to implement the sizedness trait. Returning `false` + /// means nothing -- could be sized, might not be. /// /// Note that we could never rely on the fact that a type such as `[_]` is trivially `!Sized` /// because we could be in a type environment with a bound such as `[_]: Copy`. A function with /// such a bound obviously never can be called, but that doesn't mean it shouldn't typecheck. /// This is why this method doesn't return `Option<bool>`. #[instrument(skip(tcx), level = "debug")] - pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool { + pub fn has_trivial_sizedness(self, tcx: TyCtxt<'tcx>, sizedness: SizedTraitKind) -> bool { match self.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Uint(_) @@ -1811,13 +1812,20 @@ impl<'tcx> Ty<'tcx> { | ty::Error(_) | ty::Dynamic(_, _, ty::DynStar) => true, - ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false, + ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) => match sizedness { + SizedTraitKind::Sized => false, + SizedTraitKind::MetaSized => true, + }, + + ty::Foreign(..) => match sizedness { + SizedTraitKind::Sized | SizedTraitKind::MetaSized => false, + }, - ty::Tuple(tys) => tys.last().is_none_or(|ty| ty.is_trivially_sized(tcx)), + ty::Tuple(tys) => tys.last().is_none_or(|ty| ty.has_trivial_sizedness(tcx, sizedness)), ty::Adt(def, args) => def - .sizedness_constraint(tcx, ty::SizedTraitKind::Sized) - .is_none_or(|ty| ty.instantiate(tcx, args).is_trivially_sized(tcx)), + .sizedness_constraint(tcx, sizedness) + .is_none_or(|ty| ty.instantiate(tcx, args).has_trivial_sizedness(tcx, sizedness)), ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false, diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 461d92f8006..51f57e71ce9 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -16,6 +16,7 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension}; use rustc_session::Limit; use rustc_span::sym; +use rustc_type_ir::solve::SizedTraitKind; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; @@ -1132,7 +1133,8 @@ impl<'tcx> Ty<'tcx> { /// strange rules like `<T as Foo<'static>>::Bar: Sized` that /// actually carry lifetime requirements. pub fn is_sized(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { - self.is_trivially_sized(tcx) || tcx.is_sized_raw(typing_env.as_query_input(self)) + self.has_trivial_sizedness(tcx, SizedTraitKind::Sized) + || tcx.is_sized_raw(typing_env.as_query_input(self)) } /// Checks whether values of this type `T` implement the `Freeze` 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 edca264733b..d4cc1ceb280 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -556,7 +556,7 @@ fn attempt_dyn_to_enum_suggestion( let Some(impl_type) = tcx.type_of(*impl_id).no_bound_vars() else { return None }; // Obviously unsized impl types won't be usable in an enum. - // Note: this doesn't use `Ty::is_trivially_sized` because that function + // Note: this doesn't use `Ty::has_trivial_sizedness` because that function // defaults to assuming that things are *not* sized, whereas we want to // fall back to assuming that things may be sized. match impl_type.kind() { diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 69a0c0809b5..b247c2c2968 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -12,7 +12,7 @@ use rustc_infer::traits::solve::Goal; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::Certainty; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt as _, TypingMode, + self, SizedTraitKind, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt as _, TypingMode, }; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; @@ -79,7 +79,14 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< Some(LangItem::Sized) if self .resolve_vars_if_possible(trait_pred.self_ty().skip_binder()) - .is_trivially_sized(self.0.tcx) => + .has_trivial_sizedness(self.0.tcx, SizedTraitKind::Sized) => + { + return Some(Certainty::Yes); + } + Some(LangItem::MetaSized) + if self + .resolve_vars_if_possible(trait_pred.self_ty().skip_binder()) + .has_trivial_sizedness(self.0.tcx, SizedTraitKind::MetaSized) => { return Some(Certainty::Yes); } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 0723aebd5d2..bf2cbe7c047 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -7,7 +7,7 @@ use rustc_infer::infer::InferCtxt; pub use rustc_infer::traits::util::*; use rustc_middle::bug; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + self, SizedTraitKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; pub use rustc_next_trait_solver::placeholder::BoundVarReplacer; use rustc_span::Span; @@ -362,15 +362,19 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> { } pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>) -> bool { - // Proving `Sized` very often on "obviously sized" types like `&T`, accounts for about 60% - // percentage of the predicates we have to prove. No need to canonicalize and all that for - // such cases. + // Proving `Sized`/`MetaSized`, very often on "obviously sized" types like + // `&T`, accounts for about 60% percentage of the predicates we have to prove. No need to + // canonicalize and all that for such cases. if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) = predicate.kind().skip_binder() { - if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) - && trait_ref.self_ty().is_trivially_sized(tcx) - { + let sizedness = match tcx.as_lang_item(trait_ref.def_id()) { + Some(LangItem::Sized) => SizedTraitKind::Sized, + Some(LangItem::MetaSized) => SizedTraitKind::MetaSized, + _ => return false, + }; + + if trait_ref.self_ty().has_trivial_sizedness(tcx, sizedness) { debug!("fast path -- trivial sizedness"); return true; } |
