Skip to content

Commit 495807a

Browse files
author
Lukas Markeffsky
committed
clean up ADT sized constraint computation
1 parent d1ec4eb commit 495807a

File tree

8 files changed

+88
-92
lines changed

8 files changed

+88
-92
lines changed

compiler/rustc_middle/src/query/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -703,8 +703,8 @@ rustc_queries! {
703703
separate_provide_extern
704704
}
705705

706-
query adt_sized_constraint(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<Ty<'tcx>>> {
707-
desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) }
706+
query adt_sized_constraint(key: DefId) -> Option<ty::EarlyBinder<Ty<'tcx>>> {
707+
desc { |tcx| "computing `Sized` constraint for `{}`", tcx.def_path_str(key) }
708708
}
709709

710710
query adt_dtorck_constraint(

compiler/rustc_middle/src/ty/adt.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -590,10 +590,10 @@ impl<'tcx> AdtDef<'tcx> {
590590
tcx.adt_destructor(self.did())
591591
}
592592

593-
/// Returns a list of types such that `Self: Sized` if and only if that
594-
/// type is `Sized`, or `ty::Error` if this type has a recursive layout.
595-
pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx ty::List<Ty<'tcx>>> {
596-
tcx.adt_sized_constraint(self.did())
593+
/// Returns a type such that `Self: Sized` if and only if that type is `Sized`, or `None`
594+
/// if the type is always sized, or `ty::Error` if this type has a recursive layout.
595+
pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<Ty<'tcx>>> {
596+
if self.is_struct() { tcx.adt_sized_constraint(self.did()) } else { None }
597597
}
598598
}
599599

compiler/rustc_middle/src/ty/sty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2489,7 +2489,7 @@ impl<'tcx> Ty<'tcx> {
24892489

24902490
ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)),
24912491

2492-
ty::Adt(def, _args) => def.sized_constraint(tcx).skip_binder().is_empty(),
2492+
ty::Adt(def, _args) => def.sized_constraint(tcx).is_none(),
24932493

24942494
ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false,
24952495

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
156156

157157
ty::Adt(def, args) => {
158158
let sized_crit = def.sized_constraint(ecx.tcx());
159-
Ok(sized_crit.iter_instantiated(ecx.tcx(), args).map(ty::Binder::dummy).collect())
159+
Ok(sized_crit.map_or_else(Vec::new, |ty| {
160+
vec![ty::Binder::dummy(ty.instantiate(ecx.tcx(), args))]
161+
}))
160162
}
161163
}
162164
}

compiler/rustc_trait_selection/src/traits/select/mod.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -2120,11 +2120,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
21202120
ty::Adt(def, args) => {
21212121
let sized_crit = def.sized_constraint(self.tcx());
21222122
// (*) binder moved here
2123-
Where(
2124-
obligation
2125-
.predicate
2126-
.rebind(sized_crit.iter_instantiated(self.tcx(), args).collect()),
2127-
)
2123+
Where(obligation.predicate.rebind(
2124+
sized_crit.map_or_else(Vec::new, |ty| vec![ty.instantiate(self.tcx(), args)]),
2125+
))
21282126
}
21292127

21302128
ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => None,

compiler/rustc_ty_utils/src/ty.rs

+71-68
Original file line numberDiff line numberDiff line change
@@ -3,76 +3,56 @@ use rustc_hir as hir;
33
use rustc_hir::def::DefKind;
44
use rustc_index::bit_set::BitSet;
55
use rustc_middle::query::Providers;
6-
use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitor};
6+
use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitableExt, TypeVisitor};
77
use rustc_middle::ty::{ToPredicate, TypeSuperVisitable, TypeVisitable};
88
use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
99
use rustc_span::DUMMY_SP;
1010
use rustc_trait_selection::traits;
1111

12-
fn sized_constraint_for_ty<'tcx>(
13-
tcx: TyCtxt<'tcx>,
14-
adtdef: ty::AdtDef<'tcx>,
15-
ty: Ty<'tcx>,
16-
) -> Vec<Ty<'tcx>> {
12+
#[instrument(level = "debug", skip(tcx), ret)]
13+
fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
1714
use rustc_type_ir::TyKind::*;
1815

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-
16+
match ty.kind() {
17+
// these are always sized
18+
Bool
19+
| Char
20+
| Int(..)
21+
| Uint(..)
22+
| Float(..)
23+
| RawPtr(..)
24+
| Ref(..)
25+
| FnDef(..)
26+
| FnPtr(..)
27+
| Array(..)
28+
| Closure(..)
29+
| CoroutineClosure(..)
30+
| Coroutine(..)
31+
| CoroutineWitness(..)
32+
| Never
33+
| Dynamic(_, _, ty::DynStar) => None,
34+
35+
// these are never sized
36+
Str | Slice(..) | Dynamic(_, _, ty::Dyn) | Foreign(..) => Some(ty),
37+
38+
Tuple(tys) => tys.last().and_then(|&ty| sized_constraint_for_ty(tcx, ty)),
39+
40+
// recursive case
3541
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-
}
44-
45-
Alias(..) => {
46-
// must calculate explicitly.
47-
// FIXME: consider special-casing always-Sized projections
48-
vec![ty]
42+
let intermediate = adt.sized_constraint(tcx);
43+
intermediate.and_then(|intermediate| {
44+
let ty = intermediate.instantiate(tcx, args);
45+
sized_constraint_for_ty(tcx, ty)
46+
})
4947
}
5048

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-
}
49+
// these can be sized or unsized
50+
Param(..) | Alias(..) | Error(_) => Some(ty),
6951

