rustc_const_eval/const_eval/
dyn_trait.rs1use rustc_middle::mir::interpret::{CtfeProvenance, InterpResult, Scalar, interp_ok};
2use rustc_middle::ty::{Region, Ty};
3use rustc_middle::{span_bug, ty};
4use rustc_span::def_id::DefId;
5use rustc_span::sym;
6
7use crate::const_eval::CompileTimeMachine;
8use crate::interpret::{Immediate, InterpCx, MPlaceTy, MemoryKind, Writeable};
9impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
10 pub(crate) fn write_dyn_trait_type_info(
11 &mut self,
12 dyn_place: impl Writeable<'tcx, CtfeProvenance>,
13 data: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
14 region: Region<'tcx>,
15 ) -> InterpResult<'tcx> {
16 let tcx = self.tcx.tcx;
17
18 let mut principal: Option<ty::Binder<'tcx, ty::ExistentialTraitRef<'tcx>>> = None;
21 let mut auto_traits_def_ids: Vec<ty::Binder<'tcx, DefId>> = Vec::new();
22 let mut projections: Vec<ty::Binder<'tcx, ty::ExistentialProjection<'tcx>>> = Vec::new();
23
24 for b in data.iter() {
25 match b.skip_binder() {
26 ty::ExistentialPredicate::Trait(tr) => principal = Some(b.rebind(tr)),
27 ty::ExistentialPredicate::AutoTrait(did) => auto_traits_def_ids.push(b.rebind(did)),
28 ty::ExistentialPredicate::Projection(p) => projections.push(b.rebind(p)),
29 }
30 }
31
32 let principal_ty: Option<Ty<'tcx>> = principal.map(|_tr| {
34 let preds = tcx
35 .mk_poly_existential_predicates_from_iter(data.iter().filter(|b| {
36 !#[allow(non_exhaustive_omitted_patterns)] match b.skip_binder() {
ty::ExistentialPredicate::AutoTrait(_) => true,
_ => false,
}matches!(b.skip_binder(), ty::ExistentialPredicate::AutoTrait(_))
37 }));
38 Ty::new_dynamic(tcx, preds, region)
39 });
40
41 for (field_idx, field) in
43 dyn_place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
44 {
45 let field_place = self.project_field(&dyn_place, field_idx)?;
46 match field.name {
47 sym::predicates => {
48 self.write_dyn_trait_predicates_slice(
49 &field_place,
50 principal_ty,
51 &auto_traits_def_ids,
52 region,
53 )?;
54 }
55 other => {
56 ::rustc_middle::util::bug::span_bug_fmt(self.tcx.def_span(field.did),
format_args!("unimplemented DynTrait field {0}", other))span_bug!(self.tcx.def_span(field.did), "unimplemented DynTrait field {other}")
57 }
58 }
59 }
60
61 interp_ok(())
62 }
63
64 fn mk_dyn_principal_auto_trait_ty(
65 &self,
66 auto_trait_def_id: ty::Binder<'tcx, DefId>,
67 region: Region<'tcx>,
68 ) -> Ty<'tcx> {
69 let tcx = self.tcx.tcx;
70
71 let pred_inner = ty::ExistentialPredicate::AutoTrait(auto_trait_def_id.skip_binder());
73 let pred = ty::Binder::bind_with_vars(pred_inner, auto_trait_def_id.bound_vars());
74
75 let preds = tcx.mk_poly_existential_predicates_from_iter([pred].into_iter());
76 Ty::new_dynamic(tcx, preds, region)
77 }
78
79 fn write_dyn_trait_predicates_slice(
80 &mut self,
81 slice_place: &impl Writeable<'tcx, CtfeProvenance>,
82 principal_ty: Option<Ty<'tcx>>,
83 auto_trait_def_ids: &[ty::Binder<'tcx, DefId>],
84 region: Region<'tcx>,
85 ) -> InterpResult<'tcx> {
86 let tcx = self.tcx.tcx;
87
88 let total_len = principal_ty.map(|_| 1).unwrap_or(0) + auto_trait_def_ids.len();
90
91 let slice_ty = slice_place.layout().ty.builtin_deref(false).unwrap(); let elem_ty = slice_ty.sequence_element_type(tcx); let arr_layout = self.layout_of(Ty::new_array(tcx, elem_ty, total_len as u64))?;
96 let arr_place = self.allocate(arr_layout, MemoryKind::Stack)?;
97 let mut elems = self.project_array_fields(&arr_place)?;
98
99 if let Some(principal_ty) = principal_ty {
101 let Some((_i, elem_place)) = elems.next(self)? else {
102 ::rustc_middle::util::bug::span_bug_fmt(self.tcx.span,
format_args!("DynTrait.predicates length computed wrong (principal)"));span_bug!(self.tcx.span, "DynTrait.predicates length computed wrong (principal)");
103 };
104 self.write_dyn_trait_predicate(elem_place, principal_ty, false)?;
105 }
106
107 for auto in auto_trait_def_ids {
109 let Some((_i, elem_place)) = elems.next(self)? else {
110 ::rustc_middle::util::bug::span_bug_fmt(self.tcx.span,
format_args!("DynTrait.predicates length computed wrong (auto)"));span_bug!(self.tcx.span, "DynTrait.predicates length computed wrong (auto)");
111 };
112 let auto_ty = self.mk_dyn_principal_auto_trait_ty(*auto, region);
113 self.write_dyn_trait_predicate(elem_place, auto_ty, true)?;
114 }
115
116 let arr_place = arr_place.map_provenance(CtfeProvenance::as_immutable);
117 let imm = Immediate::new_slice(arr_place.ptr(), total_len as u64, self);
118 self.write_immediate(imm, slice_place)
119 }
120
121 fn write_dyn_trait_predicate(
122 &mut self,
123 predicate_place: MPlaceTy<'tcx>,
124 trait_ty: Ty<'tcx>,
125 is_auto: bool,
126 ) -> InterpResult<'tcx> {
127 for (field_idx, field) in predicate_place
129 .layout
130 .ty
131 .ty_adt_def()
132 .unwrap()
133 .non_enum_variant()
134 .fields
135 .iter_enumerated()
136 {
137 let field_place = self.project_field(&predicate_place, field_idx)?;
138 match field.name {
139 sym::trait_ty => {
140 self.write_trait(field_place, trait_ty, is_auto)?;
142 }
143 other => {
144 ::rustc_middle::util::bug::span_bug_fmt(self.tcx.def_span(field.did),
format_args!("unimplemented DynTraitPredicate field {0}", other))span_bug!(
145 self.tcx.def_span(field.did),
146 "unimplemented DynTraitPredicate field {other}"
147 )
148 }
149 }
150 }
151 interp_ok(())
152 }
153 fn write_trait(
154 &mut self,
155 trait_place: MPlaceTy<'tcx>,
156 trait_ty: Ty<'tcx>,
157 is_auto: bool,
158 ) -> InterpResult<'tcx> {
159 for (field_idx, field) in
161 trait_place.layout.ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
162 {
163 let field_place = self.project_field(&trait_place, field_idx)?;
164 match field.name {
165 sym::ty => {
166 self.write_type_id(trait_ty, &field_place)?;
167 }
168 sym::is_auto => {
169 self.write_scalar(Scalar::from_bool(is_auto), &field_place)?;
170 }
171 other => {
172 ::rustc_middle::util::bug::span_bug_fmt(self.tcx.def_span(field.did),
format_args!("unimplemented Trait field {0}", other))span_bug!(self.tcx.def_span(field.did), "unimplemented Trait field {other}")
173 }
174 }
175 }
176 interp_ok(())
177 }
178}