-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
clean up Sized
checking
#122493
clean up Sized
checking
#122493
Changes from 4 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😊 |
||
/// 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`]. | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -154,13 +154,24 @@ 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 Adt where T: Sized forall T in field types | ||||||
// 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<Args...> where sized_constraint(Adt)<Args...>: 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<Args...> 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()); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
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))] | ||||||
})) | ||||||
} | ||||||
} | ||||||
} | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2120,11 +2120,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | |
ty::Adt(def, args) => { | ||
let sized_crit = def.sized_constraint(self.tcx()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also use |
||
// (*) 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, | ||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -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<Ty<'tcx>> { | ||||||||
#[instrument(level = "debug", skip(tcx), ret)] | ||||||||
fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { | ||||||||
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| { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
very much a nit 😅 |
||||||||
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<Ty<'tcx>>> { | ||||||||
) -> Option<ty::EarlyBinder<Ty<'tcx>>> { | ||||||||
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(_) = 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. | ||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 🤷