From 0e7e1bfdbc52931d03e40438a74b400276e46bbd Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Wed, 13 Mar 2024 18:52:25 +0100 Subject: [PATCH 1/5] make `Representability::Infinite` carry `ErrorGuaranteed` --- compiler/rustc_middle/src/ty/adt.rs | 2 +- compiler/rustc_middle/src/ty/inhabitedness/mod.rs | 2 +- compiler/rustc_middle/src/values.rs | 8 ++++---- compiler/rustc_ty_utils/src/representability.rs | 2 +- compiler/rustc_ty_utils/src/ty.rs | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 2e1c7df6454aa..36050792adc4b 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -601,5 +601,5 @@ impl<'tcx> AdtDef<'tcx> { #[derive(HashStable)] pub enum Representability { Representable, - Infinite, + Infinite(ErrorGuaranteed), } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index bbcc244cb26de..da5d57db5bef9 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -61,7 +61,7 @@ pub(crate) fn provide(providers: &mut Providers) { /// requires calling [`InhabitedPredicate::instantiate`] fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> { if let Some(def_id) = def_id.as_local() { - if matches!(tcx.representability(def_id), ty::Representability::Infinite) { + if matches!(tcx.representability(def_id), ty::Representability::Infinite(_)) { return InhabitedPredicate::True; } } diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index f7a3879a7d40c..5c17c0b3088fe 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -106,8 +106,8 @@ impl<'tcx> Value> for Representability { representable_ids.insert(def_id); } } - recursive_type_error(tcx, item_and_field_ids, &representable_ids); - Representability::Infinite + let guar = recursive_type_error(tcx, item_and_field_ids, &representable_ids); + Representability::Infinite(guar) } } @@ -268,7 +268,7 @@ pub fn recursive_type_error( tcx: TyCtxt<'_>, mut item_and_field_ids: Vec<(LocalDefId, LocalDefId)>, representable_ids: &FxHashSet, -) { +) -> ErrorGuaranteed { const ITEM_LIMIT: usize = 5; // Rotate the cycle so that the item with the lowest span is first @@ -344,7 +344,7 @@ pub fn recursive_type_error( suggestion, Applicability::HasPlaceholders, ) - .emit(); + .emit() } fn find_item_ty_spans( diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index bb546cee2dd80..a5ffa553c2a8a 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -12,7 +12,7 @@ pub(crate) fn provide(providers: &mut Providers) { macro_rules! rtry { ($e:expr) => { match $e { - e @ Representability::Infinite => return e, + e @ Representability::Infinite(_) => return e, Representability::Representable => {} } }; diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 2b6b91672c3a5..310fd55e863ad 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -99,8 +99,8 @@ fn adt_sized_constraint<'tcx>( def_id: DefId, ) -> ty::EarlyBinder<&'tcx ty::List>> { if let Some(def_id) = def_id.as_local() { - if matches!(tcx.representability(def_id), ty::Representability::Infinite) { - return ty::EarlyBinder::bind(tcx.mk_type_list(&[Ty::new_misc_error(tcx)])); + if let ty::Representability::Infinite(guar) = tcx.representability(def_id) { + return ty::EarlyBinder::bind(tcx.mk_type_list(&[Ty::new_error(tcx, guar)])); } } let def = tcx.adt_def(def_id); From 8ad94111adb790723a7db2e7449204b5f68e9c48 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Wed, 13 Mar 2024 23:33:45 +0100 Subject: [PATCH 2/5] clean up ADT sized constraint computation --- compiler/rustc_middle/src/query/mod.rs | 4 +- compiler/rustc_middle/src/ty/adt.rs | 8 +- compiler/rustc_middle/src/ty/sty.rs | 2 +- .../src/solve/assembly/structural_traits.rs | 14 +- .../src/traits/select/mod.rs | 8 +- compiler/rustc_ty_utils/src/ty.rs | 137 +++++++++--------- ...ied-gat-bound-during-assoc-ty-selection.rs | 2 +- ...gat-bound-during-assoc-ty-selection.stderr | 13 +- 8 files changed, 93 insertions(+), 95 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 865299e15c803..c73dc7cd28130 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -703,8 +703,8 @@ rustc_queries! { separate_provide_extern } - query adt_sized_constraint(key: DefId) -> ty::EarlyBinder<&'tcx ty::List>> { - desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) } + query adt_sized_constraint(key: DefId) -> Option>> { + desc { |tcx| "computing `Sized` constraint for `{}`", tcx.def_path_str(key) } } query adt_dtorck_constraint( diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 36050792adc4b..a71443167699f 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -590,10 +590,10 @@ impl<'tcx> AdtDef<'tcx> { tcx.adt_destructor(self.did()) } - /// Returns a list of types such that `Self: Sized` if and only if that - /// type is `Sized`, or `ty::Error` if this type has a recursive layout. - pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx ty::List>> { - tcx.adt_sized_constraint(self.did()) + /// Returns a type such that `Self: Sized` if and only if that type is `Sized`, + /// or `None` if the type is always sized. + pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option>> { + if self.is_struct() { tcx.adt_sized_constraint(self.did()) } else { None } } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 11065b2a382be..7ff0b8dac4c89 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2490,7 +2490,7 @@ impl<'tcx> Ty<'tcx> { ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)), - ty::Adt(def, _args) => def.sized_constraint(tcx).skip_binder().is_empty(), + ty::Adt(def, _args) => def.sized_constraint(tcx).is_none(), ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false, diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 2bfb86b592b0d..8822e55736f78 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -157,10 +157,20 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( // impl Sized for (T1, T2, .., Tn) where T1: Sized, T2: Sized, .. Tn: Sized ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()), - // impl Sized for Adt where T: Sized forall T in field types + // impl Sized for Adt where sized_constraint(Adt): Sized + // `sized_constraint(Adt)` is the deepest struct trail that can be determined + // by the definition of `Adt`, independent of the generic args. + // impl Sized for Adt if sized_constraint(Adt) == None + // As a performance optimization, `sized_constraint(Adt)` can return `None` + // if the ADTs definition implies that it is sized by for all possible args. + // In this case, the builtin impl will have no nested subgoals. This is a + // "best effort" optimization and `sized_constraint` may return `Some`, even + // if the ADT is sized for all possible args. ty::Adt(def, args) => { let sized_crit = def.sized_constraint(ecx.tcx()); - Ok(sized_crit.iter_instantiated(ecx.tcx(), args).map(ty::Binder::dummy).collect()) + Ok(sized_crit.map_or_else(Vec::new, |ty| { + vec![ty::Binder::dummy(ty.instantiate(ecx.tcx(), args))] + })) } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a6bd1ba9c3f88..a84acf6765701 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2120,11 +2120,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::Adt(def, args) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here - Where( - obligation - .predicate - .rebind(sized_crit.iter_instantiated(self.tcx(), args).collect()), - ) + Where(obligation.predicate.rebind( + sized_crit.map_or_else(Vec::new, |ty| vec![ty.instantiate(self.tcx(), args)]), + )) } ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => None, diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 310fd55e863ad..cffae62e3f028 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -1,78 +1,59 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::DefKind; +use rustc_hir::LangItem; use rustc_index::bit_set::BitSet; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitor}; +use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitableExt, TypeVisitor}; use rustc_middle::ty::{ToPredicate, TypeSuperVisitable, TypeVisitable}; use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits; -fn sized_constraint_for_ty<'tcx>( - tcx: TyCtxt<'tcx>, - adtdef: ty::AdtDef<'tcx>, - ty: Ty<'tcx>, -) -> Vec> { +#[instrument(level = "debug", skip(tcx), ret)] +fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option> { use rustc_type_ir::TyKind::*; - let result = match ty.kind() { - Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) - | FnPtr(_) | Array(..) | Closure(..) | CoroutineClosure(..) | Coroutine(..) | Never => { - vec![] - } - - Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | CoroutineWitness(..) => { - // these are never sized - return the target type - vec![ty] - } - - Tuple(tys) => match tys.last() { - None => vec![], - Some(&ty) => sized_constraint_for_ty(tcx, adtdef, ty), - }, - + match ty.kind() { + // these are always sized + Bool + | Char + | Int(..) + | Uint(..) + | Float(..) + | RawPtr(..) + | Ref(..) + | FnDef(..) + | FnPtr(..) + | Array(..) + | Closure(..) + | CoroutineClosure(..) + | Coroutine(..) + | CoroutineWitness(..) + | Never + | Dynamic(_, _, ty::DynStar) => None, + + // these are never sized + Str | Slice(..) | Dynamic(_, _, ty::Dyn) | Foreign(..) => Some(ty), + + Tuple(tys) => tys.last().and_then(|&ty| sized_constraint_for_ty(tcx, ty)), + + // recursive case Adt(adt, args) => { - // recursive case - let adt_tys = adt.sized_constraint(tcx); - debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys); - adt_tys - .iter_instantiated(tcx, args) - .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty)) - .collect() + let intermediate = adt.sized_constraint(tcx); + intermediate.and_then(|intermediate| { + let ty = intermediate.instantiate(tcx, args); + sized_constraint_for_ty(tcx, ty) + }) } - Alias(..) => { - // must calculate explicitly. - // FIXME: consider special-casing always-Sized projections - vec![ty] - } - - Param(..) => { - // perf hack: if there is a `T: Sized` bound, then - // we know that `T` is Sized and do not need to check - // it on the impl. - - let Some(sized_trait_def_id) = tcx.lang_items().sized_trait() else { return vec![ty] }; - let predicates = tcx.predicates_of(adtdef.did()).predicates; - if predicates.iter().any(|(p, _)| { - p.as_trait_clause().is_some_and(|trait_pred| { - trait_pred.def_id() == sized_trait_def_id - && trait_pred.self_ty().skip_binder() == ty - }) - }) { - vec![] - } else { - vec![ty] - } - } + // these can be sized or unsized + Param(..) | Alias(..) | Error(_) => Some(ty), Placeholder(..) | Bound(..) | Infer(..) => { - bug!("unexpected type `{:?}` in sized_constraint_for_ty", ty) + bug!("unexpected type `{ty:?}` in sized_constraint_for_ty") } - }; - debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result); - result + } } fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness { @@ -90,29 +71,45 @@ fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness { /// /// In fact, there are only a few options for the types in the constraint: /// - an obviously-unsized type -/// - a type parameter or projection whose Sizedness can't be known -/// - a tuple of type parameters or projections, if there are multiple -/// such. -/// - an Error, if a type is infinitely sized +/// - a type parameter or projection whose sizedness can't be known +#[instrument(level = "debug", skip(tcx), ret)] fn adt_sized_constraint<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, -) -> ty::EarlyBinder<&'tcx ty::List>> { +) -> Option>> { if let Some(def_id) = def_id.as_local() { - if let ty::Representability::Infinite(guar) = tcx.representability(def_id) { - return ty::EarlyBinder::bind(tcx.mk_type_list(&[Ty::new_error(tcx, guar)])); + if let ty::Representability::Infinite(_) = tcx.representability(def_id) { + return None; } } let def = tcx.adt_def(def_id); - let result = - tcx.mk_type_list_from_iter(def.variants().iter().filter_map(|v| v.tail_opt()).flat_map( - |f| sized_constraint_for_ty(tcx, def, tcx.type_of(f.did).instantiate_identity()), - )); + if !def.is_struct() { + bug!("`adt_sized_constraint` called on non-struct type: {def:?}"); + } + + let tail_def = def.non_enum_variant().tail_opt()?; + let tail_ty = tcx.type_of(tail_def.did).instantiate_identity(); - debug!("adt_sized_constraint: {:?} => {:?}", def, result); + let constraint_ty = sized_constraint_for_ty(tcx, tail_ty)?; + if constraint_ty.references_error() { + return None; + } + + // perf hack: if there is a `constraint_ty: Sized` bound, then we know + // that the type is sized and do not need to check it on the impl. + let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, None); + let predicates = tcx.predicates_of(def.did()).predicates; + if predicates.iter().any(|(p, _)| { + p.as_trait_clause().is_some_and(|trait_pred| { + trait_pred.def_id() == sized_trait_def_id + && trait_pred.self_ty().skip_binder() == constraint_ty + }) + }) { + return None; + } - ty::EarlyBinder::bind(result) + Some(ty::EarlyBinder::bind(constraint_ty)) } /// See `ParamEnv` struct definition for details. diff --git a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs index 252dc7d751e65..86da6ebfaaa42 100644 --- a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs +++ b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs @@ -29,5 +29,5 @@ where fn main() { let mut list = RcNode::::new(); - //~^ ERROR the size for values of type `Node` cannot be known at compilation time + //~^ ERROR trait bounds were not satisfied } diff --git a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr index 7813370ae63f8..b31689dbf7365 100644 --- a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr +++ b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr @@ -15,20 +15,15 @@ help: consider relaxing the implicit `Sized` restriction LL | type Pointer: Deref + ?Sized; | ++++++++ -error[E0599]: the size for values of type `Node` cannot be known at compilation time +error[E0599]: the variant or associated item `new` exists for enum `Node`, but its trait bounds were not satisfied --> $DIR/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs:31:35 | LL | enum Node { - | ------------------------------ variant or associated item `new` not found for this enum because it doesn't satisfy `Node: Sized` + | ------------------------------ variant or associated item `new` not found for this enum ... LL | let mut list = RcNode::::new(); - | ^^^ doesn't have a size known at compile-time + | ^^^ variant or associated item cannot be called on `Node` due to unsatisfied trait bounds | -note: trait bound `Node: Sized` was not satisfied - --> $DIR/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs:4:18 - | -LL | type Pointer: Deref; - | ------- ^ unsatisfied trait bound introduced here note: trait bound `(dyn Deref> + 'static): Sized` was not satisfied --> $DIR/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs:23:29 | @@ -37,8 +32,6 @@ LL | impl Node LL | where LL | P::Pointer>: Sized, | ^^^^^ unsatisfied trait bound introduced here -note: the trait `Sized` must be implemented - --> $SRC_DIR/core/src/marker.rs:LL:COL error: aborting due to 2 previous errors From 8fe99f57a42fe2a2f5ed19d3b6c3a7b2b5455edd Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Wed, 13 Mar 2024 23:35:24 +0100 Subject: [PATCH 3/5] remove unnecessary sized checks --- .../rustc_const_eval/src/interpret/eval_context.rs | 8 ++++---- compiler/rustc_middle/src/ty/sty.rs | 11 +++++++---- .../rustc_trait_selection/src/solve/assembly/mod.rs | 2 +- .../src/solve/assembly/structural_traits.rs | 5 +++-- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 09e9cc4b35d31..a9c127af8d530 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1034,8 +1034,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx> { trace!("{:?} is now live", local); - // We avoid `ty.is_trivially_sized` since that (a) cannot assume WF, so it recurses through - // all fields of a tuple, and (b) does something expensive for ADTs. + // We avoid `ty.is_trivially_sized` since that does something expensive for ADTs. fn is_very_trivially_sized(ty: Ty<'_>) -> bool { match ty.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) @@ -1054,9 +1053,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never - | ty::Error(_) => true, + | ty::Error(_) + | ty::Dynamic(_, _, ty::DynStar) => true, - ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false, + ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false, ty::Tuple(tys) => tys.last().iter().all(|ty| is_very_trivially_sized(**ty)), diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 7ff0b8dac4c89..540936d7d8a6f 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2484,13 +2484,16 @@ impl<'tcx> Ty<'tcx> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never - | ty::Error(_) => true, + | ty::Error(_) + | ty::Dynamic(_, _, ty::DynStar) => true, - ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false, + ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false, - ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)), + ty::Tuple(tys) => tys.last().map_or(true, |ty| ty.is_trivially_sized(tcx)), - ty::Adt(def, _args) => def.sized_constraint(tcx).is_none(), + ty::Adt(def, args) => def + .sized_constraint(tcx) + .map_or(true, |ty| ty.instantiate(tcx, args).is_trivially_sized(tcx)), ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false, diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 9c7fa5216d766..9f33dce2a6dfe 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -128,7 +128,7 @@ pub(super) trait GoalKind<'tcx>: goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - /// A type is `Copy` or `Clone` if its components are `Sized`. + /// A type is `Sized` if its tail component is `Sized`. /// /// These components are given by built-in rules from /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`]. diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 8822e55736f78..e7e8ff66e3e88 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -154,8 +154,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( bug!("unexpected type `{ty}`") } - // impl Sized for (T1, T2, .., Tn) where T1: Sized, T2: Sized, .. Tn: Sized - ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()), + // impl Sized for () + // impl Sized for (T1, T2, .., Tn) where Tn: Sized if n >= 1 + ty::Tuple(tys) => Ok(tys.last().map_or_else(Vec::new, |&ty| vec![ty::Binder::dummy(ty)])), // impl Sized for Adt where sized_constraint(Adt): Sized // `sized_constraint(Adt)` is the deepest struct trail that can be determined From ee66acbea856f12694ea7c8033769a371a754ae3 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Wed, 13 Mar 2024 23:51:48 +0100 Subject: [PATCH 4/5] use a let chain --- .../src/traits/query/type_op/prove_predicate.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index 14f14ae6e2e01..63289746f5e5d 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -20,14 +20,11 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { // such cases. if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) = key.value.predicate.kind().skip_binder() + && let Some(sized_def_id) = tcx.lang_items().sized_trait() + && trait_ref.def_id() == sized_def_id + && trait_ref.self_ty().is_trivially_sized(tcx) { - if let Some(sized_def_id) = tcx.lang_items().sized_trait() { - if trait_ref.def_id() == sized_def_id { - if trait_ref.self_ty().is_trivially_sized(tcx) { - return Some(()); - } - } - } + return Some(()); } if let ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) = From 99efae342e8581d12f9017affba2a229a2cfa152 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Mon, 18 Mar 2024 22:28:29 +0100 Subject: [PATCH 5/5] address nits --- compiler/rustc_middle/src/query/mod.rs | 2 +- .../src/solve/assembly/structural_traits.rs | 9 +++++---- .../rustc_trait_selection/src/traits/select/mod.rs | 13 ++++++++----- compiler/rustc_ty_utils/src/ty.rs | 11 ++++------- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c73dc7cd28130..9f0d2a89e6d1c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -704,7 +704,7 @@ rustc_queries! { } query adt_sized_constraint(key: DefId) -> Option>> { - desc { |tcx| "computing `Sized` constraint for `{}`", tcx.def_path_str(key) } + desc { |tcx| "computing the `Sized` constraint for `{}`", tcx.def_path_str(key) } } query adt_dtorck_constraint( diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index e7e8ff66e3e88..faf8c55c4757b 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -168,10 +168,11 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( // "best effort" optimization and `sized_constraint` may return `Some`, even // if the ADT is sized for all possible args. ty::Adt(def, args) => { - let sized_crit = def.sized_constraint(ecx.tcx()); - Ok(sized_crit.map_or_else(Vec::new, |ty| { - vec![ty::Binder::dummy(ty.instantiate(ecx.tcx(), args))] - })) + if let Some(sized_crit) = def.sized_constraint(ecx.tcx()) { + Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.tcx(), args))]) + } else { + Ok(vec![]) + } } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a84acf6765701..f930b758e4202 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2118,11 +2118,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ), ty::Adt(def, args) => { - let sized_crit = def.sized_constraint(self.tcx()); - // (*) binder moved here - Where(obligation.predicate.rebind( - sized_crit.map_or_else(Vec::new, |ty| vec![ty.instantiate(self.tcx(), args)]), - )) + if let Some(sized_crit) = def.sized_constraint(self.tcx()) { + // (*) binder moved here + Where( + obligation.predicate.rebind(vec![sized_crit.instantiate(self.tcx(), args)]), + ) + } else { + Where(ty::Binder::dummy(Vec::new())) + } } ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => None, diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index cffae62e3f028..547a3cb5a8c3f 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -39,13 +39,10 @@ fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option tys.last().and_then(|&ty| sized_constraint_for_ty(tcx, ty)), // recursive case - Adt(adt, args) => { - let intermediate = adt.sized_constraint(tcx); - intermediate.and_then(|intermediate| { - let ty = intermediate.instantiate(tcx, args); - sized_constraint_for_ty(tcx, ty) - }) - } + Adt(adt, args) => adt.sized_constraint(tcx).and_then(|intermediate| { + let ty = intermediate.instantiate(tcx, args); + sized_constraint_for_ty(tcx, ty) + }), // these can be sized or unsized Param(..) | Alias(..) | Error(_) => Some(ty),