11use rustc_data_structures:: fx:: FxHashSet ;
22use rustc_hir as hir;
33use rustc_hir:: def:: DefKind ;
4+ use rustc_hir:: LangItem ;
45use rustc_index:: bit_set:: BitSet ;
56use rustc_middle:: query:: Providers ;
6- use rustc_middle:: ty:: { self , EarlyBinder , Ty , TyCtxt , TypeVisitor } ;
7+ use rustc_middle:: ty:: { self , EarlyBinder , Ty , TyCtxt , TypeVisitableExt , TypeVisitor } ;
78use rustc_middle:: ty:: { ToPredicate , TypeSuperVisitable , TypeVisitable } ;
89use rustc_span:: def_id:: { DefId , LocalDefId , CRATE_DEF_ID } ;
910use rustc_span:: DUMMY_SP ;
1011use rustc_trait_selection:: traits;
1112
12- fn sized_constraint_for_ty < ' tcx > (
13- tcx : TyCtxt < ' tcx > ,
14- adtdef : ty:: AdtDef < ' tcx > ,
15- ty : Ty < ' tcx > ,
16- ) -> Vec < Ty < ' tcx > > {
13+ #[ instrument( level = "debug" , skip( tcx) , ret) ]
14+ fn sized_constraint_for_ty < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> Option < Ty < ' tcx > > {
1715 use rustc_type_ir:: TyKind :: * ;
1816
19- let result = match ty. kind ( ) {
20- Bool | Char | Int ( ..) | Uint ( ..) | Float ( ..) | RawPtr ( ..) | Ref ( ..) | FnDef ( ..)
21- | FnPtr ( _) | Array ( ..) | Closure ( ..) | CoroutineClosure ( ..) | Coroutine ( ..) | Never => {
22- vec ! [ ]
23- }
24-
25- Str | Dynamic ( ..) | Slice ( _) | Foreign ( ..) | Error ( _) | CoroutineWitness ( ..) => {
26- // these are never sized - return the target type
27- vec ! [ ty]
28- }
29-
30- Tuple ( tys) => match tys. last ( ) {
31- None => vec ! [ ] ,
32- Some ( & ty) => sized_constraint_for_ty ( tcx, adtdef, ty) ,
33- } ,
34-
17+ match ty. kind ( ) {
18+ // these are always sized
19+ Bool
20+ | Char
21+ | Int ( ..)
22+ | Uint ( ..)
23+ | Float ( ..)
24+ | RawPtr ( ..)
25+ | Ref ( ..)
26+ | FnDef ( ..)
27+ | FnPtr ( ..)
28+ | Array ( ..)
29+ | Closure ( ..)
30+ | CoroutineClosure ( ..)
31+ | Coroutine ( ..)
32+ | CoroutineWitness ( ..)
33+ | Never
34+ | Dynamic ( _, _, ty:: DynStar ) => None ,
35+
36+ // these are never sized
37+ Str | Slice ( ..) | Dynamic ( _, _, ty:: Dyn ) | Foreign ( ..) => Some ( ty) ,
38+
39+ Tuple ( tys) => tys. last ( ) . and_then ( |& ty| sized_constraint_for_ty ( tcx, ty) ) ,
40+
41+ // recursive case
3542 Adt ( adt, args) => {
36- // recursive case
37- let adt_tys = adt. sized_constraint ( tcx) ;
38- debug ! ( "sized_constraint_for_ty({:?}) intermediate = {:?}" , ty, adt_tys) ;
39- adt_tys
40- . iter_instantiated ( tcx, args)
41- . flat_map ( |ty| sized_constraint_for_ty ( tcx, adtdef, ty) )
42- . collect ( )
43+ let intermediate = adt. sized_constraint ( tcx) ;
44+ intermediate. and_then ( |intermediate| {
45+ let ty = intermediate. instantiate ( tcx, args) ;
46+ sized_constraint_for_ty ( tcx, ty)
47+ } )
4348 }
4449
45- Alias ( ..) => {
46- // must calculate explicitly.
47- // FIXME: consider special-casing always-Sized projections
48- vec ! [ ty]
49- }
50-
51- Param ( ..) => {
52- // perf hack: if there is a `T: Sized` bound, then
53- // we know that `T` is Sized and do not need to check
54- // it on the impl.
55-
56- let Some ( sized_trait_def_id) = tcx. lang_items ( ) . sized_trait ( ) else { return vec ! [ ty] } ;
57- let predicates = tcx. predicates_of ( adtdef. did ( ) ) . predicates ;
58- if predicates. iter ( ) . any ( |( p, _) | {
59- p. as_trait_clause ( ) . is_some_and ( |trait_pred| {
60- trait_pred. def_id ( ) == sized_trait_def_id
61- && trait_pred. self_ty ( ) . skip_binder ( ) == ty
62- } )
63- } ) {
64- vec ! [ ]
65- } else {
66- vec ! [ ty]
67- }
68- }
50+ // these can be sized or unsized
51+ Param ( ..) | Alias ( ..) | Error ( _) => Some ( ty) ,
6952
7053 Placeholder ( ..) | Bound ( ..) | Infer ( ..) => {
71- bug ! ( "unexpected type `{:?}` in sized_constraint_for_ty" , ty )
54+ bug ! ( "unexpected type `{ty :?}` in sized_constraint_for_ty" )
7255 }
73- } ;
74- debug ! ( "sized_constraint_for_ty({:?}) = {:?}" , ty, result) ;
75- result
56+ }
7657}
7758
7859fn defaultness ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> hir:: Defaultness {
@@ -90,29 +71,45 @@ fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
9071///
9172/// In fact, there are only a few options for the types in the constraint:
9273/// - an obviously-unsized type
93- /// - a type parameter or projection whose Sizedness can't be known
94- /// - a tuple of type parameters or projections, if there are multiple
95- /// such.
96- /// - an Error, if a type is infinitely sized
74+ /// - a type parameter or projection whose sizedness can't be known
75+ #[ instrument( level = "debug" , skip( tcx) , ret) ]
9776fn adt_sized_constraint < ' tcx > (
9877 tcx : TyCtxt < ' tcx > ,
9978 def_id : DefId ,
100- ) -> ty :: EarlyBinder < & ' tcx ty:: List < Ty < ' tcx > > > {
79+ ) -> Option < ty:: EarlyBinder < Ty < ' tcx > > > {
10180 if let Some ( def_id) = def_id. as_local ( ) {
102- if let ty:: Representability :: Infinite ( guar ) = tcx. representability ( def_id) {
103- return ty :: EarlyBinder :: bind ( tcx . mk_type_list ( & [ Ty :: new_error ( tcx , guar ) ] ) ) ;
81+ if let ty:: Representability :: Infinite ( _ ) = tcx. representability ( def_id) {
82+ return None ;
10483 }
10584 }
10685 let def = tcx. adt_def ( def_id) ;
10786
108- let result =
109- tcx. mk_type_list_from_iter ( def. variants ( ) . iter ( ) . filter_map ( |v| v. tail_opt ( ) ) . flat_map (
110- |f| sized_constraint_for_ty ( tcx, def, tcx. type_of ( f. did ) . instantiate_identity ( ) ) ,
111- ) ) ;
87+ if !def. is_struct ( ) {
88+ bug ! ( "`adt_sized_constraint` called on non-struct type: {def:?}" ) ;
89+ }
90+
91+ let tail_def = def. non_enum_variant ( ) . tail_opt ( ) ?;
92+ let tail_ty = tcx. type_of ( tail_def. did ) . instantiate_identity ( ) ;
11293
113- debug ! ( "adt_sized_constraint: {:?} => {:?}" , def, result) ;
94+ let constraint_ty = sized_constraint_for_ty ( tcx, tail_ty) ?;
95+ if constraint_ty. references_error ( ) {
96+ return None ;
97+ }
98+
99+ // perf hack: if there is a `constraint_ty: Sized` bound, then we know
100+ // that the type is sized and do not need to check it on the impl.
101+ let sized_trait_def_id = tcx. require_lang_item ( LangItem :: Sized , None ) ;
102+ let predicates = tcx. predicates_of ( def. did ( ) ) . predicates ;
103+ if predicates. iter ( ) . any ( |( p, _) | {
104+ p. as_trait_clause ( ) . is_some_and ( |trait_pred| {
105+ trait_pred. def_id ( ) == sized_trait_def_id
106+ && trait_pred. self_ty ( ) . skip_binder ( ) == constraint_ty
107+ } )
108+ } ) {
109+ return None ;
110+ }
114111
115- ty:: EarlyBinder :: bind ( result )
112+ Some ( ty:: EarlyBinder :: bind ( constraint_ty ) )
116113}
117114
118115/// See `ParamEnv` struct definition for details.
0 commit comments