Skip to content

Commit 121b836

Browse files
committed
trait_sel: add sizedness traits to fast path
There's an existing fast path for the `type_op_prove_predicate` predicate which can be extended to support the new sizedness traits and host effect predicates, avoiding lots of machinery.
1 parent 08c8602 commit 121b836

File tree

6 files changed

+80
-29
lines changed

6 files changed

+80
-29
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM;
2323
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
2424
use rustc_middle::ty::{
2525
self, AdtKind, CanonicalUserType, GenericArgKind, GenericArgsRef, GenericParamDefKind,
26-
IsIdentity, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt, UserArgs, UserSelfTy,
26+
IsIdentity, SizedTraitKind, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt,
27+
UserArgs, 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

+32-16
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_hir::def_id::DefId;
1616
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension};
1717
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
1818
use rustc_type_ir::TyKind::*;
19+
use rustc_type_ir::solve::SizedTraitKind;
1920
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, TypeVisitableExt, elaborate};
2021
use tracing::instrument;
2122
use ty::util::{AsyncDropGlueMorphology, IntTypeExt};
@@ -1783,7 +1784,7 @@ impl<'tcx> Ty<'tcx> {
17831784
let Some(pointee_ty) = self.builtin_deref(true) else {
17841785
bug!("Type {self:?} is not a pointer or reference type")
17851786
};
1786-
if pointee_ty.is_trivially_sized(tcx) {
1787+
if pointee_ty.has_trivial_sizedness(tcx, SizedTraitKind::Sized) {
17871788
tcx.types.unit
17881789
} else {
17891790
match pointee_ty.ptr_metadata_ty_or_tail(tcx, |x| x) {
@@ -1886,17 +1887,16 @@ impl<'tcx> Ty<'tcx> {
18861887
}
18871888
}
18881889

1889-
/// Fast path helper for testing if a type is `Sized`.
1890+
/// Fast path helper for testing if a type is `Sized`, `MetaSized` or `PointeeSized`.
18901891
///
1891-
/// Returning true means the type is known to be sized. Returning
1892-
/// `false` means nothing -- could be sized, might not be.
1892+
/// Returning true means the type is known to implement the sizedness trait. Returning `false`
1893+
/// means nothing -- could be sized, might not be.
18931894
///
1894-
/// Note that we could never rely on the fact that a type such as `[_]` is
1895-
/// trivially `!Sized` because we could be in a type environment with a
1896-
/// bound such as `[_]: Copy`. A function with such a bound obviously never
1897-
/// can be called, but that doesn't mean it shouldn't typecheck. This is why
1898-
/// this method doesn't return `Option<bool>`.
1899-
pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool {
1895+
/// Note that we could never rely on the fact that a type such as `[_]` is trivially `!Sized`
1896+
/// because we could be in a type environment with a bound such as `[_]: Copy`. A function with
1897+
/// such a bound obviously never can be called, but that doesn't mean it shouldn't typecheck.
1898+
/// This is why this method doesn't return `Option<bool>`.
1899+
pub fn has_trivial_sizedness(self, tcx: TyCtxt<'tcx>, sizedness: SizedTraitKind) -> bool {
19001900
match self.kind() {
19011901
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
19021902
| ty::Uint(_)
@@ -1919,20 +1919,36 @@ impl<'tcx> Ty<'tcx> {
19191919
| ty::Error(_)
19201920
| ty::Dynamic(_, _, ty::DynStar) => true,
19211921

1922-
ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false,
1922+
ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) => match sizedness {
1923+
SizedTraitKind::Sized => false,
1924+
SizedTraitKind::MetaSized | SizedTraitKind::PointeeSized => true,
1925+
},
1926+
1927+
ty::Foreign(..) => match sizedness {
1928+
SizedTraitKind::Sized | SizedTraitKind::MetaSized => false,
1929+
SizedTraitKind::PointeeSized => true,
1930+
},
19231931

1924-
ty::Tuple(tys) => tys.last().is_none_or(|ty| ty.is_trivially_sized(tcx)),
1932+
ty::Tuple(tys) => tys.last().is_none_or(|ty| ty.has_trivial_sizedness(tcx, sizedness)),
19251933

1926-
ty::Adt(def, args) => def
1927-
.sized_constraint(tcx)
1928-
.is_none_or(|ty| ty.instantiate(tcx, args).is_trivially_sized(tcx)),
1934+
ty::Adt(def, args) => {
1935+
let constraint = match sizedness {
1936+
SizedTraitKind::Sized => def.sized_constraint(tcx),
1937+
SizedTraitKind::MetaSized => def.meta_sized_constraint(tcx),
1938+
SizedTraitKind::PointeeSized => def.pointee_sized_constraint(tcx),
1939+
};
1940+
1941+
constraint.is_none_or(|ty| {
1942+
ty.instantiate(tcx, args).has_trivial_sizedness(tcx, sizedness)
1943+
})
1944+
}
19291945

19301946
ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false,
19311947

19321948
ty::Infer(ty::TyVar(_)) => false,
19331949

19341950
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
1935-
bug!("`is_trivially_sized` applied to unexpected type: {:?}", self)
1951+
bug!("`has_trivial_sizedness` applied to unexpected type: {:?}", self)
19361952
}
19371953
}
19381954
}

compiler/rustc_middle/src/ty/util.rs

+3-1
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

@@ -1189,7 +1190,8 @@ impl<'tcx> Ty<'tcx> {
11891190
/// strange rules like `<T as Foo<'static>>::Bar: Sized` that
11901191
/// actually carry lifetime requirements.
11911192
pub fn is_sized(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
1192-
self.is_trivially_sized(tcx) || tcx.is_sized_raw(typing_env.as_query_input(self))
1193+
self.has_trivial_sizedness(tcx, SizedTraitKind::Sized)
1194+
|| tcx.is_sized_raw(typing_env.as_query_input(self))
11931195
}
11941196

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

compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,8 @@ where
196196
/// trait to be implemented (see the trait goal for that), as these are orthogonal. This means that
197197
/// the effect predicate can succeed while the trait predicate can fail - this is unintuitive but
198198
/// allows this function to be much simpler.
199-
// NOTE: Keep this in sync with `evaluate_host_effect_for_sizedness_goal` in the old solver.
199+
// NOTE: Keep this in sync with `evaluate_host_effect_for_sizedness_goal` in the old solver and
200+
// `ProvePredicate::try_fast_path`
200201
#[instrument(level = "trace", skip(cx), ret)]
201202
pub(in crate::solve) fn const_conditions_for_sizedness<I: Interner>(
202203
cx: I,

compiler/rustc_trait_selection/src/traits/effects.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ fn evaluate_host_effect_from_builtin_impls<'tcx>(
253253
}
254254
}
255255

256-
// NOTE: Keep this in sync with `const_conditions_for_sizedness` in the new solver.
256+
// NOTE: Keep this in sync with `const_conditions_for_sizedness` in the new solver and
257+
// `ProvePredicate::try_fast_path`
257258
fn evaluate_host_effect_for_sizedness_goal<'tcx>(
258259
selcx: &mut SelectionContext<'_, 'tcx>,
259260
obligation: &HostEffectObligation<'tcx>,

compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs

+36-8
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ use rustc_infer::traits::Obligation;
33
use rustc_middle::traits::ObligationCause;
44
use rustc_middle::traits::query::NoSolution;
55
pub use rustc_middle::traits::query::type_op::ProvePredicate;
6-
use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt};
6+
use rustc_middle::ty::{self, ParamEnvAnd, SizedTraitKind, TyCtxt};
77
use rustc_span::Span;
8+
use rustc_type_ir::TypeVisitableExt;
89

910
use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse};
1011
use crate::traits::ObligationCtxt;
@@ -16,16 +17,43 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
1617
tcx: TyCtxt<'tcx>,
1718
key: &ParamEnvAnd<'tcx, Self>,
1819
) -> Option<Self::QueryResponse> {
19-
// Proving Sized, very often on "obviously sized" types like
20-
// `&T`, accounts for about 60% percentage of the predicates
21-
// we have to prove. No need to canonicalize and all that for
22-
// such cases.
20+
// Proving `Sized`/`MetaSized`/`PointeeSized`, very often on "obviously sized" types like
21+
// `&T`, accounts for about 60% percentage of the predicates we have to prove. No need to
22+
// canonicalize and all that for such cases.
2323
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) =
2424
key.value.predicate.kind().skip_binder()
25-
&& tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized)
26-
&& trait_ref.self_ty().is_trivially_sized(tcx)
2725
{
28-
return Some(());
26+
let sizedness = if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) {
27+
Some(SizedTraitKind::Sized)
28+
} else if tcx.is_lang_item(trait_ref.def_id(), LangItem::MetaSized) {
29+
Some(SizedTraitKind::MetaSized)
30+
} else if tcx.is_lang_item(trait_ref.def_id(), LangItem::PointeeSized) {
31+
Some(SizedTraitKind::PointeeSized)
32+
} else {
33+
None
34+
};
35+
36+
if let Some(sizedness) = sizedness
37+
&& trait_ref.self_ty().has_trivial_sizedness(tcx, sizedness)
38+
{
39+
return Some(());
40+
}
41+
}
42+
43+
// Likewise, determining if a sizedness trait is implemented const-ly is a trivial
44+
// determination that can happen in the fast path.
45+
//
46+
// NOTE: Keep this in sync with `evaluate_host_effect_for_sizedness_goal` in the old solver,
47+
// `const_conditions_for_sizedness` in the new solver.
48+
if let ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(host_pred)) =
49+
key.value.predicate.kind().skip_binder()
50+
{
51+
let is_sizedness = tcx.is_lang_item(host_pred.def_id(), LangItem::Sized)
52+
&& tcx.is_lang_item(host_pred.def_id(), LangItem::MetaSized);
53+
54+
if is_sizedness && !host_pred.self_ty().has_non_const_sizedness() {
55+
return Some(());
56+
}
2957
}
3058

3159
if let ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) =

0 commit comments

Comments
 (0)