}
fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
- let tcx = cx.tcx();
- let tag_layout = |tag: &Scalar| -> C::TyAndLayout {
- let layout = Layout::scalar(cx, tag.clone());
- MaybeResult::from(Ok(TyAndLayout {
- layout: tcx.intern_layout(layout),
- ty: tag.value.to_ty(tcx),
- }))
- };
+ enum TyMaybeWithLayout<C: LayoutOf> {
+ Ty(C::Ty),
+ TyAndLayout(C::TyAndLayout),
+ }
- cx.layout_of(match *this.ty.kind() {
- ty::Bool
- | ty::Char
- | ty::Int(_)
- | ty::Uint(_)
- | ty::Float(_)
- | ty::FnPtr(_)
- | ty::Never
- | ty::FnDef(..)
- | ty::GeneratorWitness(..)
- | ty::Foreign(..)
- | ty::Dynamic(..) => bug!("TyAndLayout::field_type({:?}): not applicable", this),
-
- // Potentially-fat pointers.
- ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
- assert!(i < this.fields.count());
-
- // Reuse the fat `*T` type as its own thin pointer data field.
- // This provides information about, e.g., DST struct pointees
- // (which may have no non-DST form), and will work as long
- // as the `Abi` or `FieldsShape` is checked by users.
- if i == 0 {
- let nil = tcx.mk_unit();
- let ptr_ty = if this.ty.is_unsafe_ptr() {
- tcx.mk_mut_ptr(nil)
- } else {
- tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
- };
- return MaybeResult::from(cx.layout_of(ptr_ty).to_result().map(
- |mut ptr_layout| {
- ptr_layout.ty = this.ty;
- ptr_layout
- },
- ));
- }
+ fn ty_and_layout_kind<
+ C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout: MaybeResult<TyAndLayout<'tcx>>>
+ + HasTyCtxt<'tcx>
+ + HasParamEnv<'tcx>,
+ >(
+ this: TyAndLayout<'tcx>,
+ cx: &C,
+ i: usize,
+ ty: C::Ty,
+ ) -> TyMaybeWithLayout<C> {
+ let tcx = cx.tcx();
+ let tag_layout = |tag: &Scalar| -> C::TyAndLayout {
+ let layout = Layout::scalar(cx, tag.clone());
+ MaybeResult::from(Ok(TyAndLayout {
+ layout: tcx.intern_layout(layout),
+ ty: tag.value.to_ty(tcx),
+ }))
+ };
- match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
- ty::Slice(_) | ty::Str => tcx.types.usize,
- ty::Dynamic(_, _) => {
- tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3))
- /* FIXME: use actual fn pointers
- Warning: naively computing the number of entries in the
- vtable by counting the methods on the trait + methods on
- all parent traits does not work, because some methods can
- be not object safe and thus excluded from the vtable.
- Increase this counter if you tried to implement this but
- failed to do it without duplicating a lot of code from
- other places in the compiler: 2
- tcx.mk_tup(&[
- tcx.mk_array(tcx.types.usize, 3),
- tcx.mk_array(Option<fn()>),
- ])
- */
+ match *ty.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::FnPtr(_)
+ | ty::Never
+ | ty::FnDef(..)
+ | ty::GeneratorWitness(..)
+ | ty::Foreign(..)
+ | ty::Dynamic(..) => bug!("TyAndLayout::field_type({:?}): not applicable", this),
+
+ // Potentially-fat pointers.
+ ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
+ assert!(i < this.fields.count());
+
+ // Reuse the fat `*T` type as its own thin pointer data field.
+ // This provides information about, e.g., DST struct pointees
+ // (which may have no non-DST form), and will work as long
+ // as the `Abi` or `FieldsShape` is checked by users.
+ if i == 0 {
+ let nil = tcx.mk_unit();
+ let ptr_ty = if ty.is_unsafe_ptr() {
+ tcx.mk_mut_ptr(nil)
+ } else {
+ tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
+ };
+ return TyMaybeWithLayout::TyAndLayout(MaybeResult::from(
+ cx.layout_of(ptr_ty).to_result().map(|mut ptr_layout| {
+ ptr_layout.ty = ty;
+ ptr_layout
+ }),
+ ));
}
- _ => bug!("TyAndLayout::field_type({:?}): not applicable", this),
- }
- }
- // Arrays and slices.
- ty::Array(element, _) | ty::Slice(element) => element,
- ty::Str => tcx.types.u8,
-
- // Tuples, generators and closures.
- ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().nth(i).unwrap(),
-
- ty::Generator(def_id, ref substs, _) => match this.variants {
- Variants::Single { index } => substs
- .as_generator()
- .state_tys(def_id, tcx)
- .nth(index.as_usize())
- .unwrap()
- .nth(i)
- .unwrap(),
- Variants::Multiple { ref tag, tag_field, .. } => {
- if i == tag_field {
- return tag_layout(tag);
+ match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
+ ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize),
+ ty::Dynamic(_, _) => {
+ TyMaybeWithLayout::Ty(tcx.mk_imm_ref(
+ tcx.lifetimes.re_static,
+ tcx.mk_array(tcx.types.usize, 3),
+ ))
+ /* FIXME: use actual fn pointers
+ Warning: naively computing the number of entries in the
+ vtable by counting the methods on the trait + methods on
+ all parent traits does not work, because some methods can
+ be not object safe and thus excluded from the vtable.
+ Increase this counter if you tried to implement this but
+ failed to do it without duplicating a lot of code from
+ other places in the compiler: 2
+ tcx.mk_tup(&[
+ tcx.mk_array(tcx.types.usize, 3),
+ tcx.mk_array(Option<fn()>),
+ ])
+ */
+ }
+ _ => bug!("TyAndLayout::field_type({:?}): not applicable", this),
}
- substs.as_generator().prefix_tys().nth(i).unwrap()
}
- },
- ty::Tuple(tys) => tys[i].expect_ty(),
+ // Arrays and slices.
+ ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element),
+ ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8),
- // ADTs.
- ty::Adt(def, substs) => {
- match this.variants {
- Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs),
+ // Tuples, generators and closures.
+ ty::Closure(_, ref substs) => {
+ ty_and_layout_kind(this, cx, i, substs.as_closure().tupled_upvars_ty())
+ }
+
+ ty::Generator(def_id, ref substs, _) => match this.variants {
+ Variants::Single { index } => TyMaybeWithLayout::Ty(
+ substs
+ .as_generator()
+ .state_tys(def_id, tcx)
+ .nth(index.as_usize())
+ .unwrap()
+ .nth(i)
+ .unwrap(),
+ ),
+ Variants::Multiple { ref tag, tag_field, .. } => {
+ if i == tag_field {
+ return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
+ }
+ TyMaybeWithLayout::Ty(substs.as_generator().prefix_tys().nth(i).unwrap())
+ }
+ },
+
+ ty::Tuple(tys) => TyMaybeWithLayout::Ty(tys[i].expect_ty()),
+
+ // ADTs.
+ ty::Adt(def, substs) => {
+ match this.variants {
+ Variants::Single { index } => {
+ TyMaybeWithLayout::Ty(def.variants[index].fields[i].ty(tcx, substs))
+ }
- // Discriminant field for enums (where applicable).
- Variants::Multiple { ref tag, .. } => {
- assert_eq!(i, 0);
- return tag_layout(tag);
+ // Discriminant field for enums (where applicable).
+ Variants::Multiple { ref tag, .. } => {
+ assert_eq!(i, 0);
+ return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
+ }
}
}
+
+ ty::Projection(_)
+ | ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Opaque(..)
+ | ty::Param(_)
+ | ty::Infer(_)
+ | ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty),
}
+ }
- ty::Projection(_)
- | ty::Bound(..)
- | ty::Placeholder(..)
- | ty::Opaque(..)
- | ty::Param(_)
- | ty::Infer(_)
- | ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty),
+ cx.layout_of(match ty_and_layout_kind(this, cx, i, this.ty) {
+ TyMaybeWithLayout::Ty(result) => result,
+ TyMaybeWithLayout::TyAndLayout(result) => return result,
})
}