7052
Placeholder(..) | Bound(..) | Infer(..) => {
71-
bug!("unexpected type `{:?}` in sized_constraint_for_ty", ty)
53+
bug!("unexpected type `{ty:?}` in sized_constraint_for_ty")
7254
}
73-
};
74-
debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result);
75-
result
55+
}
7656
}
7757

7858
fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
@@ -90,29 +70,52 @@ fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
9070
///
9171
/// In fact, there are only a few options for the types in the constraint:
9272
/// - 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.
73+
/// - a type parameter or projection whose sizedness can't be known
9674
/// - an Error, if a type is infinitely sized
75+
#[instrument(level = "debug", skip(tcx), ret)]
9776
fn 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() {
10281
if let ty::Representability::Infinite(guar) = tcx.representability(def_id) {
103-
return ty::EarlyBinder::bind(tcx.mk_type_list(&[Ty::new_error(tcx, guar)]));
82+
return Some(ty::EarlyBinder::bind(Ty::new_error(tcx, guar)));
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();
93+
94+
let result = sized_constraint_for_ty(tcx, tail_ty);
95+
96+
let result = result.filter(|&ty| {
97+
// perf hack: if there is a `ty: Sized` bound, then we know that
98+
// the type is sized and do not need to check it on the impl.
99+
100+
if ty.references_error() {
101+
return true;
102+
}
103+
104+
let Some(sized_trait_def_id) = tcx.lang_items().sized_trait() else {
105+
return true;
106+
};
107+
108+
let predicates = tcx.predicates_of(def.did()).predicates;
112109

113-
debug!("adt_sized_constraint: {:?} => {:?}", def, result);
110+
!predicates.iter().any(|(p, _)| {
111+
p.as_trait_clause().is_some_and(|trait_pred| {
112+
trait_pred.def_id() == sized_trait_def_id
113+
&& trait_pred.self_ty().skip_binder() == ty
114+
})
115+
})
116+
});
114117

115-
ty::EarlyBinder::bind(result)
118+
result.map(ty::EarlyBinder::bind)
116119
}
117120

118121
/// See `ParamEnv` struct definition for details.

tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ where
2929

3030
fn main() {
3131
let mut list = RcNode::<i32>::new();
32-
//~^ ERROR the size for values of type `Node<i32, RcFamily>` cannot be known at compilation time
32+
//~^ ERROR trait bounds were not satisfied
3333
}

tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr

+3-10
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,15 @@ help: consider relaxing the implicit `Sized` restriction
1515
LL | type Pointer<T>: Deref<Target = T> + ?Sized;
1616
| ++++++++
1717

18-
error[E0599]: the size for values of type `Node<i32, RcFamily>` cannot be known at compilation time
18+
error[E0599]: the variant or associated item `new` exists for enum `Node<i32, RcFamily>`, but its trait bounds were not satisfied
1919
--> $DIR/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs:31:35
2020
|
2121
LL | enum Node<T, P: PointerFamily> {
22-
| ------------------------------ variant or associated item `new` not found for this enum because it doesn't satisfy `Node<i32, RcFamily>: Sized`
22+
| ------------------------------ variant or associated item `new` not found for this enum
2323
...
2424
LL | let mut list = RcNode::<i32>::new();
25-
| ^^^ doesn't have a size known at compile-time
25+
| ^^^ variant or associated item cannot be called on `Node<i32, RcFamily>` due to unsatisfied trait bounds
2626
|
27-
note: trait bound `Node<i32, RcFamily>: Sized` was not satisfied
28-
--> $DIR/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs:4:18
29-
|
30-
LL | type Pointer<T>: Deref<Target = T>;
31-
| ------- ^ unsatisfied trait bound introduced here
3227
note: trait bound `(dyn Deref<Target = Node<i32, RcFamily>> + 'static): Sized` was not satisfied
3328
--> $DIR/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs:23:29
3429
|
@@ -37,8 +32,6 @@ LL | impl<T, P: PointerFamily> Node<T, P>
3732
LL | where
3833
LL | P::Pointer<Node<T, P>>: Sized,
3934
| ^^^^^ unsatisfied trait bound introduced here
40-
note: the trait `Sized` must be implemented
41-
--> $SRC_DIR/core/src/marker.rs:LL:COL
4235

4336
error: aborting due to 2 previous errors
4437

0 commit comments

Comments
 (0)